Skip to main content

@c-a-f/testing

Testing utilities and helpers for CAF applications. Mocks and test helpers for Ploc, Pulse, UseCase, repositories, RouteManager, and framework-specific rendering (React, Vue, Angular).

Installation

npm install @c-a-f/testing --save-dev

Features

Core (@c-a-f/testing/core)

FeatureDescription
createPlocTesterTrack state changes; getStateChangeCount, getStateHistory, getLastStateChange.
createMockPlocPloc with controllable state (no business logic).
waitForStateChangeWait for Ploc state to match a predicate.
waitForStateChangesWait for a specific number of state changes.
assertStateHistoryAssert state history matches expected.
getStateHistorySnapshotSnapshot state history for tests.
createPulseTesterTrack Pulse value changes.
waitForPulseValueWait for Pulse value to match predicate.
createMockUseCaseMock UseCase with custom implementation.
createMockUseCaseSuccessMock that returns success with data.
createMockUseCaseErrorMock that returns error.
createMockUseCaseAsyncMock that resolves after optional delay.
createUseCaseTesterExecute and assert on RequestResult.
createSuccessResult, createErrorResult, createLoadingResultBuild RequestResult for tests.
createMockRepositoryGeneric stub for I*Repository interfaces.
createMockRepositoryStubEmpty stub; assign or spy methods.
createMockRouteRepositoryMock RouteRepository.
createRouteManagerTesterTrack route changes; getCurrentRoute, getRouteHistory.
flushPromisesResolve pending microtasks.
createPlocUseCaseContextMinimal Ploc + UseCase context for integration tests.

React (@c-a-f/testing/react)

FeatureDescription
renderWithCAFRender component wrapped in CAFProvider (plocs, useCases).
createTestPlocPloc with controllable state for component tests.
waitForPlocStateWait for Ploc state to match predicate.
mockUseCasemockUseCase.success(data), mockUseCase.error(error), mockUseCase.async(data, delayMs?), mockUseCase.fn(impl).

Vue (@c-a-f/testing/vue)

FeatureDescription
mountWithCAFMount component with CAF context (plocs, useCases).
createTestPlocSame as React.
waitForPlocStateSame as React.
mockUseCaseSame as React.

Angular (@c-a-f/testing/angular)

FeatureDescription
provideTestingCAFTestBed providers for plocs and useCases.
createTestPlocSame as React.
waitForPlocStateSame as React.
mockUseCaseSame as React.

Optional subpackages

  • @c-a-f/testing/workflow — createWorkflowTester, waitForWorkflowState, waitForFinalState
  • @c-a-f/testing/permission — createMockPermissionChecker, createPermissionTester
  • @c-a-f/testing/i18n — createMockTranslator, createTranslationTester
  • @c-a-f/testing/validation — createMockValidator, createValidationTester

Core: Ploc

import { createPlocTester, waitForStateChange } from '@c-a-f/testing/core';

const ploc = new CounterPloc();
const tester = createPlocTester(ploc);
ploc.increment();
ploc.increment();
expect(tester.getStateChangeCount()).toBe(2);
expect(tester.getStateHistory()).toEqual([0, 1, 2]);
expect(tester.getLastStateChange()).toBe(2);
tester.cleanup();

Core: Mock UseCase

import { createMockUseCaseSuccess, createMockUseCaseError } from '@c-a-f/testing/core';

const useCase = createMockUseCaseSuccess([{ id: '1', name: 'John' }]);
const result = await useCase.execute();
expect(result.data.value).toHaveLength(1);

const errorUseCase = createMockUseCaseError(new Error('Failed'));
const errResult = await errorUseCase.execute();
expect(errResult.error.value?.message).toBe('Failed');

Core: Mock repository

import { createMockRepository, createMockRepositoryStub } from '@c-a-f/testing/core';

const repo = createMockRepository<IUserRepository>({
getUsers: async () => [{ id: '1', name: 'John' }],
getUserById: async (id) => ({ id, name: 'User ' + id }),
});
expect(await repo.getUsers()).toHaveLength(1);

const stub = createMockRepositoryStub<IUserRepository>();
stub.getUsers = vi.fn().mockResolvedValue([]);

React: renderWithCAF

import { renderWithCAF, createTestPloc } from '@c-a-f/testing/react';

const ploc = createTestPloc({ count: 5 });
renderWithCAF(<Counter />, { plocs: { counter: ploc } });
expect(screen.getByTestId('count')).toHaveTextContent('5');

Angular: provideTestingCAF

import { provideTestingCAF, createTestPloc, mockUseCase } from '@c-a-f/testing/angular';

TestBed.configureTestingModule({
providers: [
provideTestingCAF({
plocs: { user: createTestPloc({ name: 'Test' }) },
useCases: { createUser: mockUseCase.success({ id: '1' }) },
}),
],
});

Exports

  • @c-a-f/testing/core — All core testers and mocks listed above
  • @c-a-f/testing/react — renderWithCAF, createTestPloc, waitForPlocState, mockUseCase
  • @c-a-f/testing/vue — mountWithCAF, createTestPloc, waitForPlocState, mockUseCase
  • @c-a-f/testing/angular — provideTestingCAF, createTestPloc, waitForPlocState, mockUseCase

Dependencies

  • @c-a-f/core — Core primitives
  • Optional: @c-a-f/infrastructure-react, @c-a-f/infrastructure-vue, @c-a-f/infrastructure-angular for framework helpers
  • Optional: @c-a-f/workflow, @c-a-f/permission, @c-a-f/i18n, @c-a-f/validation for subpackage testers