@c.a.f/testing 1.0.0
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.
- package/.build/__tests__/react/renderWithCAF.spec.d.ts +1 -0
- package/.build/__tests__/react/renderWithCAF.spec.js +53 -0
- package/.build/index.d.ts +1 -0
- package/.build/index.js +1 -0
- package/.build/src/core/IntegrationTestHelpers.d.ts +77 -0
- package/.build/src/core/IntegrationTestHelpers.js +78 -0
- package/.build/src/core/PlocTestHelpers.d.ts +133 -0
- package/.build/src/core/PlocTestHelpers.js +205 -0
- package/.build/src/core/PulseTestHelpers.d.ts +71 -0
- package/.build/src/core/PulseTestHelpers.js +106 -0
- package/.build/src/core/RepositoryTestHelpers.d.ts +48 -0
- package/.build/src/core/RepositoryTestHelpers.js +76 -0
- package/.build/src/core/RouteTestHelpers.d.ts +67 -0
- package/.build/src/core/RouteTestHelpers.js +94 -0
- package/.build/src/core/UseCaseTestHelpers.d.ts +100 -0
- package/.build/src/core/UseCaseTestHelpers.js +161 -0
- package/.build/src/core/index.d.ts +6 -0
- package/.build/src/core/index.js +6 -0
- package/.build/src/i18n/I18nTestHelpers.d.ts +76 -0
- package/.build/src/i18n/I18nTestHelpers.js +122 -0
- package/.build/src/i18n/index.d.ts +1 -0
- package/.build/src/i18n/index.js +1 -0
- package/.build/src/index.d.ts +5 -0
- package/.build/src/index.js +10 -0
- package/.build/src/permission/PermissionTestHelpers.d.ts +75 -0
- package/.build/src/permission/PermissionTestHelpers.js +121 -0
- package/.build/src/permission/index.d.ts +1 -0
- package/.build/src/permission/index.js +1 -0
- package/.build/src/react/createTestPloc.d.ts +19 -0
- package/.build/src/react/createTestPloc.js +21 -0
- package/.build/src/react/index.d.ts +12 -0
- package/.build/src/react/index.js +12 -0
- package/.build/src/react/mockUseCase.d.ts +36 -0
- package/.build/src/react/mockUseCase.js +44 -0
- package/.build/src/react/renderWithCAF.d.ts +31 -0
- package/.build/src/react/renderWithCAF.js +23 -0
- package/.build/src/react/waitForPlocState.d.ts +22 -0
- package/.build/src/react/waitForPlocState.js +24 -0
- package/.build/src/validation/ValidationTestHelpers.d.ts +66 -0
- package/.build/src/validation/ValidationTestHelpers.js +118 -0
- package/.build/src/validation/index.d.ts +1 -0
- package/.build/src/validation/index.js +1 -0
- package/.build/src/workflow/WorkflowTestHelpers.d.ts +75 -0
- package/.build/src/workflow/WorkflowTestHelpers.js +146 -0
- package/.build/src/workflow/index.d.ts +1 -0
- package/.build/src/workflow/index.js +1 -0
- package/.build/vitest.config.d.ts +7 -0
- package/.build/vitest.config.js +6 -0
- package/README.md +503 -0
- package/package.json +87 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test helpers for Validation.
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for testing validators and validation runners.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { createMockValidator, createValidationTester } from '@c.a.f/testing/validation';
|
|
9
|
+
* import { ValidationRunner } from '@c.a.f/validation';
|
|
10
|
+
*
|
|
11
|
+
* const mockValidator = createMockValidator((data) => {
|
|
12
|
+
* return data.email && data.email.includes('@');
|
|
13
|
+
* });
|
|
14
|
+
* const tester = createValidationTester(mockValidator);
|
|
15
|
+
*
|
|
16
|
+
* const result = await tester.validate({ email: 'test@example.com' });
|
|
17
|
+
* expect(result.success).toBe(true);
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
import type { IValidator, ValidationResult, ValidationError } from '@c.a.f/validation';
|
|
21
|
+
/**
|
|
22
|
+
* Mock Validator implementation for testing.
|
|
23
|
+
*/
|
|
24
|
+
export declare class MockValidator<T = unknown> implements IValidator<T> {
|
|
25
|
+
private validateFn;
|
|
26
|
+
private errorMessage?;
|
|
27
|
+
constructor(validateFn: (data: unknown) => boolean | Promise<boolean>, errorMessage?: string | undefined);
|
|
28
|
+
validate(data: unknown): Promise<ValidationResult>;
|
|
29
|
+
parse(data: unknown): Promise<T>;
|
|
30
|
+
isValid(data: unknown): Promise<boolean>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Create a mock Validator.
|
|
34
|
+
*/
|
|
35
|
+
export declare function createMockValidator<T = unknown>(validateFn: (data: unknown) => boolean | Promise<boolean>, errorMessage?: string): IValidator<T>;
|
|
36
|
+
/**
|
|
37
|
+
* Validation tester utility.
|
|
38
|
+
*/
|
|
39
|
+
export declare class ValidationTester<T = unknown> {
|
|
40
|
+
readonly validator: IValidator<T>;
|
|
41
|
+
constructor(validator: IValidator<T>);
|
|
42
|
+
/**
|
|
43
|
+
* Validate data.
|
|
44
|
+
*/
|
|
45
|
+
validate(data: unknown): Promise<ValidationResult>;
|
|
46
|
+
/**
|
|
47
|
+
* Parse and validate data.
|
|
48
|
+
*/
|
|
49
|
+
parse(data: unknown): Promise<T>;
|
|
50
|
+
/**
|
|
51
|
+
* Check if data is valid.
|
|
52
|
+
*/
|
|
53
|
+
isValid(data: unknown): Promise<boolean>;
|
|
54
|
+
/**
|
|
55
|
+
* Validate and expect success.
|
|
56
|
+
*/
|
|
57
|
+
expectSuccess(data: unknown): Promise<T>;
|
|
58
|
+
/**
|
|
59
|
+
* Validate and expect failure.
|
|
60
|
+
*/
|
|
61
|
+
expectFailure(data: unknown): Promise<ValidationError[]>;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Create a Validation tester instance.
|
|
65
|
+
*/
|
|
66
|
+
export declare function createValidationTester<T = unknown>(validator: IValidator<T>): ValidationTester<T>;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test helpers for Validation.
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for testing validators and validation runners.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { createMockValidator, createValidationTester } from '@c.a.f/testing/validation';
|
|
9
|
+
* import { ValidationRunner } from '@c.a.f/validation';
|
|
10
|
+
*
|
|
11
|
+
* const mockValidator = createMockValidator((data) => {
|
|
12
|
+
* return data.email && data.email.includes('@');
|
|
13
|
+
* });
|
|
14
|
+
* const tester = createValidationTester(mockValidator);
|
|
15
|
+
*
|
|
16
|
+
* const result = await tester.validate({ email: 'test@example.com' });
|
|
17
|
+
* expect(result.success).toBe(true);
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Mock Validator implementation for testing.
|
|
22
|
+
*/
|
|
23
|
+
export class MockValidator {
|
|
24
|
+
validateFn;
|
|
25
|
+
errorMessage;
|
|
26
|
+
constructor(validateFn, errorMessage) {
|
|
27
|
+
this.validateFn = validateFn;
|
|
28
|
+
this.errorMessage = errorMessage;
|
|
29
|
+
}
|
|
30
|
+
async validate(data) {
|
|
31
|
+
const isValid = await this.validateFn(data);
|
|
32
|
+
if (isValid) {
|
|
33
|
+
return {
|
|
34
|
+
success: true,
|
|
35
|
+
errors: [],
|
|
36
|
+
data: data,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
success: false,
|
|
41
|
+
errors: [
|
|
42
|
+
{
|
|
43
|
+
path: '',
|
|
44
|
+
message: this.errorMessage || 'Validation failed',
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
async parse(data) {
|
|
50
|
+
const result = await this.validate(data);
|
|
51
|
+
if (!result.success) {
|
|
52
|
+
throw new Error(result.errors.map(e => e.message).join(', '));
|
|
53
|
+
}
|
|
54
|
+
return result.data;
|
|
55
|
+
}
|
|
56
|
+
async isValid(data) {
|
|
57
|
+
return await this.validateFn(data);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Create a mock Validator.
|
|
62
|
+
*/
|
|
63
|
+
export function createMockValidator(validateFn, errorMessage) {
|
|
64
|
+
return new MockValidator(validateFn, errorMessage);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Validation tester utility.
|
|
68
|
+
*/
|
|
69
|
+
export class ValidationTester {
|
|
70
|
+
validator;
|
|
71
|
+
constructor(validator) {
|
|
72
|
+
this.validator = validator;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Validate data.
|
|
76
|
+
*/
|
|
77
|
+
async validate(data) {
|
|
78
|
+
return await this.validator.validate(data);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Parse and validate data.
|
|
82
|
+
*/
|
|
83
|
+
async parse(data) {
|
|
84
|
+
return await this.validator.parse(data);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Check if data is valid.
|
|
88
|
+
*/
|
|
89
|
+
async isValid(data) {
|
|
90
|
+
return await this.validator.isValid(data);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Validate and expect success.
|
|
94
|
+
*/
|
|
95
|
+
async expectSuccess(data) {
|
|
96
|
+
const result = await this.validate(data);
|
|
97
|
+
if (!result.success) {
|
|
98
|
+
throw new Error(`Expected validation success but got errors: ${result.errors.map(e => e.message).join(', ')}`);
|
|
99
|
+
}
|
|
100
|
+
return result.data;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Validate and expect failure.
|
|
104
|
+
*/
|
|
105
|
+
async expectFailure(data) {
|
|
106
|
+
const result = await this.validate(data);
|
|
107
|
+
if (result.success) {
|
|
108
|
+
throw new Error('Expected validation failure but validation succeeded');
|
|
109
|
+
}
|
|
110
|
+
return result.errors;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Create a Validation tester instance.
|
|
115
|
+
*/
|
|
116
|
+
export function createValidationTester(validator) {
|
|
117
|
+
return new ValidationTester(validator);
|
|
118
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ValidationTestHelpers';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ValidationTestHelpers';
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test helpers for Workflow.
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for testing WorkflowManager instances.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { createWorkflowTester, waitForWorkflowState } from '@c.a.f/testing/workflow';
|
|
9
|
+
* import { WorkflowManager, WorkflowDefinition } from '@c.a.f/workflow';
|
|
10
|
+
*
|
|
11
|
+
* const workflow = new WorkflowManager(definition);
|
|
12
|
+
* const tester = createWorkflowTester(workflow);
|
|
13
|
+
*
|
|
14
|
+
* await tester.dispatch('approve');
|
|
15
|
+
* await waitForWorkflowState(workflow, 'approved');
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
import type { WorkflowManager, WorkflowStateId, WorkflowStateSnapshot } from '@c.a.f/workflow';
|
|
19
|
+
/**
|
|
20
|
+
* Workflow tester utility.
|
|
21
|
+
*/
|
|
22
|
+
export declare class WorkflowTester {
|
|
23
|
+
readonly workflow: WorkflowManager;
|
|
24
|
+
private stateHistory;
|
|
25
|
+
private listener;
|
|
26
|
+
constructor(workflow: WorkflowManager);
|
|
27
|
+
/**
|
|
28
|
+
* Get the current state snapshot.
|
|
29
|
+
*/
|
|
30
|
+
getState(): WorkflowStateSnapshot;
|
|
31
|
+
/**
|
|
32
|
+
* Get the current state ID.
|
|
33
|
+
*/
|
|
34
|
+
getCurrentState(): WorkflowStateId;
|
|
35
|
+
/**
|
|
36
|
+
* Get the state history.
|
|
37
|
+
*/
|
|
38
|
+
getStateHistory(): WorkflowStateSnapshot[];
|
|
39
|
+
/**
|
|
40
|
+
* Dispatch an event and wait for transition.
|
|
41
|
+
*/
|
|
42
|
+
dispatch(event: string, payload?: unknown): Promise<boolean>;
|
|
43
|
+
/**
|
|
44
|
+
* Check if a transition is available.
|
|
45
|
+
*/
|
|
46
|
+
canTransition(event: string): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Reset the workflow.
|
|
49
|
+
*/
|
|
50
|
+
reset(): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Update workflow context.
|
|
53
|
+
*/
|
|
54
|
+
updateContext(context: Record<string, unknown>): void;
|
|
55
|
+
/**
|
|
56
|
+
* Get available transitions from current state.
|
|
57
|
+
*/
|
|
58
|
+
getAvailableTransitions(): Record<string, unknown>;
|
|
59
|
+
/**
|
|
60
|
+
* Cleanup: unsubscribe from state changes.
|
|
61
|
+
*/
|
|
62
|
+
cleanup(): void;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Create a Workflow tester instance.
|
|
66
|
+
*/
|
|
67
|
+
export declare function createWorkflowTester(workflow: WorkflowManager): WorkflowTester;
|
|
68
|
+
/**
|
|
69
|
+
* Wait for workflow to reach a specific state.
|
|
70
|
+
*/
|
|
71
|
+
export declare function waitForWorkflowState(workflow: WorkflowManager, targetState: WorkflowStateId, timeout?: number): Promise<WorkflowStateSnapshot>;
|
|
72
|
+
/**
|
|
73
|
+
* Wait for workflow to reach a final state.
|
|
74
|
+
*/
|
|
75
|
+
export declare function waitForFinalState(workflow: WorkflowManager, timeout?: number): Promise<WorkflowStateSnapshot>;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test helpers for Workflow.
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for testing WorkflowManager instances.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { createWorkflowTester, waitForWorkflowState } from '@c.a.f/testing/workflow';
|
|
9
|
+
* import { WorkflowManager, WorkflowDefinition } from '@c.a.f/workflow';
|
|
10
|
+
*
|
|
11
|
+
* const workflow = new WorkflowManager(definition);
|
|
12
|
+
* const tester = createWorkflowTester(workflow);
|
|
13
|
+
*
|
|
14
|
+
* await tester.dispatch('approve');
|
|
15
|
+
* await waitForWorkflowState(workflow, 'approved');
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Workflow tester utility.
|
|
20
|
+
*/
|
|
21
|
+
export class WorkflowTester {
|
|
22
|
+
workflow;
|
|
23
|
+
stateHistory = [];
|
|
24
|
+
listener = null;
|
|
25
|
+
constructor(workflow) {
|
|
26
|
+
this.workflow = workflow;
|
|
27
|
+
this.stateHistory.push(workflow.getState());
|
|
28
|
+
this.listener = (snapshot) => {
|
|
29
|
+
this.stateHistory.push(snapshot);
|
|
30
|
+
};
|
|
31
|
+
workflow.subscribe(this.listener);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Get the current state snapshot.
|
|
35
|
+
*/
|
|
36
|
+
getState() {
|
|
37
|
+
return this.workflow.getState();
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Get the current state ID.
|
|
41
|
+
*/
|
|
42
|
+
getCurrentState() {
|
|
43
|
+
return this.workflow.getState().currentState;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Get the state history.
|
|
47
|
+
*/
|
|
48
|
+
getStateHistory() {
|
|
49
|
+
return [...this.stateHistory];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Dispatch an event and wait for transition.
|
|
53
|
+
*/
|
|
54
|
+
async dispatch(event, payload) {
|
|
55
|
+
return await this.workflow.dispatch(event, payload);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Check if a transition is available.
|
|
59
|
+
*/
|
|
60
|
+
canTransition(event) {
|
|
61
|
+
return this.workflow.canTransition(event);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Reset the workflow.
|
|
65
|
+
*/
|
|
66
|
+
async reset() {
|
|
67
|
+
await this.workflow.reset();
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Update workflow context.
|
|
71
|
+
*/
|
|
72
|
+
updateContext(context) {
|
|
73
|
+
this.workflow.updateContext(context);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get available transitions from current state.
|
|
77
|
+
*/
|
|
78
|
+
getAvailableTransitions() {
|
|
79
|
+
return this.workflow.getAvailableTransitions();
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Cleanup: unsubscribe from state changes.
|
|
83
|
+
*/
|
|
84
|
+
cleanup() {
|
|
85
|
+
if (this.listener) {
|
|
86
|
+
this.workflow.unsubscribe(this.listener);
|
|
87
|
+
this.listener = null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Create a Workflow tester instance.
|
|
93
|
+
*/
|
|
94
|
+
export function createWorkflowTester(workflow) {
|
|
95
|
+
return new WorkflowTester(workflow);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Wait for workflow to reach a specific state.
|
|
99
|
+
*/
|
|
100
|
+
export function waitForWorkflowState(workflow, targetState, timeout = 5000) {
|
|
101
|
+
return new Promise((resolve, reject) => {
|
|
102
|
+
// Check current state first
|
|
103
|
+
const currentState = workflow.getState();
|
|
104
|
+
if (currentState.currentState === targetState) {
|
|
105
|
+
resolve(currentState);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const listener = (snapshot) => {
|
|
109
|
+
if (snapshot.currentState === targetState) {
|
|
110
|
+
clearTimeout(timer);
|
|
111
|
+
workflow.unsubscribe(listener);
|
|
112
|
+
resolve(snapshot);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const timer = setTimeout(() => {
|
|
116
|
+
workflow.unsubscribe(listener);
|
|
117
|
+
reject(new Error(`Timeout waiting for workflow state '${targetState}' (${timeout}ms)`));
|
|
118
|
+
}, timeout);
|
|
119
|
+
workflow.subscribe(listener);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Wait for workflow to reach a final state.
|
|
124
|
+
*/
|
|
125
|
+
export function waitForFinalState(workflow, timeout = 5000) {
|
|
126
|
+
return new Promise((resolve, reject) => {
|
|
127
|
+
// Check current state first
|
|
128
|
+
const currentState = workflow.getState();
|
|
129
|
+
if (currentState.isFinal) {
|
|
130
|
+
resolve(currentState);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const listener = (snapshot) => {
|
|
134
|
+
if (snapshot.isFinal) {
|
|
135
|
+
clearTimeout(timer);
|
|
136
|
+
workflow.unsubscribe(listener);
|
|
137
|
+
resolve(snapshot);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
const timer = setTimeout(() => {
|
|
141
|
+
workflow.unsubscribe(listener);
|
|
142
|
+
reject(new Error(`Timeout waiting for final state (${timeout}ms)`));
|
|
143
|
+
}, timeout);
|
|
144
|
+
workflow.subscribe(listener);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './WorkflowTestHelpers';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './WorkflowTestHelpers';
|