@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.
- 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/angular/createTestPloc.d.ts +19 -0
- package/.build/src/angular/createTestPloc.js +21 -0
- package/.build/src/angular/index.d.ts +12 -0
- package/.build/src/angular/index.js +12 -0
- package/.build/src/angular/mockUseCase.d.ts +32 -0
- package/.build/src/angular/mockUseCase.js +40 -0
- package/.build/src/angular/provideTestingCAF.d.ts +29 -0
- package/.build/src/angular/provideTestingCAF.js +26 -0
- package/.build/src/angular/waitForPlocState.d.ts +18 -0
- package/.build/src/angular/waitForPlocState.js +20 -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/vue/createTestPloc.d.ts +19 -0
- package/.build/src/vue/createTestPloc.js +21 -0
- package/.build/src/vue/index.d.ts +12 -0
- package/.build/src/vue/index.js +12 -0
- package/.build/src/vue/mockUseCase.d.ts +34 -0
- package/.build/src/vue/mockUseCase.js +42 -0
- package/.build/src/vue/mountWithCAF.d.ts +31 -0
- package/.build/src/vue/mountWithCAF.js +40 -0
- package/.build/src/vue/waitForPlocState.d.ts +19 -0
- package/.build/src/vue/waitForPlocState.js +21 -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 +598 -0
- package/package.json +127 -0
|
@@ -0,0 +1,205 @@
|
|
|
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
|
+
/**
|
|
26
|
+
* Concrete Ploc implementation for testing.
|
|
27
|
+
* Provides a Ploc with controllable state and no business logic.
|
|
28
|
+
*/
|
|
29
|
+
export class MockPloc extends Ploc {
|
|
30
|
+
constructor(initialState) {
|
|
31
|
+
super(initialState);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Create a mock Ploc with controllable state for unit tests.
|
|
36
|
+
* The returned Ploc has no logic; use changeState() to drive state in tests.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* const ploc = createMockPloc({ count: 0, loading: false });
|
|
41
|
+
* expect(ploc.state.count).toBe(0);
|
|
42
|
+
* ploc.changeState({ count: 1, loading: true });
|
|
43
|
+
* expect(ploc.state.count).toBe(1);
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export function createMockPloc(initialState) {
|
|
47
|
+
return new MockPloc(initialState);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Ploc tester utility.
|
|
51
|
+
* Tracks state changes and provides testing utilities.
|
|
52
|
+
*/
|
|
53
|
+
export class PlocTester {
|
|
54
|
+
ploc;
|
|
55
|
+
stateHistory = [];
|
|
56
|
+
listener = null;
|
|
57
|
+
constructor(ploc) {
|
|
58
|
+
this.ploc = ploc;
|
|
59
|
+
this.stateHistory.push(ploc.state);
|
|
60
|
+
this.listener = (state) => {
|
|
61
|
+
this.stateHistory.push(state);
|
|
62
|
+
};
|
|
63
|
+
ploc.subscribe(this.listener);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get the current state.
|
|
67
|
+
*/
|
|
68
|
+
getState() {
|
|
69
|
+
return this.ploc.state;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Get the state history.
|
|
73
|
+
*/
|
|
74
|
+
getStateHistory() {
|
|
75
|
+
return [...this.stateHistory];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get the initial state.
|
|
79
|
+
*/
|
|
80
|
+
getInitialState() {
|
|
81
|
+
return this.stateHistory[0];
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Get the last state change.
|
|
85
|
+
*/
|
|
86
|
+
getLastStateChange() {
|
|
87
|
+
return this.stateHistory.length > 1
|
|
88
|
+
? this.stateHistory[this.stateHistory.length - 1]
|
|
89
|
+
: undefined;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get the number of state changes.
|
|
93
|
+
*/
|
|
94
|
+
getStateChangeCount() {
|
|
95
|
+
return Math.max(0, this.stateHistory.length - 1);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Cleanup: unsubscribe from state changes.
|
|
99
|
+
*/
|
|
100
|
+
cleanup() {
|
|
101
|
+
if (this.listener) {
|
|
102
|
+
this.ploc.unsubscribe(this.listener);
|
|
103
|
+
this.listener = null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Create a Ploc tester instance.
|
|
109
|
+
*/
|
|
110
|
+
export function createPlocTester(ploc) {
|
|
111
|
+
return new PlocTester(ploc);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Wait for a state change that matches a predicate.
|
|
115
|
+
*
|
|
116
|
+
* @param ploc The Ploc instance to watch
|
|
117
|
+
* @param predicate Function that returns true when the desired state is reached
|
|
118
|
+
* @param timeout Maximum time to wait in milliseconds (default: 5000)
|
|
119
|
+
* @returns Promise that resolves when the predicate returns true
|
|
120
|
+
*/
|
|
121
|
+
export function waitForStateChange(ploc, predicate, timeout = 5000) {
|
|
122
|
+
return new Promise((resolve, reject) => {
|
|
123
|
+
// Check current state first
|
|
124
|
+
if (predicate(ploc.state)) {
|
|
125
|
+
resolve(ploc.state);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const listener = (state) => {
|
|
129
|
+
if (predicate(state)) {
|
|
130
|
+
clearTimeout(timer);
|
|
131
|
+
ploc.unsubscribe(listener);
|
|
132
|
+
resolve(state);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
const timer = setTimeout(() => {
|
|
136
|
+
ploc.unsubscribe(listener);
|
|
137
|
+
reject(new Error(`Timeout waiting for state change (${timeout}ms)`));
|
|
138
|
+
}, timeout);
|
|
139
|
+
ploc.subscribe(listener);
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Wait for a specific number of state changes.
|
|
144
|
+
*/
|
|
145
|
+
export function waitForStateChanges(ploc, count, timeout = 5000) {
|
|
146
|
+
return new Promise((resolve, reject) => {
|
|
147
|
+
const states = [];
|
|
148
|
+
const listener = (state) => {
|
|
149
|
+
states.push(state);
|
|
150
|
+
if (states.length >= count) {
|
|
151
|
+
clearTimeout(timer);
|
|
152
|
+
ploc.unsubscribe(listener);
|
|
153
|
+
resolve(states);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
const timer = setTimeout(() => {
|
|
157
|
+
ploc.unsubscribe(listener);
|
|
158
|
+
reject(new Error(`Timeout waiting for ${count} state changes (${timeout}ms)`));
|
|
159
|
+
}, timeout);
|
|
160
|
+
ploc.subscribe(listener);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
// --- Snapshot testing utilities ---
|
|
164
|
+
/**
|
|
165
|
+
* Assert that the Ploc tester's state history matches the expected states.
|
|
166
|
+
* Uses JSON comparison so objects are compared by value.
|
|
167
|
+
* Use with your test framework's expect (e.g. expect().toEqual).
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```ts
|
|
171
|
+
* const tester = createPlocTester(ploc);
|
|
172
|
+
* ploc.changeState({ step: 1 });
|
|
173
|
+
* ploc.changeState({ step: 2 });
|
|
174
|
+
* assertStateHistory(tester, [initialState, { step: 1 }, { step: 2 }]);
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
export function assertStateHistory(tester, expected) {
|
|
178
|
+
const actual = tester.getStateHistory();
|
|
179
|
+
const actualJson = JSON.stringify(actual);
|
|
180
|
+
const expectedJson = JSON.stringify(expected);
|
|
181
|
+
if (actualJson !== expectedJson) {
|
|
182
|
+
throw new Error(`State history mismatch.\nExpected: ${expectedJson}\nActual: ${actualJson}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Return a serializable snapshot of the state history for snapshot testing.
|
|
187
|
+
* Use with your test framework's toMatchSnapshot() or similar.
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```ts
|
|
191
|
+
* const tester = createPlocTester(ploc);
|
|
192
|
+
* // ... trigger state changes ...
|
|
193
|
+
* expect(getStateHistorySnapshot(tester)).toMatchSnapshot();
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
export function getStateHistorySnapshot(tester) {
|
|
197
|
+
return tester.getStateHistory();
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Return a serialized (JSON) snapshot of the state history for snapshot testing.
|
|
201
|
+
* Useful when state is plain data and you want a string snapshot.
|
|
202
|
+
*/
|
|
203
|
+
export function getStateHistorySnapshotJson(tester) {
|
|
204
|
+
return JSON.stringify(tester.getStateHistory(), null, 2);
|
|
205
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test helpers for Pulse (reactive values).
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for testing Pulse instances.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { createPulseTester, waitForPulseValue } from '@c-a-f/testing/core';
|
|
9
|
+
* import { pulse } from '@c-a-f/core';
|
|
10
|
+
*
|
|
11
|
+
* const count = pulse(0);
|
|
12
|
+
* const tester = createPulseTester(count);
|
|
13
|
+
*
|
|
14
|
+
* count.value = 5;
|
|
15
|
+
* await waitForPulseValue(count, (value) => value === 5);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
import type { Pulse } from '@c-a-f/core';
|
|
19
|
+
/**
|
|
20
|
+
* Pulse tester utility.
|
|
21
|
+
* Tracks value changes and provides testing utilities.
|
|
22
|
+
*/
|
|
23
|
+
type PulseLike<T> = Pulse<T> & {
|
|
24
|
+
value: T;
|
|
25
|
+
subscribe(listener: (value: T) => void): void;
|
|
26
|
+
unsubscribe(listener: (value: T) => void): void;
|
|
27
|
+
};
|
|
28
|
+
export declare class PulseTester<T> {
|
|
29
|
+
readonly pulse: PulseLike<T>;
|
|
30
|
+
private valueHistory;
|
|
31
|
+
private listener;
|
|
32
|
+
constructor(pulse: PulseLike<T>);
|
|
33
|
+
/**
|
|
34
|
+
* Get the current value.
|
|
35
|
+
*/
|
|
36
|
+
getValue(): T;
|
|
37
|
+
/**
|
|
38
|
+
* Get the value history.
|
|
39
|
+
*/
|
|
40
|
+
getValueHistory(): T[];
|
|
41
|
+
/**
|
|
42
|
+
* Get the initial value.
|
|
43
|
+
*/
|
|
44
|
+
getInitialValue(): T;
|
|
45
|
+
/**
|
|
46
|
+
* Get the last value change.
|
|
47
|
+
*/
|
|
48
|
+
getLastValueChange(): T | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Get the number of value changes.
|
|
51
|
+
*/
|
|
52
|
+
getValueChangeCount(): number;
|
|
53
|
+
/**
|
|
54
|
+
* Cleanup: unsubscribe from value changes.
|
|
55
|
+
*/
|
|
56
|
+
cleanup(): void;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Create a Pulse tester instance.
|
|
60
|
+
*/
|
|
61
|
+
export declare function createPulseTester<T>(pulse: PulseLike<T>): PulseTester<T>;
|
|
62
|
+
/**
|
|
63
|
+
* Wait for a pulse value that matches a predicate.
|
|
64
|
+
*
|
|
65
|
+
* @param pulse The Pulse instance to watch
|
|
66
|
+
* @param predicate Function that returns true when the desired value is reached
|
|
67
|
+
* @param timeout Maximum time to wait in milliseconds (default: 5000)
|
|
68
|
+
* @returns Promise that resolves when the predicate returns true
|
|
69
|
+
*/
|
|
70
|
+
export declare function waitForPulseValue<T>(pulse: PulseLike<T>, predicate: (value: T) => boolean, timeout?: number): Promise<T>;
|
|
71
|
+
export {};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test helpers for Pulse (reactive values).
|
|
3
|
+
*
|
|
4
|
+
* Provides utilities for testing Pulse instances.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { createPulseTester, waitForPulseValue } from '@c-a-f/testing/core';
|
|
9
|
+
* import { pulse } from '@c-a-f/core';
|
|
10
|
+
*
|
|
11
|
+
* const count = pulse(0);
|
|
12
|
+
* const tester = createPulseTester(count);
|
|
13
|
+
*
|
|
14
|
+
* count.value = 5;
|
|
15
|
+
* await waitForPulseValue(count, (value) => value === 5);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export class PulseTester {
|
|
19
|
+
pulse;
|
|
20
|
+
valueHistory = [];
|
|
21
|
+
listener = null;
|
|
22
|
+
constructor(pulse) {
|
|
23
|
+
this.pulse = pulse;
|
|
24
|
+
this.valueHistory.push(pulse.value);
|
|
25
|
+
this.listener = (value) => {
|
|
26
|
+
this.valueHistory.push(value);
|
|
27
|
+
};
|
|
28
|
+
pulse.subscribe(this.listener);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Get the current value.
|
|
32
|
+
*/
|
|
33
|
+
getValue() {
|
|
34
|
+
return this.pulse.value;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get the value history.
|
|
38
|
+
*/
|
|
39
|
+
getValueHistory() {
|
|
40
|
+
return [...this.valueHistory];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get the initial value.
|
|
44
|
+
*/
|
|
45
|
+
getInitialValue() {
|
|
46
|
+
return this.valueHistory[0];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Get the last value change.
|
|
50
|
+
*/
|
|
51
|
+
getLastValueChange() {
|
|
52
|
+
return this.valueHistory.length > 1
|
|
53
|
+
? this.valueHistory[this.valueHistory.length - 1]
|
|
54
|
+
: undefined;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get the number of value changes.
|
|
58
|
+
*/
|
|
59
|
+
getValueChangeCount() {
|
|
60
|
+
return Math.max(0, this.valueHistory.length - 1);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Cleanup: unsubscribe from value changes.
|
|
64
|
+
*/
|
|
65
|
+
cleanup() {
|
|
66
|
+
if (this.listener) {
|
|
67
|
+
this.pulse.unsubscribe(this.listener);
|
|
68
|
+
this.listener = null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Create a Pulse tester instance.
|
|
74
|
+
*/
|
|
75
|
+
export function createPulseTester(pulse) {
|
|
76
|
+
return new PulseTester(pulse);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Wait for a pulse value that matches a predicate.
|
|
80
|
+
*
|
|
81
|
+
* @param pulse The Pulse instance to watch
|
|
82
|
+
* @param predicate Function that returns true when the desired value is reached
|
|
83
|
+
* @param timeout Maximum time to wait in milliseconds (default: 5000)
|
|
84
|
+
* @returns Promise that resolves when the predicate returns true
|
|
85
|
+
*/
|
|
86
|
+
export function waitForPulseValue(pulse, predicate, timeout = 5000) {
|
|
87
|
+
return new Promise((resolve, reject) => {
|
|
88
|
+
// Check current value first
|
|
89
|
+
if (predicate(pulse.value)) {
|
|
90
|
+
resolve(pulse.value);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const listener = (value) => {
|
|
94
|
+
if (predicate(value)) {
|
|
95
|
+
clearTimeout(timer);
|
|
96
|
+
pulse.unsubscribe(listener);
|
|
97
|
+
resolve(value);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
const timer = setTimeout(() => {
|
|
101
|
+
pulse.unsubscribe(listener);
|
|
102
|
+
reject(new Error(`Timeout waiting for pulse value (${timeout}ms)`));
|
|
103
|
+
}, timeout);
|
|
104
|
+
pulse.subscribe(listener);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test helpers for domain repository interfaces (I*Repository).
|
|
3
|
+
*
|
|
4
|
+
* Provides a generic stub so you can override only the methods your test needs.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { createMockRepository } from '@c-a-f/testing/core';
|
|
9
|
+
* import type { IUserRepository } from '../domain';
|
|
10
|
+
*
|
|
11
|
+
* const mockRepo = createMockRepository<IUserRepository>({
|
|
12
|
+
* getUsers: async () => [{ id: '1', name: 'John' }],
|
|
13
|
+
* getUserById: async (id) => ({ id, name: 'User ' + id }),
|
|
14
|
+
* });
|
|
15
|
+
* // getUsers and getUserById are stubbed; other methods return undefined (can be overridden)
|
|
16
|
+
*
|
|
17
|
+
* // Or use an empty stub and assign/spy later
|
|
18
|
+
* const stub = createMockRepository<IUserRepository>();
|
|
19
|
+
* stub.getUsers = async () => [];
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Create a generic mock repository stub.
|
|
24
|
+
* - With no args: returns a proxy that implements any method as async () => undefined.
|
|
25
|
+
* You can assign specific methods or use with a test spy.
|
|
26
|
+
* - With methods: returns an object with those methods; any other method call
|
|
27
|
+
* returns undefined (optional second argument can provide a default).
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* const repo = createMockRepository<IUserRepository>({
|
|
32
|
+
* getUsers: async () => [],
|
|
33
|
+
* getUserById: async (id) => ({ id, name: 'Test' }),
|
|
34
|
+
* });
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function createMockRepository<T extends Record<string, (...args: any[]) => Promise<any>>>(methods?: Partial<T>): T;
|
|
38
|
+
/**
|
|
39
|
+
* Create an empty repository stub. Every method returns Promise.resolve(undefined).
|
|
40
|
+
* Assign or spy on methods as needed.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* const repo = createMockRepositoryStub<IUserRepository>();
|
|
45
|
+
* repo.getUsers = vi.fn().mockResolvedValue([{ id: '1', name: 'John' }]);
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare function createMockRepositoryStub<T>(): T;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test helpers for domain repository interfaces (I*Repository).
|
|
3
|
+
*
|
|
4
|
+
* Provides a generic stub so you can override only the methods your test needs.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { createMockRepository } from '@c-a-f/testing/core';
|
|
9
|
+
* import type { IUserRepository } from '../domain';
|
|
10
|
+
*
|
|
11
|
+
* const mockRepo = createMockRepository<IUserRepository>({
|
|
12
|
+
* getUsers: async () => [{ id: '1', name: 'John' }],
|
|
13
|
+
* getUserById: async (id) => ({ id, name: 'User ' + id }),
|
|
14
|
+
* });
|
|
15
|
+
* // getUsers and getUserById are stubbed; other methods return undefined (can be overridden)
|
|
16
|
+
*
|
|
17
|
+
* // Or use an empty stub and assign/spy later
|
|
18
|
+
* const stub = createMockRepository<IUserRepository>();
|
|
19
|
+
* stub.getUsers = async () => [];
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
const defaultAsyncStub = async () => undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Create a generic mock repository stub.
|
|
25
|
+
* - With no args: returns a proxy that implements any method as async () => undefined.
|
|
26
|
+
* You can assign specific methods or use with a test spy.
|
|
27
|
+
* - With methods: returns an object with those methods; any other method call
|
|
28
|
+
* returns undefined (optional second argument can provide a default).
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* const repo = createMockRepository<IUserRepository>({
|
|
33
|
+
* getUsers: async () => [],
|
|
34
|
+
* getUserById: async (id) => ({ id, name: 'Test' }),
|
|
35
|
+
* });
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export function createMockRepository(methods) {
|
|
39
|
+
const base = (methods ?? {});
|
|
40
|
+
return new Proxy(base, {
|
|
41
|
+
get(target, prop) {
|
|
42
|
+
if (prop in target && typeof target[prop] === 'function') {
|
|
43
|
+
return target[prop];
|
|
44
|
+
}
|
|
45
|
+
return defaultAsyncStub;
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create an empty repository stub. Every method returns Promise.resolve(undefined).
|
|
51
|
+
* Assign or spy on methods as needed.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* const repo = createMockRepositoryStub<IUserRepository>();
|
|
56
|
+
* repo.getUsers = vi.fn().mockResolvedValue([{ id: '1', name: 'John' }]);
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export function createMockRepositoryStub() {
|
|
60
|
+
const target = {};
|
|
61
|
+
return new Proxy(target, {
|
|
62
|
+
get(target, prop) {
|
|
63
|
+
// If property exists on target (was assigned), return it
|
|
64
|
+
if (prop in target) {
|
|
65
|
+
return target[prop];
|
|
66
|
+
}
|
|
67
|
+
// Otherwise return default stub
|
|
68
|
+
return defaultAsyncStub;
|
|
69
|
+
},
|
|
70
|
+
set(target, prop, value) {
|
|
71
|
+
// Allow assignment
|
|
72
|
+
target[prop] = value;
|
|
73
|
+
return true;
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test helpers for RouteManager and RouteRepository.
|
|
3
|
+
*
|
|
4
|
+
* Provides mock implementations and utilities for testing routing.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { createMockRouteRepository, createRouteManagerTester } from '@c-a-f/testing/core';
|
|
9
|
+
* import { RouteManager } from '@c-a-f/core';
|
|
10
|
+
*
|
|
11
|
+
* const mockRepo = createMockRouteRepository();
|
|
12
|
+
* const routeManager = new RouteManager(mockRepo);
|
|
13
|
+
* const tester = createRouteManagerTester(routeManager);
|
|
14
|
+
*
|
|
15
|
+
* await tester.changeRoute('/dashboard');
|
|
16
|
+
* expect(tester.getCurrentRoute()).toBe('/dashboard');
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
import type { RouteRepository, RouteManager } from '@c-a-f/core';
|
|
20
|
+
/**
|
|
21
|
+
* Mock RouteRepository implementation for testing.
|
|
22
|
+
*/
|
|
23
|
+
export declare class MockRouteRepository implements RouteRepository {
|
|
24
|
+
private _currentRoute;
|
|
25
|
+
get currentRoute(): string;
|
|
26
|
+
change(route: string): void;
|
|
27
|
+
/**
|
|
28
|
+
* Set the current route directly (for testing).
|
|
29
|
+
*/
|
|
30
|
+
setRoute(route: string): void;
|
|
31
|
+
/**
|
|
32
|
+
* Get route change history.
|
|
33
|
+
*/
|
|
34
|
+
getRouteHistory(): string[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create a mock RouteRepository.
|
|
38
|
+
*/
|
|
39
|
+
export declare function createMockRouteRepository(): MockRouteRepository;
|
|
40
|
+
/**
|
|
41
|
+
* RouteManager tester utility.
|
|
42
|
+
*/
|
|
43
|
+
export declare class RouteManagerTester {
|
|
44
|
+
readonly routeManager: RouteManager;
|
|
45
|
+
private routeHistory;
|
|
46
|
+
constructor(routeManager: RouteManager);
|
|
47
|
+
/**
|
|
48
|
+
* Change route and track it.
|
|
49
|
+
*/
|
|
50
|
+
changeRoute(route: string): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Get the current route.
|
|
53
|
+
*/
|
|
54
|
+
getCurrentRoute(): string;
|
|
55
|
+
/**
|
|
56
|
+
* Get route change history.
|
|
57
|
+
*/
|
|
58
|
+
getRouteHistory(): string[];
|
|
59
|
+
/**
|
|
60
|
+
* Check if user is logged in (based on RouteManager auth options).
|
|
61
|
+
*/
|
|
62
|
+
checkForLoginRoute(): void;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Create a RouteManager tester instance.
|
|
66
|
+
*/
|
|
67
|
+
export declare function createRouteManagerTester(routeManager: RouteManager): RouteManagerTester;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test helpers for RouteManager and RouteRepository.
|
|
3
|
+
*
|
|
4
|
+
* Provides mock implementations and utilities for testing routing.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { createMockRouteRepository, createRouteManagerTester } from '@c-a-f/testing/core';
|
|
9
|
+
* import { RouteManager } from '@c-a-f/core';
|
|
10
|
+
*
|
|
11
|
+
* const mockRepo = createMockRouteRepository();
|
|
12
|
+
* const routeManager = new RouteManager(mockRepo);
|
|
13
|
+
* const tester = createRouteManagerTester(routeManager);
|
|
14
|
+
*
|
|
15
|
+
* await tester.changeRoute('/dashboard');
|
|
16
|
+
* expect(tester.getCurrentRoute()).toBe('/dashboard');
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Mock RouteRepository implementation for testing.
|
|
21
|
+
*/
|
|
22
|
+
export class MockRouteRepository {
|
|
23
|
+
_currentRoute = '/';
|
|
24
|
+
get currentRoute() {
|
|
25
|
+
return this._currentRoute;
|
|
26
|
+
}
|
|
27
|
+
change(route) {
|
|
28
|
+
this._currentRoute = route;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Set the current route directly (for testing).
|
|
32
|
+
*/
|
|
33
|
+
setRoute(route) {
|
|
34
|
+
this._currentRoute = route;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get route change history.
|
|
38
|
+
*/
|
|
39
|
+
getRouteHistory() {
|
|
40
|
+
return [this._currentRoute];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Create a mock RouteRepository.
|
|
45
|
+
*/
|
|
46
|
+
export function createMockRouteRepository() {
|
|
47
|
+
return new MockRouteRepository();
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* RouteManager tester utility.
|
|
51
|
+
*/
|
|
52
|
+
export class RouteManagerTester {
|
|
53
|
+
routeManager;
|
|
54
|
+
routeHistory = [];
|
|
55
|
+
constructor(routeManager) {
|
|
56
|
+
this.routeManager = routeManager;
|
|
57
|
+
// Track route changes if possible
|
|
58
|
+
const repo = routeManager.routeRepository;
|
|
59
|
+
if (repo instanceof MockRouteRepository) {
|
|
60
|
+
this.routeHistory.push(repo.currentRoute);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Change route and track it.
|
|
65
|
+
*/
|
|
66
|
+
async changeRoute(route) {
|
|
67
|
+
this.routeManager.changeRoute(route);
|
|
68
|
+
this.routeHistory.push(route);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get the current route.
|
|
72
|
+
*/
|
|
73
|
+
getCurrentRoute() {
|
|
74
|
+
return this.routeManager.routeRepository.currentRoute;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Get route change history.
|
|
78
|
+
*/
|
|
79
|
+
getRouteHistory() {
|
|
80
|
+
return [...this.routeHistory];
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Check if user is logged in (based on RouteManager auth options).
|
|
84
|
+
*/
|
|
85
|
+
checkForLoginRoute() {
|
|
86
|
+
this.routeManager.checkForLoginRoute();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Create a RouteManager tester instance.
|
|
91
|
+
*/
|
|
92
|
+
export function createRouteManagerTester(routeManager) {
|
|
93
|
+
return new RouteManagerTester(routeManager);
|
|
94
|
+
}
|