@c-a-f/testing 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/.build/__tests__/react/renderWithCAF.spec.d.ts +1 -0
  2. package/.build/__tests__/react/renderWithCAF.spec.js +53 -0
  3. package/.build/index.d.ts +1 -0
  4. package/.build/index.js +1 -0
  5. package/.build/src/angular/createTestPloc.d.ts +19 -0
  6. package/.build/src/angular/createTestPloc.js +21 -0
  7. package/.build/src/angular/index.d.ts +12 -0
  8. package/.build/src/angular/index.js +12 -0
  9. package/.build/src/angular/mockUseCase.d.ts +32 -0
  10. package/.build/src/angular/mockUseCase.js +40 -0
  11. package/.build/src/angular/provideTestingCAF.d.ts +29 -0
  12. package/.build/src/angular/provideTestingCAF.js +26 -0
  13. package/.build/src/angular/waitForPlocState.d.ts +18 -0
  14. package/.build/src/angular/waitForPlocState.js +20 -0
  15. package/.build/src/core/IntegrationTestHelpers.d.ts +77 -0
  16. package/.build/src/core/IntegrationTestHelpers.js +78 -0
  17. package/.build/src/core/PlocTestHelpers.d.ts +133 -0
  18. package/.build/src/core/PlocTestHelpers.js +205 -0
  19. package/.build/src/core/PulseTestHelpers.d.ts +71 -0
  20. package/.build/src/core/PulseTestHelpers.js +106 -0
  21. package/.build/src/core/RepositoryTestHelpers.d.ts +48 -0
  22. package/.build/src/core/RepositoryTestHelpers.js +76 -0
  23. package/.build/src/core/RouteTestHelpers.d.ts +67 -0
  24. package/.build/src/core/RouteTestHelpers.js +94 -0
  25. package/.build/src/core/UseCaseTestHelpers.d.ts +100 -0
  26. package/.build/src/core/UseCaseTestHelpers.js +161 -0
  27. package/.build/src/core/index.d.ts +6 -0
  28. package/.build/src/core/index.js +6 -0
  29. package/.build/src/i18n/I18nTestHelpers.d.ts +76 -0
  30. package/.build/src/i18n/I18nTestHelpers.js +122 -0
  31. package/.build/src/i18n/index.d.ts +1 -0
  32. package/.build/src/i18n/index.js +1 -0
  33. package/.build/src/index.d.ts +5 -0
  34. package/.build/src/index.js +10 -0
  35. package/.build/src/permission/PermissionTestHelpers.d.ts +75 -0
  36. package/.build/src/permission/PermissionTestHelpers.js +121 -0
  37. package/.build/src/permission/index.d.ts +1 -0
  38. package/.build/src/permission/index.js +1 -0
  39. package/.build/src/react/createTestPloc.d.ts +19 -0
  40. package/.build/src/react/createTestPloc.js +21 -0
  41. package/.build/src/react/index.d.ts +12 -0
  42. package/.build/src/react/index.js +12 -0
  43. package/.build/src/react/mockUseCase.d.ts +36 -0
  44. package/.build/src/react/mockUseCase.js +44 -0
  45. package/.build/src/react/renderWithCAF.d.ts +31 -0
  46. package/.build/src/react/renderWithCAF.js +23 -0
  47. package/.build/src/react/waitForPlocState.d.ts +22 -0
  48. package/.build/src/react/waitForPlocState.js +24 -0
  49. package/.build/src/validation/ValidationTestHelpers.d.ts +66 -0
  50. package/.build/src/validation/ValidationTestHelpers.js +118 -0
  51. package/.build/src/validation/index.d.ts +1 -0
  52. package/.build/src/validation/index.js +1 -0
  53. package/.build/src/vue/createTestPloc.d.ts +19 -0
  54. package/.build/src/vue/createTestPloc.js +21 -0
  55. package/.build/src/vue/index.d.ts +12 -0
  56. package/.build/src/vue/index.js +12 -0
  57. package/.build/src/vue/mockUseCase.d.ts +34 -0
  58. package/.build/src/vue/mockUseCase.js +42 -0
  59. package/.build/src/vue/mountWithCAF.d.ts +31 -0
  60. package/.build/src/vue/mountWithCAF.js +40 -0
  61. package/.build/src/vue/waitForPlocState.d.ts +19 -0
  62. package/.build/src/vue/waitForPlocState.js +21 -0
  63. package/.build/src/workflow/WorkflowTestHelpers.d.ts +75 -0
  64. package/.build/src/workflow/WorkflowTestHelpers.js +146 -0
  65. package/.build/src/workflow/index.d.ts +1 -0
  66. package/.build/src/workflow/index.js +1 -0
  67. package/.build/vitest.config.d.ts +7 -0
  68. package/.build/vitest.config.js +6 -0
  69. package/README.md +598 -0
  70. package/package.json +127 -0
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,53 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { describe, it, expect } from 'vitest';
3
+ import { createSuccessResult } from '../../src/core/UseCaseTestHelpers';
4
+ import { renderWithCAF, createTestPloc, waitForPlocState, mockUseCase } from '../../src/react';
5
+ // Full render tests require a single React instance (no duplicate react in node_modules).
6
+ // Use renderWithCAF in your app tests; see README for examples.
7
+ describe('renderWithCAF', () => {
8
+ it.skip('returns render result when given ui and options (run in app to avoid duplicate React)', () => {
9
+ const ploc = createTestPloc({ count: 0 });
10
+ const result = renderWithCAF(_jsx("div", { "data-testid": "root", children: "Hello" }), { plocs: { counter: ploc } });
11
+ expect(result).toBeDefined();
12
+ expect(result.getByTestId('root')).toHaveTextContent('Hello');
13
+ });
14
+ });
15
+ describe('createTestPloc', () => {
16
+ it('creates ploc with initial state', () => {
17
+ const ploc = createTestPloc({ count: 0 });
18
+ expect(ploc.state).toEqual({ count: 0 });
19
+ });
20
+ it('allows changing state', () => {
21
+ const ploc = createTestPloc({ count: 0 });
22
+ ploc.changeState({ count: 1 });
23
+ expect(ploc.state.count).toBe(1);
24
+ });
25
+ });
26
+ describe('waitForPlocState', () => {
27
+ it('resolves when predicate matches', async () => {
28
+ const ploc = createTestPloc({ count: 0 });
29
+ const promise = waitForPlocState(ploc, (s) => s.count === 2);
30
+ ploc.changeState({ count: 1 });
31
+ ploc.changeState({ count: 2 });
32
+ const state = await promise;
33
+ expect(state).toEqual({ count: 2 });
34
+ });
35
+ });
36
+ describe('mockUseCase', () => {
37
+ it('success returns data', async () => {
38
+ const uc = mockUseCase.success({ id: '1' });
39
+ const result = await uc.execute();
40
+ expect(result.data.value).toEqual({ id: '1' });
41
+ });
42
+ it('error returns error', async () => {
43
+ const err = new Error('Fail');
44
+ const uc = mockUseCase.error(err);
45
+ const result = await uc.execute();
46
+ expect(result.error.value).toBe(err);
47
+ });
48
+ it('fn uses custom implementation', async () => {
49
+ const uc = mockUseCase.fn((n) => Promise.resolve(createSuccessResult(n * 2)));
50
+ const result = await uc.execute(21);
51
+ expect(result.data.value).toBe(42);
52
+ });
53
+ });
@@ -0,0 +1 @@
1
+ export * from './src';
@@ -0,0 +1 @@
1
+ export * from './src';
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Create a Ploc instance for Angular component tests. Same as createMockPloc from core:
3
+ * a Ploc with controllable state and no business logic. Use with provideTestingCAF.
4
+ *
5
+ * @example
6
+ * ```ts
7
+ * import { provideTestingCAF, createTestPloc } from '@c-a-f/testing/angular';
8
+ *
9
+ * const ploc = createTestPloc({ count: 0 });
10
+ * TestBed.configureTestingModule({
11
+ * providers: [provideTestingCAF({ plocs: { counter: ploc } })],
12
+ * });
13
+ * ```
14
+ */
15
+ import type { Ploc } from '@c-a-f/core';
16
+ /**
17
+ * Create a test Ploc with initial state. Use changeState() to drive state in tests.
18
+ */
19
+ export declare function createTestPloc<S>(initialState: S): Ploc<S>;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Create a Ploc instance for Angular component tests. Same as createMockPloc from core:
3
+ * a Ploc with controllable state and no business logic. Use with provideTestingCAF.
4
+ *
5
+ * @example
6
+ * ```ts
7
+ * import { provideTestingCAF, createTestPloc } from '@c-a-f/testing/angular';
8
+ *
9
+ * const ploc = createTestPloc({ count: 0 });
10
+ * TestBed.configureTestingModule({
11
+ * providers: [provideTestingCAF({ plocs: { counter: ploc } })],
12
+ * });
13
+ * ```
14
+ */
15
+ import { createMockPloc } from '../core/PlocTestHelpers';
16
+ /**
17
+ * Create a test Ploc with initial state. Use changeState() to drive state in tests.
18
+ */
19
+ export function createTestPloc(initialState) {
20
+ return createMockPloc(initialState);
21
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Angular testing utilities for CAF.
3
+ *
4
+ * - provideTestingCAF: provide CAF context in TestBed (plocs, useCases)
5
+ * - createTestPloc: create a test Ploc with controllable state
6
+ * - waitForPlocState: wait for Ploc state to match a predicate
7
+ * - mockUseCase: mock UseCase (success, error, async, fn)
8
+ */
9
+ export { provideTestingCAF, type ProvideTestingCAFConfig } from './provideTestingCAF';
10
+ export { createTestPloc } from './createTestPloc';
11
+ export { waitForPlocState } from './waitForPlocState';
12
+ export { mockUseCase } from './mockUseCase';
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Angular testing utilities for CAF.
3
+ *
4
+ * - provideTestingCAF: provide CAF context in TestBed (plocs, useCases)
5
+ * - createTestPloc: create a test Ploc with controllable state
6
+ * - waitForPlocState: wait for Ploc state to match a predicate
7
+ * - mockUseCase: mock UseCase (success, error, async, fn)
8
+ */
9
+ export { provideTestingCAF } from './provideTestingCAF';
10
+ export { createTestPloc } from './createTestPloc';
11
+ export { waitForPlocState } from './waitForPlocState';
12
+ export { mockUseCase } from './mockUseCase';
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Helpers to create mock UseCases for Angular component tests. Use with provideTestingCAF.
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * import { provideTestingCAF, mockUseCase } from '@c-a-f/testing/angular';
7
+ *
8
+ * const submit = mockUseCase.success({ id: '1' });
9
+ * TestBed.configureTestingModule({
10
+ * providers: [provideTestingCAF({ useCases: { submit } })],
11
+ * });
12
+ * ```
13
+ */
14
+ import type { UseCase, RequestResult } from '@c-a-f/core';
15
+ export declare const mockUseCase: {
16
+ /**
17
+ * UseCase that always returns success with the given data.
18
+ */
19
+ success<T>(data: T): UseCase<[], T>;
20
+ /**
21
+ * UseCase that always returns the given error.
22
+ */
23
+ error<T_1 = unknown>(error: Error): UseCase<[], T_1>;
24
+ /**
25
+ * UseCase that resolves with data after an optional delay (for loading-state tests).
26
+ */
27
+ async<T_2>(data: T_2, delayMs?: number): UseCase<[], T_2>;
28
+ /**
29
+ * UseCase with a custom implementation (same as createMockUseCase).
30
+ */
31
+ fn<A extends any[], T_3>(implementation: (...args: A) => RequestResult<T_3> | Promise<RequestResult<T_3>>): UseCase<A, T_3>;
32
+ };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Helpers to create mock UseCases for Angular component tests. Use with provideTestingCAF.
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * import { provideTestingCAF, mockUseCase } from '@c-a-f/testing/angular';
7
+ *
8
+ * const submit = mockUseCase.success({ id: '1' });
9
+ * TestBed.configureTestingModule({
10
+ * providers: [provideTestingCAF({ useCases: { submit } })],
11
+ * });
12
+ * ```
13
+ */
14
+ import { createMockUseCase, createMockUseCaseSuccess, createMockUseCaseError, createMockUseCaseAsync, } from '../core/UseCaseTestHelpers';
15
+ export const mockUseCase = {
16
+ /**
17
+ * UseCase that always returns success with the given data.
18
+ */
19
+ success(data) {
20
+ return createMockUseCaseSuccess(data);
21
+ },
22
+ /**
23
+ * UseCase that always returns the given error.
24
+ */
25
+ error(error) {
26
+ return createMockUseCaseError(error);
27
+ },
28
+ /**
29
+ * UseCase that resolves with data after an optional delay (for loading-state tests).
30
+ */
31
+ async(data, delayMs = 0) {
32
+ return createMockUseCaseAsync(data, delayMs);
33
+ },
34
+ /**
35
+ * UseCase with a custom implementation (same as createMockUseCase).
36
+ */
37
+ fn(implementation) {
38
+ return createMockUseCase(implementation);
39
+ },
40
+ };
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Provide CAF context (Plocs/UseCases) in Angular tests. Use with TestBed:
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * import { TestBed } from '@angular/core/testing';
7
+ * import { provideTestingCAF, createTestPloc, mockUseCase } from '@c-a-f/testing/angular';
8
+ *
9
+ * const ploc = createTestPloc({ count: 0 });
10
+ * await TestBed.configureTestingModule({
11
+ * imports: [MyComponent],
12
+ * providers: [provideTestingCAF({ plocs: { counter: ploc }, useCases: { submit: mockUseCase.success({ id: '1' }) })],
13
+ * }).compileComponents();
14
+ *
15
+ * const fixture = TestBed.createComponent(MyComponent);
16
+ * ```
17
+ */
18
+ import type { Provider } from '@angular/core';
19
+ import type { Ploc, UseCase } from '@c-a-f/core';
20
+ export interface ProvideTestingCAFConfig {
21
+ plocs?: Record<string, Ploc<unknown>>;
22
+ useCases?: Record<string, UseCase<any[], any>>;
23
+ }
24
+ /**
25
+ * Returns Angular providers for CAF context. Use in TestBed.configureTestingModule providers.
26
+ * Same as provideCAF from @c-a-f/infrastructure-angular; re-exported here so tests
27
+ * can use a single import from @c-a-f/testing/angular.
28
+ */
29
+ export declare function provideTestingCAF(config: ProvideTestingCAFConfig): Provider;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Provide CAF context (Plocs/UseCases) in Angular tests. Use with TestBed:
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * import { TestBed } from '@angular/core/testing';
7
+ * import { provideTestingCAF, createTestPloc, mockUseCase } from '@c-a-f/testing/angular';
8
+ *
9
+ * const ploc = createTestPloc({ count: 0 });
10
+ * await TestBed.configureTestingModule({
11
+ * imports: [MyComponent],
12
+ * providers: [provideTestingCAF({ plocs: { counter: ploc }, useCases: { submit: mockUseCase.success({ id: '1' }) })],
13
+ * }).compileComponents();
14
+ *
15
+ * const fixture = TestBed.createComponent(MyComponent);
16
+ * ```
17
+ */
18
+ import { provideCAF as provideCAFFromInfra } from '@c-a-f/infrastructure-angular';
19
+ /**
20
+ * Returns Angular providers for CAF context. Use in TestBed.configureTestingModule providers.
21
+ * Same as provideCAF from @c-a-f/infrastructure-angular; re-exported here so tests
22
+ * can use a single import from @c-a-f/testing/angular.
23
+ */
24
+ export function provideTestingCAF(config) {
25
+ return provideCAFFromInfra(config);
26
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Wait for a Ploc to reach a state that matches a predicate. Useful in Angular tests
3
+ * after triggering an action that updates the Ploc asynchronously.
4
+ *
5
+ * @example
6
+ * ```ts
7
+ * import { createTestPloc, waitForPlocState } from '@c-a-f/testing/angular';
8
+ *
9
+ * const ploc = createTestPloc({ loading: true, items: [] });
10
+ * ploc.changeState({ loading: false, items: [{ id: '1' }] });
11
+ * await waitForPlocState(ploc, (state) => !state.loading && state.items.length > 0);
12
+ * ```
13
+ */
14
+ import type { Ploc } from '@c-a-f/core';
15
+ /**
16
+ * Wait until the Ploc's state satisfies the predicate (or timeout).
17
+ */
18
+ export declare function waitForPlocState<S>(ploc: Ploc<S>, predicate: (state: S) => boolean, timeoutMs?: number): Promise<S>;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Wait for a Ploc to reach a state that matches a predicate. Useful in Angular tests
3
+ * after triggering an action that updates the Ploc asynchronously.
4
+ *
5
+ * @example
6
+ * ```ts
7
+ * import { createTestPloc, waitForPlocState } from '@c-a-f/testing/angular';
8
+ *
9
+ * const ploc = createTestPloc({ loading: true, items: [] });
10
+ * ploc.changeState({ loading: false, items: [{ id: '1' }] });
11
+ * await waitForPlocState(ploc, (state) => !state.loading && state.items.length > 0);
12
+ * ```
13
+ */
14
+ import { waitForStateChange } from '../core/PlocTestHelpers';
15
+ /**
16
+ * Wait until the Ploc's state satisfies the predicate (or timeout).
17
+ */
18
+ export function waitForPlocState(ploc, predicate, timeoutMs = 5000) {
19
+ return waitForStateChange(ploc, predicate, timeoutMs);
20
+ }
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Integration test helpers for CAF.
3
+ *
4
+ * Utilities to run Ploc + UseCase together, flush async work, and small
5
+ * helpers for integration-style tests.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import {
10
+ * createPlocWithUseCase,
11
+ * flushPromises,
12
+ * runWithFakeTimers,
13
+ * } from '@c-a-f/testing/core';
14
+ * import { Ploc } from '@c-a-f/core';
15
+ *
16
+ * const ploc = createPlocWithUseCase(InitialState, (state, useCase) => ({ ... }));
17
+ * await flushPromises();
18
+ * ```
19
+ */
20
+ import type { Ploc } from '@c-a-f/core';
21
+ import type { UseCase } from '@c-a-f/core';
22
+ /**
23
+ * Resolve all pending promises (microtasks).
24
+ * Call after triggering async code to wait for Promise resolution in tests.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * ploc.load();
29
+ * await flushPromises();
30
+ * expect(ploc.state.items.length).toBe(1);
31
+ * ```
32
+ */
33
+ export declare function flushPromises(): Promise<void>;
34
+ /**
35
+ * Run a callback with fake timers (if the test environment supports it).
36
+ * Returns the result of the callback. Does not install/uninstall timers;
37
+ * use your test framework's fake timers (e.g. vi.useFakeTimers()) and this
38
+ * to run a tick or advance time.
39
+ *
40
+ * This helper is a no-op that just runs the callback; use it as a placeholder
41
+ * for "run this in a fake timer context" when you pair it with vi.useFakeTimers()
42
+ * or jest.useFakeTimers() in the test.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * vi.useFakeTimers();
47
+ * const p = doSomethingAsync();
48
+ * await runWithFakeTimers(async () => {
49
+ * vi.advanceTimersByTime(1000);
50
+ * await flushPromises();
51
+ * });
52
+ * vi.useRealTimers();
53
+ * ```
54
+ */
55
+ export declare function runWithFakeTimers<T>(fn: () => Promise<T>): Promise<T>;
56
+ /**
57
+ * Minimal context for integration tests: a Ploc and a UseCase.
58
+ * Use when your test needs to wire a Ploc to a UseCase without a full app.
59
+ */
60
+ export interface PlocUseCaseTestContext<S, A extends any[], T> {
61
+ ploc: Ploc<S>;
62
+ useCase: UseCase<A, T>;
63
+ }
64
+ /**
65
+ * Create a minimal integration context with a mock Ploc and a success-returning UseCase.
66
+ * Useful when testing a component or flow that expects both a Ploc and a UseCase from context.
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * const { ploc, useCase } = createPlocUseCaseContext(
71
+ * { items: [], loading: false },
72
+ * []
73
+ * );
74
+ * // Inject into CAFProvider or pass as props
75
+ * ```
76
+ */
77
+ export declare function createPlocUseCaseContext<S, T>(initialState: S, useCaseResult: T): PlocUseCaseTestContext<S, [], T>;
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Integration test helpers for CAF.
3
+ *
4
+ * Utilities to run Ploc + UseCase together, flush async work, and small
5
+ * helpers for integration-style tests.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import {
10
+ * createPlocWithUseCase,
11
+ * flushPromises,
12
+ * runWithFakeTimers,
13
+ * } from '@c-a-f/testing/core';
14
+ * import { Ploc } from '@c-a-f/core';
15
+ *
16
+ * const ploc = createPlocWithUseCase(InitialState, (state, useCase) => ({ ... }));
17
+ * await flushPromises();
18
+ * ```
19
+ */
20
+ import { createMockPloc } from './PlocTestHelpers';
21
+ import { createMockUseCaseSuccess } from './UseCaseTestHelpers';
22
+ /**
23
+ * Resolve all pending promises (microtasks).
24
+ * Call after triggering async code to wait for Promise resolution in tests.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * ploc.load();
29
+ * await flushPromises();
30
+ * expect(ploc.state.items.length).toBe(1);
31
+ * ```
32
+ */
33
+ export function flushPromises() {
34
+ return new Promise((resolve) => setTimeout(resolve, 0));
35
+ }
36
+ /**
37
+ * Run a callback with fake timers (if the test environment supports it).
38
+ * Returns the result of the callback. Does not install/uninstall timers;
39
+ * use your test framework's fake timers (e.g. vi.useFakeTimers()) and this
40
+ * to run a tick or advance time.
41
+ *
42
+ * This helper is a no-op that just runs the callback; use it as a placeholder
43
+ * for "run this in a fake timer context" when you pair it with vi.useFakeTimers()
44
+ * or jest.useFakeTimers() in the test.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * vi.useFakeTimers();
49
+ * const p = doSomethingAsync();
50
+ * await runWithFakeTimers(async () => {
51
+ * vi.advanceTimersByTime(1000);
52
+ * await flushPromises();
53
+ * });
54
+ * vi.useRealTimers();
55
+ * ```
56
+ */
57
+ export async function runWithFakeTimers(fn) {
58
+ return fn();
59
+ }
60
+ /**
61
+ * Create a minimal integration context with a mock Ploc and a success-returning UseCase.
62
+ * Useful when testing a component or flow that expects both a Ploc and a UseCase from context.
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * const { ploc, useCase } = createPlocUseCaseContext(
67
+ * { items: [], loading: false },
68
+ * []
69
+ * );
70
+ * // Inject into CAFProvider or pass as props
71
+ * ```
72
+ */
73
+ export function createPlocUseCaseContext(initialState, useCaseResult) {
74
+ return {
75
+ ploc: createMockPloc(initialState),
76
+ useCase: createMockUseCaseSuccess(useCaseResult),
77
+ };
78
+ }
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Test helpers for Ploc (Presentation Logic Component).
3
+ *
4
+ * Provides utilities for testing Ploc instances.
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import { createPlocTester, waitForStateChange, createMockPloc } from '@c-a-f/testing/core';
9
+ * import { MyPloc } from './MyPloc';
10
+ *
11
+ * const tester = createPlocTester(new MyPloc());
12
+ *
13
+ * // Wait for state change
14
+ * await waitForStateChange(tester.ploc, (state) => state.count === 5);
15
+ *
16
+ * // Get state history
17
+ * const history = tester.getStateHistory();
18
+ *
19
+ * // Or use a mock Ploc with controllable state
20
+ * const mockPloc = createMockPloc({ count: 0 });
21
+ * mockPloc.changeState({ count: 1 });
22
+ * ```
23
+ */
24
+ import { Ploc } from '@c-a-f/core';
25
+ type PlocInstance<T> = {
26
+ state: T;
27
+ changeState(state: T): void;
28
+ subscribe(listener: (state: T) => void): void;
29
+ unsubscribe(listener: (state: T) => void): void;
30
+ };
31
+ /**
32
+ * Concrete Ploc implementation for testing.
33
+ * Provides a Ploc with controllable state and no business logic.
34
+ */
35
+ export declare class MockPloc<S> extends Ploc<S> {
36
+ constructor(initialState: S);
37
+ }
38
+ /**
39
+ * Create a mock Ploc with controllable state for unit tests.
40
+ * The returned Ploc has no logic; use changeState() to drive state in tests.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * const ploc = createMockPloc({ count: 0, loading: false });
45
+ * expect(ploc.state.count).toBe(0);
46
+ * ploc.changeState({ count: 1, loading: true });
47
+ * expect(ploc.state.count).toBe(1);
48
+ * ```
49
+ */
50
+ export declare function createMockPloc<S>(initialState: S): Ploc<S>;
51
+ /**
52
+ * Ploc tester utility.
53
+ * Tracks state changes and provides testing utilities.
54
+ */
55
+ export declare class PlocTester<T> {
56
+ readonly ploc: PlocInstance<T>;
57
+ private stateHistory;
58
+ private listener;
59
+ constructor(ploc: PlocInstance<T>);
60
+ /**
61
+ * Get the current state.
62
+ */
63
+ getState(): T;
64
+ /**
65
+ * Get the state history.
66
+ */
67
+ getStateHistory(): T[];
68
+ /**
69
+ * Get the initial state.
70
+ */
71
+ getInitialState(): T;
72
+ /**
73
+ * Get the last state change.
74
+ */
75
+ getLastStateChange(): T | undefined;
76
+ /**
77
+ * Get the number of state changes.
78
+ */
79
+ getStateChangeCount(): number;
80
+ /**
81
+ * Cleanup: unsubscribe from state changes.
82
+ */
83
+ cleanup(): void;
84
+ }
85
+ /**
86
+ * Create a Ploc tester instance.
87
+ */
88
+ export declare function createPlocTester<T>(ploc: PlocInstance<T>): PlocTester<T>;
89
+ /**
90
+ * Wait for a state change that matches a predicate.
91
+ *
92
+ * @param ploc The Ploc instance to watch
93
+ * @param predicate Function that returns true when the desired state is reached
94
+ * @param timeout Maximum time to wait in milliseconds (default: 5000)
95
+ * @returns Promise that resolves when the predicate returns true
96
+ */
97
+ export declare function waitForStateChange<T>(ploc: PlocInstance<T>, predicate: (state: T) => boolean, timeout?: number): Promise<T>;
98
+ /**
99
+ * Wait for a specific number of state changes.
100
+ */
101
+ export declare function waitForStateChanges<T>(ploc: PlocInstance<T>, count: number, timeout?: number): Promise<T[]>;
102
+ /**
103
+ * Assert that the Ploc tester's state history matches the expected states.
104
+ * Uses JSON comparison so objects are compared by value.
105
+ * Use with your test framework's expect (e.g. expect().toEqual).
106
+ *
107
+ * @example
108
+ * ```ts
109
+ * const tester = createPlocTester(ploc);
110
+ * ploc.changeState({ step: 1 });
111
+ * ploc.changeState({ step: 2 });
112
+ * assertStateHistory(tester, [initialState, { step: 1 }, { step: 2 }]);
113
+ * ```
114
+ */
115
+ export declare function assertStateHistory<T>(tester: PlocTester<T>, expected: T[]): void;
116
+ /**
117
+ * Return a serializable snapshot of the state history for snapshot testing.
118
+ * Use with your test framework's toMatchSnapshot() or similar.
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * const tester = createPlocTester(ploc);
123
+ * // ... trigger state changes ...
124
+ * expect(getStateHistorySnapshot(tester)).toMatchSnapshot();
125
+ * ```
126
+ */
127
+ export declare function getStateHistorySnapshot<T>(tester: PlocTester<T>): T[];
128
+ /**
129
+ * Return a serialized (JSON) snapshot of the state history for snapshot testing.
130
+ * Useful when state is plain data and you want a string snapshot.
131
+ */
132
+ export declare function getStateHistorySnapshotJson<T>(tester: PlocTester<T>): string;
133
+ export {};