@directive-run/core 0.4.0 → 0.4.2

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.
@@ -12,8 +12,12 @@ import { p as ModulesMap, q as CreateSystemOptionsNamed, R as Requirement, N as
12
12
  */
13
13
 
14
14
  /**
15
- * Flush all pending microtasks.
16
- * Call this after advancing fake timers to ensure all Promise callbacks run.
15
+ * Flush all pending microtasks by awaiting multiple rounds of `Promise.resolve()`.
16
+ *
17
+ * Call this after advancing fake timers to ensure all Promise callbacks
18
+ * (including nested microtasks) have run before making assertions.
19
+ *
20
+ * @returns A promise that resolves after all pending microtasks have been drained.
17
21
  *
18
22
  * @example
19
23
  * ```typescript
@@ -24,15 +28,22 @@ import { p as ModulesMap, q as CreateSystemOptionsNamed, R as Requirement, N as
24
28
  * vi.advanceTimersByTime(100); // Advance resolver delay
25
29
  * await flushMicrotasks(); // Let resolver complete
26
30
  * ```
31
+ *
32
+ * @public
27
33
  */
28
34
  declare function flushMicrotasks(): Promise<void>;
29
35
  /**
30
36
  * Wait for the system to settle with fake timers enabled.
31
- * Combines timer advancement with microtask flushing.
32
37
  *
33
- * @param system - The Directive system
34
- * @param advanceTime - Function to advance fake timers (e.g., vi.advanceTimersByTime)
35
- * @param options - Configuration options
38
+ * Repeatedly advances fake timers in discrete steps while flushing microtasks,
39
+ * until no resolvers remain inflight or the time budget is exhausted.
40
+ *
41
+ * @param system - The Directive system to wait on (must expose {@link SystemInspection} via `inspect()`).
42
+ * @param advanceTime - Function that advances fake timers by a given number of milliseconds (e.g., `vi.advanceTimersByTime`).
43
+ * @param options - Configuration for total time budget, step size, and iteration limit.
44
+ * @returns A promise that resolves once the system is idle.
45
+ *
46
+ * @throws Error if the system does not settle within the configured time budget.
36
47
  *
37
48
  * @example
38
49
  * ```typescript
@@ -48,6 +59,8 @@ declare function flushMicrotasks(): Promise<void>;
48
59
  *
49
60
  * expect(system.facts.result).toBe("done");
50
61
  * ```
62
+ *
63
+ * @public
51
64
  */
52
65
  declare function settleWithFakeTimers(system: {
53
66
  inspect(): SystemInspection;
@@ -59,41 +72,77 @@ declare function settleWithFakeTimers(system: {
59
72
  /** Maximum iterations before giving up (default: 1000) */
60
73
  maxIterations?: number;
61
74
  }): Promise<void>;
75
+ /**
76
+ * Standalone fake timer controller for tests that do not use Vitest/Jest fake timers.
77
+ *
78
+ * @remarks
79
+ * For most tests, prefer Vitest's `vi.useFakeTimers()` paired with
80
+ * {@link settleWithFakeTimers} for better integration. Use this interface
81
+ * only when you need a lightweight, framework-independent timer mock.
82
+ *
83
+ * @public
84
+ */
62
85
  interface FakeTimers {
63
- /** Advance time by a number of milliseconds */
86
+ /** Advance time by a number of milliseconds, firing any timers that fall within the window. */
64
87
  advance(ms: number): Promise<void>;
65
- /** Advance to the next scheduled timer */
88
+ /** Advance to the next scheduled timer and fire its callback. */
66
89
  next(): Promise<void>;
67
- /** Run all pending timers */
90
+ /** Run all pending timers in chronological order. */
68
91
  runAll(): Promise<void>;
69
- /** Get current fake time */
92
+ /** Get the current fake time in milliseconds. */
70
93
  now(): number;
71
- /** Reset to time 0 */
94
+ /** Reset the clock to time 0 and discard all scheduled timers. */
72
95
  reset(): void;
73
96
  }
74
97
  /**
75
- * Create standalone fake timers for testing.
76
- * Note: For most tests, prefer using Vitest's vi.useFakeTimers() with
77
- * settleWithFakeTimers() for better integration.
98
+ * Create standalone fake timers for testing without a framework timer mock.
99
+ *
100
+ * @remarks
101
+ * For most tests, prefer Vitest's `vi.useFakeTimers()` paired with
102
+ * {@link settleWithFakeTimers}. This factory is useful when you need an
103
+ * isolated timer that does not interfere with global timer state.
104
+ *
105
+ * @returns A {@link FakeTimers} controller with `advance`, `next`, `runAll`, `now`, and `reset` methods.
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * const timers = createFakeTimers();
110
+ * // schedule work, then:
111
+ * await timers.advance(500);
112
+ * expect(timers.now()).toBe(500);
113
+ * ```
114
+ *
115
+ * @public
78
116
  */
79
117
  declare function createFakeTimers(): FakeTimers;
80
- /** Context passed to mock resolver resolve functions */
118
+ /**
119
+ * Context passed to mock resolver resolve functions.
120
+ *
121
+ * @public
122
+ */
81
123
  interface MockResolverContext {
82
124
  /** Facts object (use type assertion for specific facts) */
83
125
  facts: any;
84
126
  /** Abort signal for cancellation */
85
127
  signal: AbortSignal;
86
128
  }
129
+ /**
130
+ * Configuration for a simple mock resolver created via {@link createMockResolver}.
131
+ *
132
+ * @typeParam R - The requirement type this resolver handles.
133
+ *
134
+ * @public
135
+ */
87
136
  interface MockResolverOptions<R extends Requirement = Requirement> {
88
- /** Predicate to check if this resolver handles a requirement */
137
+ /** Predicate to check if this resolver handles a given requirement. */
89
138
  requirement?: (req: Requirement) => req is R;
90
- /** Mock implementation */
139
+ /** Mock implementation invoked when the resolver runs. */
91
140
  resolve?: (req: R, ctx: MockResolverContext) => void | Promise<void>;
92
- /** Delay before resolving (ms) */
141
+ /** Artificial delay in milliseconds before the resolver completes. */
93
142
  delay?: number;
94
- /** Simulate an error */
143
+ /** Error (or message string) to throw, simulating a resolver failure. */
95
144
  error?: Error | string;
96
- /** Track calls */
145
+ /** Array that receives every requirement passed to this resolver. */
97
146
  calls?: R[];
98
147
  }
99
148
  /** Internal resolver definition type for mock resolvers */
@@ -102,12 +151,32 @@ interface MockResolverDef {
102
151
  resolve: (req: Requirement, ctx: MockResolverContext) => Promise<void>;
103
152
  }
104
153
  /**
105
- * Create a mock resolver for testing.
154
+ * Create a simple mock resolver that matches requirements by type and optionally
155
+ * records calls, injects delays, or throws errors.
156
+ *
157
+ * @param typeOrOptions - A requirement type string, or a full {@link MockResolverOptions} object.
158
+ * @returns A resolver definition that can be spread into a module's `resolvers` map.
159
+ *
160
+ * @example
161
+ * ```typescript
162
+ * const calls: Requirement[] = [];
163
+ * const mock = createMockResolver({ requirement: (r): r is MyReq => r.type === "LOAD", calls });
164
+ * ```
165
+ *
166
+ * @public
106
167
  */
107
168
  declare function createMockResolver<R extends Requirement = Requirement>(typeOrOptions: string | MockResolverOptions<R>): MockResolverDef;
108
169
  /**
109
170
  * A mock resolver that captures requirements for manual resolution.
110
- * Use this when you need fine-grained control over when and how requirements resolve.
171
+ *
172
+ * @remarks
173
+ * Use this when you need fine-grained control over when and how requirements
174
+ * resolve. Requirements are queued in `pending` and stay unresolved until you
175
+ * explicitly call `resolve()` or `reject()`.
176
+ *
177
+ * @typeParam R - The requirement type this resolver handles.
178
+ *
179
+ * @public
111
180
  */
112
181
  interface MockResolver<R extends Requirement = Requirement> {
113
182
  /** All requirements received by this resolver */
@@ -130,8 +199,11 @@ interface MockResolver<R extends Requirement = Requirement> {
130
199
  reset(): void;
131
200
  }
132
201
  /**
133
- * Create a mock resolver that captures requirements instead of resolving them.
134
- * This gives you manual control over requirement resolution in tests.
202
+ * Create a mock resolver that captures requirements instead of resolving them,
203
+ * giving you manual control over when and how each requirement completes.
204
+ *
205
+ * @param _requirementType - The requirement `type` string this mock handles (used for documentation; matching is done by the test harness).
206
+ * @returns A {@link MockResolver} with a `handler` function suitable for passing to {@link createTestSystem} mocks.
135
207
  *
136
208
  * @example
137
209
  * ```typescript
@@ -159,12 +231,18 @@ interface MockResolver<R extends Requirement = Requirement> {
159
231
  *
160
232
  * expect(system.facts.user).toEqual({ name: "John" });
161
233
  * ```
234
+ *
235
+ * @public
162
236
  */
163
237
  declare function mockResolver<R extends Requirement = Requirement>(_requirementType: string): MockResolver<R> & {
164
238
  /** Handler that can be passed to createTestSystem mocks */
165
239
  handler: (req: Requirement, ctx: MockResolverContext) => Promise<void>;
166
240
  };
167
- /** Record of a single fact change */
241
+ /**
242
+ * Record of a single fact change captured by the test tracking plugin.
243
+ *
244
+ * @public
245
+ */
168
246
  interface FactChangeRecord {
169
247
  /** The fact key that changed (without namespace prefix for namespaced systems) */
170
248
  key: string;
@@ -179,6 +257,17 @@ interface FactChangeRecord {
179
257
  /** Timestamp of the change */
180
258
  timestamp: number;
181
259
  }
260
+ /**
261
+ * A Directive system augmented with testing utilities.
262
+ *
263
+ * @remarks
264
+ * Extends {@link NamespacedSystem} with event/resolver/fact tracking, idle
265
+ * waiting, and assertion helpers. Created via {@link createTestSystem}.
266
+ *
267
+ * @typeParam Modules - The modules map that defines the system's schema.
268
+ *
269
+ * @public
270
+ */
182
271
  interface TestSystem<Modules extends ModulesMap> extends NamespacedSystem<Modules> {
183
272
  /**
184
273
  * Wait for all pending operations to complete.
@@ -219,6 +308,14 @@ interface TestSystem<Modules extends ModulesMap> extends NamespacedSystem<Module
219
308
  */
220
309
  assertFactChanges(key: string, times: number): void;
221
310
  }
311
+ /**
312
+ * Options for {@link createTestSystem}, extending the standard system options
313
+ * with mock resolver injection and automatic tracking.
314
+ *
315
+ * @typeParam Modules - The modules map that defines the system's schema.
316
+ *
317
+ * @public
318
+ */
222
319
  interface CreateTestSystemOptions<Modules extends ModulesMap> extends Omit<CreateSystemOptionsNamed<Modules>, "plugins"> {
223
320
  /** Mock resolvers by type */
224
321
  mocks?: {
@@ -228,7 +325,26 @@ interface CreateTestSystemOptions<Modules extends ModulesMap> extends Omit<Creat
228
325
  plugins?: Array<any>;
229
326
  }
230
327
  /**
231
- * Create a test system with additional testing utilities.
328
+ * Create a Directive system instrumented for testing.
329
+ *
330
+ * Wraps {@link createSystem} with an automatic tracking plugin that records
331
+ * dispatched events, resolver calls, fact changes, and generated requirements.
332
+ * Mock resolvers can be injected via `options.mocks.resolvers` to replace
333
+ * real resolvers by requirement type.
334
+ *
335
+ * @param options - System configuration with optional mock resolvers and additional plugins.
336
+ * @returns A {@link TestSystem} with assertion helpers, idle waiting, and history tracking.
337
+ *
338
+ * @example
339
+ * ```typescript
340
+ * const system = createTestSystem({
341
+ * modules: { counter: counterModule },
342
+ * mocks: { resolvers: { INCREMENT: { resolve: (req, context) => { context.facts.count++; } } } },
343
+ * });
344
+ * system.start();
345
+ * ```
346
+ *
347
+ * @public
232
348
  */
233
349
  declare function createTestSystem<Modules extends ModulesMap>(options: CreateTestSystemOptions<Modules>): TestSystem<Modules>;
234
350
 
package/dist/testing.d.ts CHANGED
@@ -12,8 +12,12 @@ import { p as ModulesMap, q as CreateSystemOptionsNamed, R as Requirement, N as
12
12
  */
13
13
 
14
14
  /**
15
- * Flush all pending microtasks.
16
- * Call this after advancing fake timers to ensure all Promise callbacks run.
15
+ * Flush all pending microtasks by awaiting multiple rounds of `Promise.resolve()`.
16
+ *
17
+ * Call this after advancing fake timers to ensure all Promise callbacks
18
+ * (including nested microtasks) have run before making assertions.
19
+ *
20
+ * @returns A promise that resolves after all pending microtasks have been drained.
17
21
  *
18
22
  * @example
19
23
  * ```typescript
@@ -24,15 +28,22 @@ import { p as ModulesMap, q as CreateSystemOptionsNamed, R as Requirement, N as
24
28
  * vi.advanceTimersByTime(100); // Advance resolver delay
25
29
  * await flushMicrotasks(); // Let resolver complete
26
30
  * ```
31
+ *
32
+ * @public
27
33
  */
28
34
  declare function flushMicrotasks(): Promise<void>;
29
35
  /**
30
36
  * Wait for the system to settle with fake timers enabled.
31
- * Combines timer advancement with microtask flushing.
32
37
  *
33
- * @param system - The Directive system
34
- * @param advanceTime - Function to advance fake timers (e.g., vi.advanceTimersByTime)
35
- * @param options - Configuration options
38
+ * Repeatedly advances fake timers in discrete steps while flushing microtasks,
39
+ * until no resolvers remain inflight or the time budget is exhausted.
40
+ *
41
+ * @param system - The Directive system to wait on (must expose {@link SystemInspection} via `inspect()`).
42
+ * @param advanceTime - Function that advances fake timers by a given number of milliseconds (e.g., `vi.advanceTimersByTime`).
43
+ * @param options - Configuration for total time budget, step size, and iteration limit.
44
+ * @returns A promise that resolves once the system is idle.
45
+ *
46
+ * @throws Error if the system does not settle within the configured time budget.
36
47
  *
37
48
  * @example
38
49
  * ```typescript
@@ -48,6 +59,8 @@ declare function flushMicrotasks(): Promise<void>;
48
59
  *
49
60
  * expect(system.facts.result).toBe("done");
50
61
  * ```
62
+ *
63
+ * @public
51
64
  */
52
65
  declare function settleWithFakeTimers(system: {
53
66
  inspect(): SystemInspection;
@@ -59,41 +72,77 @@ declare function settleWithFakeTimers(system: {
59
72
  /** Maximum iterations before giving up (default: 1000) */
60
73
  maxIterations?: number;
61
74
  }): Promise<void>;
75
+ /**
76
+ * Standalone fake timer controller for tests that do not use Vitest/Jest fake timers.
77
+ *
78
+ * @remarks
79
+ * For most tests, prefer Vitest's `vi.useFakeTimers()` paired with
80
+ * {@link settleWithFakeTimers} for better integration. Use this interface
81
+ * only when you need a lightweight, framework-independent timer mock.
82
+ *
83
+ * @public
84
+ */
62
85
  interface FakeTimers {
63
- /** Advance time by a number of milliseconds */
86
+ /** Advance time by a number of milliseconds, firing any timers that fall within the window. */
64
87
  advance(ms: number): Promise<void>;
65
- /** Advance to the next scheduled timer */
88
+ /** Advance to the next scheduled timer and fire its callback. */
66
89
  next(): Promise<void>;
67
- /** Run all pending timers */
90
+ /** Run all pending timers in chronological order. */
68
91
  runAll(): Promise<void>;
69
- /** Get current fake time */
92
+ /** Get the current fake time in milliseconds. */
70
93
  now(): number;
71
- /** Reset to time 0 */
94
+ /** Reset the clock to time 0 and discard all scheduled timers. */
72
95
  reset(): void;
73
96
  }
74
97
  /**
75
- * Create standalone fake timers for testing.
76
- * Note: For most tests, prefer using Vitest's vi.useFakeTimers() with
77
- * settleWithFakeTimers() for better integration.
98
+ * Create standalone fake timers for testing without a framework timer mock.
99
+ *
100
+ * @remarks
101
+ * For most tests, prefer Vitest's `vi.useFakeTimers()` paired with
102
+ * {@link settleWithFakeTimers}. This factory is useful when you need an
103
+ * isolated timer that does not interfere with global timer state.
104
+ *
105
+ * @returns A {@link FakeTimers} controller with `advance`, `next`, `runAll`, `now`, and `reset` methods.
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * const timers = createFakeTimers();
110
+ * // schedule work, then:
111
+ * await timers.advance(500);
112
+ * expect(timers.now()).toBe(500);
113
+ * ```
114
+ *
115
+ * @public
78
116
  */
79
117
  declare function createFakeTimers(): FakeTimers;
80
- /** Context passed to mock resolver resolve functions */
118
+ /**
119
+ * Context passed to mock resolver resolve functions.
120
+ *
121
+ * @public
122
+ */
81
123
  interface MockResolverContext {
82
124
  /** Facts object (use type assertion for specific facts) */
83
125
  facts: any;
84
126
  /** Abort signal for cancellation */
85
127
  signal: AbortSignal;
86
128
  }
129
+ /**
130
+ * Configuration for a simple mock resolver created via {@link createMockResolver}.
131
+ *
132
+ * @typeParam R - The requirement type this resolver handles.
133
+ *
134
+ * @public
135
+ */
87
136
  interface MockResolverOptions<R extends Requirement = Requirement> {
88
- /** Predicate to check if this resolver handles a requirement */
137
+ /** Predicate to check if this resolver handles a given requirement. */
89
138
  requirement?: (req: Requirement) => req is R;
90
- /** Mock implementation */
139
+ /** Mock implementation invoked when the resolver runs. */
91
140
  resolve?: (req: R, ctx: MockResolverContext) => void | Promise<void>;
92
- /** Delay before resolving (ms) */
141
+ /** Artificial delay in milliseconds before the resolver completes. */
93
142
  delay?: number;
94
- /** Simulate an error */
143
+ /** Error (or message string) to throw, simulating a resolver failure. */
95
144
  error?: Error | string;
96
- /** Track calls */
145
+ /** Array that receives every requirement passed to this resolver. */
97
146
  calls?: R[];
98
147
  }
99
148
  /** Internal resolver definition type for mock resolvers */
@@ -102,12 +151,32 @@ interface MockResolverDef {
102
151
  resolve: (req: Requirement, ctx: MockResolverContext) => Promise<void>;
103
152
  }
104
153
  /**
105
- * Create a mock resolver for testing.
154
+ * Create a simple mock resolver that matches requirements by type and optionally
155
+ * records calls, injects delays, or throws errors.
156
+ *
157
+ * @param typeOrOptions - A requirement type string, or a full {@link MockResolverOptions} object.
158
+ * @returns A resolver definition that can be spread into a module's `resolvers` map.
159
+ *
160
+ * @example
161
+ * ```typescript
162
+ * const calls: Requirement[] = [];
163
+ * const mock = createMockResolver({ requirement: (r): r is MyReq => r.type === "LOAD", calls });
164
+ * ```
165
+ *
166
+ * @public
106
167
  */
107
168
  declare function createMockResolver<R extends Requirement = Requirement>(typeOrOptions: string | MockResolverOptions<R>): MockResolverDef;
108
169
  /**
109
170
  * A mock resolver that captures requirements for manual resolution.
110
- * Use this when you need fine-grained control over when and how requirements resolve.
171
+ *
172
+ * @remarks
173
+ * Use this when you need fine-grained control over when and how requirements
174
+ * resolve. Requirements are queued in `pending` and stay unresolved until you
175
+ * explicitly call `resolve()` or `reject()`.
176
+ *
177
+ * @typeParam R - The requirement type this resolver handles.
178
+ *
179
+ * @public
111
180
  */
112
181
  interface MockResolver<R extends Requirement = Requirement> {
113
182
  /** All requirements received by this resolver */
@@ -130,8 +199,11 @@ interface MockResolver<R extends Requirement = Requirement> {
130
199
  reset(): void;
131
200
  }
132
201
  /**
133
- * Create a mock resolver that captures requirements instead of resolving them.
134
- * This gives you manual control over requirement resolution in tests.
202
+ * Create a mock resolver that captures requirements instead of resolving them,
203
+ * giving you manual control over when and how each requirement completes.
204
+ *
205
+ * @param _requirementType - The requirement `type` string this mock handles (used for documentation; matching is done by the test harness).
206
+ * @returns A {@link MockResolver} with a `handler` function suitable for passing to {@link createTestSystem} mocks.
135
207
  *
136
208
  * @example
137
209
  * ```typescript
@@ -159,12 +231,18 @@ interface MockResolver<R extends Requirement = Requirement> {
159
231
  *
160
232
  * expect(system.facts.user).toEqual({ name: "John" });
161
233
  * ```
234
+ *
235
+ * @public
162
236
  */
163
237
  declare function mockResolver<R extends Requirement = Requirement>(_requirementType: string): MockResolver<R> & {
164
238
  /** Handler that can be passed to createTestSystem mocks */
165
239
  handler: (req: Requirement, ctx: MockResolverContext) => Promise<void>;
166
240
  };
167
- /** Record of a single fact change */
241
+ /**
242
+ * Record of a single fact change captured by the test tracking plugin.
243
+ *
244
+ * @public
245
+ */
168
246
  interface FactChangeRecord {
169
247
  /** The fact key that changed (without namespace prefix for namespaced systems) */
170
248
  key: string;
@@ -179,6 +257,17 @@ interface FactChangeRecord {
179
257
  /** Timestamp of the change */
180
258
  timestamp: number;
181
259
  }
260
+ /**
261
+ * A Directive system augmented with testing utilities.
262
+ *
263
+ * @remarks
264
+ * Extends {@link NamespacedSystem} with event/resolver/fact tracking, idle
265
+ * waiting, and assertion helpers. Created via {@link createTestSystem}.
266
+ *
267
+ * @typeParam Modules - The modules map that defines the system's schema.
268
+ *
269
+ * @public
270
+ */
182
271
  interface TestSystem<Modules extends ModulesMap> extends NamespacedSystem<Modules> {
183
272
  /**
184
273
  * Wait for all pending operations to complete.
@@ -219,6 +308,14 @@ interface TestSystem<Modules extends ModulesMap> extends NamespacedSystem<Module
219
308
  */
220
309
  assertFactChanges(key: string, times: number): void;
221
310
  }
311
+ /**
312
+ * Options for {@link createTestSystem}, extending the standard system options
313
+ * with mock resolver injection and automatic tracking.
314
+ *
315
+ * @typeParam Modules - The modules map that defines the system's schema.
316
+ *
317
+ * @public
318
+ */
222
319
  interface CreateTestSystemOptions<Modules extends ModulesMap> extends Omit<CreateSystemOptionsNamed<Modules>, "plugins"> {
223
320
  /** Mock resolvers by type */
224
321
  mocks?: {
@@ -228,7 +325,26 @@ interface CreateTestSystemOptions<Modules extends ModulesMap> extends Omit<Creat
228
325
  plugins?: Array<any>;
229
326
  }
230
327
  /**
231
- * Create a test system with additional testing utilities.
328
+ * Create a Directive system instrumented for testing.
329
+ *
330
+ * Wraps {@link createSystem} with an automatic tracking plugin that records
331
+ * dispatched events, resolver calls, fact changes, and generated requirements.
332
+ * Mock resolvers can be injected via `options.mocks.resolvers` to replace
333
+ * real resolvers by requirement type.
334
+ *
335
+ * @param options - System configuration with optional mock resolvers and additional plugins.
336
+ * @returns A {@link TestSystem} with assertion helpers, idle waiting, and history tracking.
337
+ *
338
+ * @example
339
+ * ```typescript
340
+ * const system = createTestSystem({
341
+ * modules: { counter: counterModule },
342
+ * mocks: { resolvers: { INCREMENT: { resolve: (req, context) => { context.facts.count++; } } } },
343
+ * });
344
+ * system.start();
345
+ * ```
346
+ *
347
+ * @public
232
348
  */
233
349
  declare function createTestSystem<Modules extends ModulesMap>(options: CreateTestSystemOptions<Modules>): TestSystem<Modules>;
234
350