@kronos-ts/test 0.1.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.
@@ -0,0 +1,78 @@
1
+ import { type Metadata } from "@kronos-ts/common";
2
+ import type { CommandDescriptor, EventDescriptor, EventMessage, CommandMessage } from "@kronos-ts/messaging";
3
+ import { type App, type RunningApp } from "@kronos-ts/app";
4
+ import type { z } from "zod";
5
+ type EventPair = [EventDescriptor<any>, unknown];
6
+ type CommandPair = [CommandDescriptor<any>, unknown];
7
+ /**
8
+ * Creates a BDD test fixture that runs your REAL application code
9
+ * against an in-memory event store with recording decorators.
10
+ *
11
+ * Pass a configuration function that sets up the same domain
12
+ * as your production app via the kronos() App fluent surface.
13
+ *
14
+ * ```typescript
15
+ * const fixture = await createTestFixture((app) => {
16
+ * app.states(Course)
17
+ * app.commands(createCourse, subscribeStudent)
18
+ * app.queries(getCourseView, getAllCourses)
19
+ * })
20
+ *
21
+ * await fixture
22
+ * .given()
23
+ * .events([CourseCreated, { courseId: "cs-101", name: "Intro", capacity: 30 }])
24
+ * .when()
25
+ * .command(SubscribeStudent, { courseId: "cs-101", studentId: "stu-001" })
26
+ * .then()
27
+ * .expectSuccess()
28
+ * .expectEvents([StudentSubscribed, { courseId: "cs-101", studentId: "stu-001" }])
29
+ *
30
+ * await fixture.stop()
31
+ * ```
32
+ */
33
+ export declare function createTestFixture(configureFn: (app: App) => void): Promise<TestFixture>;
34
+ export interface TestFixture {
35
+ given(): GivenPhase;
36
+ stop(): Promise<void>;
37
+ }
38
+ export interface GivenPhase {
39
+ events(...pairs: EventPair[]): GivenPhase;
40
+ commands(...pairs: CommandPair[]): GivenPhase;
41
+ execute(fn: (app: RunningApp) => void | Promise<void>): GivenPhase;
42
+ noPriorActivity(): GivenPhase;
43
+ when(): WhenPhase;
44
+ }
45
+ export interface WhenPhase {
46
+ command<P extends z.ZodType>(descriptor: CommandDescriptor<P>, payload: z.infer<P>, metadata?: Metadata): WhenResult;
47
+ event<P extends z.ZodType>(descriptor: EventDescriptor<P>, payload: z.infer<P>, metadata?: Metadata): WhenResult;
48
+ nothing(): WhenResult;
49
+ }
50
+ export interface WhenResult {
51
+ then(): ThenPhase;
52
+ }
53
+ export interface ThenPhase extends PromiseLike<void> {
54
+ expectEvents(...pairs: EventPair[]): ThenPhase;
55
+ expectNoEvents(): ThenPhase;
56
+ expectSuccess(): ThenPhase;
57
+ expectResult(expected: unknown): ThenPhase;
58
+ expectResultSatisfying(fn: (result: unknown) => void): ThenPhase;
59
+ expectResultPayloadSatisfying<T>(fn: (payload: T) => void): ThenPhase;
60
+ expectException(messageSubstring: string): ThenPhase;
61
+ expectExceptionType(errorName: string): ThenPhase;
62
+ expectExceptionSatisfying(fn: (error: unknown) => void): ThenPhase;
63
+ expectEventsSatisfying(fn: (events: ReadonlyArray<EventMessage>) => void): ThenPhase;
64
+ expectCommands(...pairs: CommandPair[]): ThenPhase;
65
+ expectNoCommands(): ThenPhase;
66
+ expectCommandsSatisfying(fn: (commands: ReadonlyArray<CommandMessage>) => void): ThenPhase;
67
+ expect(fn: (app: RunningApp) => void | Promise<void>): ThenPhase;
68
+ await(assertion: (app: RunningApp) => void | Promise<void>, timeoutMs?: number, intervalMs?: number): ThenPhase;
69
+ and(): TestFixture;
70
+ }
71
+ export declare class FixtureAssertionError extends Error {
72
+ constructor(message: string);
73
+ }
74
+ export type FieldFilter = (fieldName: string, owner: unknown) => boolean;
75
+ export declare const allFieldsFilter: FieldFilter;
76
+ export declare function ignoreFields(...fieldNames: string[]): FieldFilter;
77
+ export {};
78
+ //# sourceMappingURL=fixture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixture.d.ts","sourceRoot":"","sources":["../src/fixture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,424 @@
1
+ import { generateIdentifier, emptyMetadata, qualifiedNameToString, } from "@kronos-ts/common";
2
+ import { runInNewUoW } from "@kronos-ts/messaging";
3
+ import { kronos } from "@kronos-ts/app";
4
+ import { createRecordings, testRecordingExtension, } from "./recording-enhancer.js";
5
+ // ---------------------------------------------------------------------------
6
+ // Fixture entry point
7
+ // ---------------------------------------------------------------------------
8
+ /**
9
+ * Creates a BDD test fixture that runs your REAL application code
10
+ * against an in-memory event store with recording decorators.
11
+ *
12
+ * Pass a configuration function that sets up the same domain
13
+ * as your production app via the kronos() App fluent surface.
14
+ *
15
+ * ```typescript
16
+ * const fixture = await createTestFixture((app) => {
17
+ * app.states(Course)
18
+ * app.commands(createCourse, subscribeStudent)
19
+ * app.queries(getCourseView, getAllCourses)
20
+ * })
21
+ *
22
+ * await fixture
23
+ * .given()
24
+ * .events([CourseCreated, { courseId: "cs-101", name: "Intro", capacity: 30 }])
25
+ * .when()
26
+ * .command(SubscribeStudent, { courseId: "cs-101", studentId: "stu-001" })
27
+ * .then()
28
+ * .expectSuccess()
29
+ * .expectEvents([StudentSubscribed, { courseId: "cs-101", studentId: "stu-001" }])
30
+ *
31
+ * await fixture.stop()
32
+ * ```
33
+ */
34
+ export async function createTestFixture(configureFn) {
35
+ const recordings = createRecordings();
36
+ const app = kronos({ quiet: true });
37
+ // Apply testRecordingExtension synchronously BEFORE configureFn so its
38
+ // decorators land FIRST in the registration order — Phase 6 D-62: first
39
+ // registered = innermost wrap. Recording must be innermost so it captures
40
+ // messages AFTER all interceptors have enriched them.
41
+ testRecordingExtension(recordings)(app);
42
+ // Capture the eventStore reference via an identity decorator so the BDD
43
+ // given/when paths can append events directly. The decorator runs as
44
+ // part of the user-decorator pass at .start(), so it sees whatever
45
+ // (recording-wrapped) store the framework resolved.
46
+ let capturedEventStore;
47
+ app.decorate("eventStore", (inner) => {
48
+ capturedEventStore = inner;
49
+ return inner;
50
+ });
51
+ configureFn(app);
52
+ const running = await app.start();
53
+ if (!capturedEventStore) {
54
+ throw new Error("Test fixture: eventStore capture failed (start() did not run probe decorator).");
55
+ }
56
+ const eventStore = capturedEventStore;
57
+ return {
58
+ given() {
59
+ return new GivenPhaseImpl(running, recordings, eventStore);
60
+ },
61
+ async stop() {
62
+ await running.stop();
63
+ },
64
+ };
65
+ }
66
+ class GivenPhaseImpl {
67
+ app;
68
+ recordings;
69
+ eventStore;
70
+ givenEvents = [];
71
+ givenCommands = [];
72
+ givenSetupFns = [];
73
+ _prerequisite;
74
+ constructor(app, recordings, eventStore) {
75
+ this.app = app;
76
+ this.recordings = recordings;
77
+ this.eventStore = eventStore;
78
+ }
79
+ events(...pairs) {
80
+ this.givenEvents.push(...pairs);
81
+ return this;
82
+ }
83
+ commands(...pairs) {
84
+ this.givenCommands.push(...pairs);
85
+ return this;
86
+ }
87
+ execute(fn) {
88
+ this.givenSetupFns.push(fn);
89
+ return this;
90
+ }
91
+ noPriorActivity() {
92
+ return this;
93
+ }
94
+ when() {
95
+ return new WhenPhaseImpl(this.app, this.recordings, this.eventStore, this.givenEvents, this.givenCommands, this.givenSetupFns, this._prerequisite);
96
+ }
97
+ }
98
+ class WhenPhaseImpl {
99
+ app;
100
+ recordings;
101
+ eventStore;
102
+ givenEvents;
103
+ givenCommands;
104
+ givenSetupFns;
105
+ prerequisite;
106
+ constructor(app, recordings, eventStore, givenEvents, givenCommands, givenSetupFns, prerequisite) {
107
+ this.app = app;
108
+ this.recordings = recordings;
109
+ this.eventStore = eventStore;
110
+ this.givenEvents = givenEvents;
111
+ this.givenCommands = givenCommands;
112
+ this.givenSetupFns = givenSetupFns;
113
+ this.prerequisite = prerequisite;
114
+ }
115
+ command(descriptor, payload, metadata) {
116
+ const thenPhase = new ThenPhaseImpl(this.app, this.recordings, this.eventStore, this.givenEvents, this.givenCommands, this.givenSetupFns, { kind: "command", descriptor, payload, metadata }, this.prerequisite);
117
+ return { then: () => thenPhase };
118
+ }
119
+ event(descriptor, payload, metadata) {
120
+ const thenPhase = new ThenPhaseImpl(this.app, this.recordings, this.eventStore, this.givenEvents, this.givenCommands, this.givenSetupFns, { kind: "event", descriptor, payload, metadata }, this.prerequisite);
121
+ return { then: () => thenPhase };
122
+ }
123
+ nothing() {
124
+ const thenPhase = new ThenPhaseImpl(this.app, this.recordings, this.eventStore, this.givenEvents, this.givenCommands, this.givenSetupFns, { kind: "nothing" }, this.prerequisite);
125
+ return { then: () => thenPhase };
126
+ }
127
+ }
128
+ class ThenPhaseImpl {
129
+ app;
130
+ recordings;
131
+ eventStore;
132
+ givenEvents;
133
+ givenCommands;
134
+ givenSetupFns;
135
+ whenAction;
136
+ prerequisite;
137
+ assertions = [];
138
+ executionPromise = null;
139
+ constructor(app, recordings, eventStore, givenEvents, givenCommands, givenSetupFns, whenAction, prerequisite) {
140
+ this.app = app;
141
+ this.recordings = recordings;
142
+ this.eventStore = eventStore;
143
+ this.givenEvents = givenEvents;
144
+ this.givenCommands = givenCommands;
145
+ this.givenSetupFns = givenSetupFns;
146
+ this.whenAction = whenAction;
147
+ this.prerequisite = prerequisite;
148
+ }
149
+ expectEvents(...pairs) {
150
+ this.assertions.push((_result, _error, events) => {
151
+ if (events.length !== pairs.length) {
152
+ throw new FixtureAssertionError(`Expected ${pairs.length} event(s) but got ${events.length}.\n` +
153
+ ` Expected: [${pairs.map(([d]) => qualifiedNameToString(d.name)).join(", ")}]\n` +
154
+ ` Actual: [${events.map((e) => qualifiedNameToString(e.name)).join(", ")}]`);
155
+ }
156
+ for (let i = 0; i < pairs.length; i++) {
157
+ const [desc, payload] = pairs[i];
158
+ const actual = events[i];
159
+ const expectedName = qualifiedNameToString(desc.name);
160
+ const actualName = qualifiedNameToString(actual.name);
161
+ if (actualName !== expectedName) {
162
+ throw new FixtureAssertionError(`Event ${i}: expected "${expectedName}" but got "${actualName}"`);
163
+ }
164
+ assertDeepEqual(payload, actual.payload, `Event ${i} (${expectedName}) payload`);
165
+ }
166
+ });
167
+ return this;
168
+ }
169
+ expectNoEvents() {
170
+ this.assertions.push((_result, _error, events) => {
171
+ if (events.length !== 0) {
172
+ throw new FixtureAssertionError(`Expected no events but got ${events.length}: ` + events.map((e) => qualifiedNameToString(e.name)).join(", "));
173
+ }
174
+ });
175
+ return this;
176
+ }
177
+ expectSuccess() {
178
+ this.assertions.push((_result, error) => {
179
+ if (error)
180
+ throw new FixtureAssertionError(`Expected success but command failed: ${error instanceof Error ? error.message : String(error)}`);
181
+ });
182
+ return this;
183
+ }
184
+ expectResult(expected) {
185
+ this.assertions.push((result, error) => {
186
+ if (error)
187
+ throw new FixtureAssertionError(`Expected result but command failed: ${error}`);
188
+ assertDeepEqual(expected, result, "Command result");
189
+ });
190
+ return this;
191
+ }
192
+ expectResultSatisfying(fn) {
193
+ this.assertions.push((result, error) => {
194
+ if (error)
195
+ throw new FixtureAssertionError(`Expected result but command failed: ${error}`);
196
+ fn(result);
197
+ });
198
+ return this;
199
+ }
200
+ expectResultPayloadSatisfying(fn) {
201
+ this.assertions.push((result, error) => {
202
+ if (error)
203
+ throw new FixtureAssertionError(`Expected result but command failed: ${error}`);
204
+ fn(result);
205
+ });
206
+ return this;
207
+ }
208
+ expectException(messageSubstring) {
209
+ this.assertions.push((_result, error) => {
210
+ if (!error)
211
+ throw new FixtureAssertionError(`Expected exception containing "${messageSubstring}" but command succeeded`);
212
+ const msg = error instanceof Error ? error.message : String(error);
213
+ if (!msg.includes(messageSubstring)) {
214
+ throw new FixtureAssertionError(`Expected exception containing "${messageSubstring}" but got: "${msg}"`);
215
+ }
216
+ });
217
+ return this;
218
+ }
219
+ expectExceptionType(errorName) {
220
+ this.assertions.push((_result, error) => {
221
+ if (!error)
222
+ throw new FixtureAssertionError(`Expected ${errorName} but command succeeded`);
223
+ const actualName = error instanceof Error ? error.name : "Error";
224
+ if (actualName !== errorName) {
225
+ throw new FixtureAssertionError(`Expected ${errorName} but got ${actualName}: ${error instanceof Error ? error.message : error}`);
226
+ }
227
+ });
228
+ return this;
229
+ }
230
+ expectExceptionSatisfying(fn) {
231
+ this.assertions.push((_result, error) => {
232
+ if (!error)
233
+ throw new FixtureAssertionError("Expected exception but command succeeded");
234
+ fn(error);
235
+ });
236
+ return this;
237
+ }
238
+ expectEventsSatisfying(fn) {
239
+ this.assertions.push((_result, _error, events) => { fn(events); });
240
+ return this;
241
+ }
242
+ expectCommands(...pairs) {
243
+ this.assertions.push(() => {
244
+ const actual = this.recordings.commands();
245
+ const handlerCommands = actual.slice(1);
246
+ if (handlerCommands.length !== pairs.length) {
247
+ throw new FixtureAssertionError(`Expected ${pairs.length} dispatched command(s) but got ${handlerCommands.length}.`);
248
+ }
249
+ for (let i = 0; i < pairs.length; i++) {
250
+ const [desc, payload] = pairs[i];
251
+ const actualCmd = handlerCommands[i];
252
+ const expectedName = qualifiedNameToString(desc.name);
253
+ const actualName = qualifiedNameToString(actualCmd.name);
254
+ if (actualName !== expectedName)
255
+ throw new FixtureAssertionError(`Command ${i}: expected "${expectedName}" but got "${actualName}"`);
256
+ assertDeepEqual(payload, actualCmd.payload, `Command ${i} (${expectedName}) payload`);
257
+ }
258
+ });
259
+ return this;
260
+ }
261
+ expectNoCommands() {
262
+ this.assertions.push(() => {
263
+ const handlerCommands = this.recordings.commands().slice(1);
264
+ if (handlerCommands.length !== 0) {
265
+ throw new FixtureAssertionError(`Expected no dispatched commands but got ${handlerCommands.length}`);
266
+ }
267
+ });
268
+ return this;
269
+ }
270
+ expectCommandsSatisfying(fn) {
271
+ this.assertions.push(() => { fn(this.recordings.commands().slice(1)); });
272
+ return this;
273
+ }
274
+ expect(fn) {
275
+ this.assertions.push(async () => { await fn(this.app); });
276
+ return this;
277
+ }
278
+ await(assertion, timeoutMs = 5000, intervalMs = 50) {
279
+ this.assertions.push(async () => {
280
+ const start = Date.now();
281
+ let lastError;
282
+ while (Date.now() - start < timeoutMs) {
283
+ try {
284
+ await assertion(this.app);
285
+ return;
286
+ }
287
+ catch (err) {
288
+ lastError = err;
289
+ await new Promise((r) => setTimeout(r, intervalMs));
290
+ }
291
+ }
292
+ throw new FixtureAssertionError(`Assertion did not pass within ${timeoutMs}ms. Last error: ${lastError instanceof Error ? lastError.message : String(lastError)}`);
293
+ });
294
+ return this;
295
+ }
296
+ and() {
297
+ const prerequisite = this.getExecutionPromise();
298
+ return {
299
+ given: () => {
300
+ const given = new GivenPhaseImpl(this.app, this.recordings, this.eventStore);
301
+ given._prerequisite = prerequisite;
302
+ return given;
303
+ },
304
+ stop: async () => { await this.app.stop(); },
305
+ };
306
+ }
307
+ then(onfulfilled, onrejected) {
308
+ return this.getExecutionPromise().then(onfulfilled, onrejected);
309
+ }
310
+ getExecutionPromise() {
311
+ if (!this.executionPromise)
312
+ this.executionPromise = this.execute();
313
+ return this.executionPromise;
314
+ }
315
+ async execute() {
316
+ if (this.prerequisite)
317
+ await this.prerequisite;
318
+ const eventStore = this.eventStore;
319
+ // 1. Given: publish events within a UnitOfWork
320
+ if (this.givenEvents.length > 0) {
321
+ await runInNewUoW(emptyMetadata(), async () => {
322
+ const events = this.givenEvents.map(([desc, payload]) => {
323
+ const tags = desc.tags ? desc.tags(payload) : [];
324
+ return { identifier: generateIdentifier(), name: desc.name, version: desc.version, payload, metadata: emptyMetadata(), timestamp: Date.now(), tags };
325
+ });
326
+ await eventStore.append(events);
327
+ });
328
+ }
329
+ // 1b. Given: run custom setup
330
+ for (const fn of this.givenSetupFns) {
331
+ await fn(this.app);
332
+ }
333
+ // 1c. Given: dispatch commands via the gateway (matches user-facing semantics).
334
+ // The recording decorator on the bus captures messages whether they
335
+ // arrive via gateway or direct bus dispatch.
336
+ for (const [desc, payload] of this.givenCommands) {
337
+ await this.app.commandGateway.send(desc, payload, emptyMetadata());
338
+ }
339
+ // 2. Reset recordings
340
+ this.recordings.reset();
341
+ // 3. When
342
+ let result;
343
+ let error;
344
+ if (this.whenAction.kind === "command") {
345
+ try {
346
+ result = await this.app.commandGateway.send(this.whenAction.descriptor, this.whenAction.payload, this.whenAction.metadata ?? emptyMetadata());
347
+ }
348
+ catch (err) {
349
+ error = err;
350
+ }
351
+ }
352
+ else if (this.whenAction.kind === "event") {
353
+ const desc = this.whenAction.descriptor;
354
+ const payload = this.whenAction.payload;
355
+ const tags = desc.tags ? desc.tags(payload) : [];
356
+ try {
357
+ await eventStore.append([{ identifier: generateIdentifier(), name: desc.name, version: desc.version, payload, metadata: this.whenAction.metadata ?? emptyMetadata(), timestamp: Date.now(), tags }]);
358
+ }
359
+ catch (err) {
360
+ error = err;
361
+ }
362
+ }
363
+ // 4. Then
364
+ const recordedEvents = this.recordings.events();
365
+ for (const assertion of this.assertions) {
366
+ await assertion(result, error, recordedEvents);
367
+ }
368
+ }
369
+ }
370
+ // ---------------------------------------------------------------------------
371
+ // Helpers
372
+ // ---------------------------------------------------------------------------
373
+ export class FixtureAssertionError extends Error {
374
+ constructor(message) { super(message); this.name = "FixtureAssertionError"; }
375
+ }
376
+ export const allFieldsFilter = () => true;
377
+ export function ignoreFields(...fieldNames) {
378
+ const ignored = new Set(fieldNames);
379
+ return (name) => !ignored.has(name);
380
+ }
381
+ function assertDeepEqual(expected, actual, label, fieldFilter = allFieldsFilter) {
382
+ const differences = deepCompare(expected, actual, "", fieldFilter);
383
+ if (differences.length > 0)
384
+ throw new FixtureAssertionError(`${label} mismatch:\n${differences.map((d) => ` ${d}`).join("\n")}`);
385
+ }
386
+ function deepCompare(expected, actual, path, fieldFilter) {
387
+ if (expected === actual)
388
+ return [];
389
+ if (expected === null || actual === null)
390
+ return [`${path || "root"}: expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`];
391
+ if (typeof expected !== typeof actual)
392
+ return [`${path || "root"}: expected type ${typeof expected}, got type ${typeof actual}`];
393
+ if (typeof expected !== "object")
394
+ return [`${path || "root"}: expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`];
395
+ if (Array.isArray(expected) !== Array.isArray(actual))
396
+ return [`${path || "root"}: expected ${Array.isArray(expected) ? "array" : "object"}, got ${Array.isArray(actual) ? "array" : "object"}`];
397
+ if (Array.isArray(expected) && Array.isArray(actual)) {
398
+ const diffs = [];
399
+ for (let i = 0; i < Math.max(expected.length, actual.length); i++) {
400
+ if (i >= expected.length)
401
+ diffs.push(`${path}[${i}]: unexpected extra element`);
402
+ else if (i >= actual.length)
403
+ diffs.push(`${path}[${i}]: missing expected element`);
404
+ else
405
+ diffs.push(...deepCompare(expected[i], actual[i], `${path}[${i}]`, fieldFilter));
406
+ }
407
+ return diffs;
408
+ }
409
+ const diffs = [];
410
+ const allKeys = new Set([...Object.keys(expected), ...Object.keys(actual)]);
411
+ for (const key of allKeys) {
412
+ if (!fieldFilter(key, expected))
413
+ continue;
414
+ const fieldPath = path ? `${path}.${key}` : key;
415
+ if (!(key in expected))
416
+ diffs.push(`${fieldPath}: unexpected field`);
417
+ else if (!(key in actual))
418
+ diffs.push(`${fieldPath}: missing expected value`);
419
+ else
420
+ diffs.push(...deepCompare(expected[key], actual[key], fieldPath, fieldFilter));
421
+ }
422
+ return diffs;
423
+ }
424
+ //# sourceMappingURL=fixture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixture.js","sourceRoot":"","sources":["../src/fixture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { type TestFixture, type GivenPhase, type WhenPhase, type WhenResult, type ThenPhase, type FieldFilter, allFieldsFilter, ignoreFields, createTestFixture, FixtureAssertionError, } from "./fixture.js";
2
+ export { type Recordings, createRecordings, testRecordingExtension, } from "./recording-enhancer.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,eAAe,EACf,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,cAAc,CAAA;AAErB,OAAO,EACL,KAAK,UAAU,EACf,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,yBAAyB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { allFieldsFilter, ignoreFields, createTestFixture, FixtureAssertionError, } from "./fixture.js";
2
+ export { createRecordings, testRecordingExtension, } from "./recording-enhancer.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,eAAe,EACf,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,cAAc,CAAA;AAErB,OAAO,EAEL,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,yBAAyB,CAAA"}
@@ -0,0 +1,40 @@
1
+ import type { Extension } from "@kronos-ts/app";
2
+ import type { CommandMessage, EventMessage } from "@kronos-ts/messaging";
3
+ /**
4
+ * Recorded state from the test fixture.
5
+ * Events and commands are captured by decorators installed at the
6
+ * INNERMOST position (after all interceptors have run).
7
+ */
8
+ export interface Recordings {
9
+ /** Events recorded since the last reset. */
10
+ events(): ReadonlyArray<EventMessage>;
11
+ /** Commands dispatched since the last reset. */
12
+ commands(): ReadonlyArray<CommandMessage>;
13
+ /** Clear all recordings. Called between Given and When phases. */
14
+ reset(): void;
15
+ }
16
+ /**
17
+ * Create a fresh Recordings handle. Pass it into {@link testRecordingExtension}
18
+ * so the fixture and the decorators share the same backing arrays.
19
+ *
20
+ * Replaces the legacy "register testRecordings as a component, retrieve via
21
+ * configuration.getComponent" pattern (removed in Phase 8).
22
+ */
23
+ export declare function createRecordings(): Recordings;
24
+ /**
25
+ * Native Extension that decorates the eventStore and commandBus with
26
+ * recording wrappers.
27
+ *
28
+ * **Decoration order** (Phase 6 D-62): user decorators registered AFTER this
29
+ * extension's `app.use(...)` wrap OUTSIDE the recording decorators. To land
30
+ * the recording decorators at the INNERMOST position (capturing messages
31
+ * AFTER all interceptors have enriched them), call
32
+ * `app.use(testRecordingExtension(recordings))` BEFORE applying any user
33
+ * decorators / `configureFn(app)`.
34
+ *
35
+ * The legacy enhancer used `Number.MIN_SAFE_INTEGER` numeric priority for the
36
+ * same effect; Phase 6 dropped numeric priorities — innermost = first
37
+ * registered.
38
+ */
39
+ export declare function testRecordingExtension(recordings: Recordings): Extension;
40
+ //# sourceMappingURL=recording-enhancer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recording-enhancer.d.ts","sourceRoot":"","sources":["../src/recording-enhancer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAO,MAAM,gBAAgB,CAAA;AACpD,OAAO,KAAK,EAAc,cAAc,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAEpF;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,4CAA4C;IAC5C,MAAM,IAAI,aAAa,CAAC,YAAY,CAAC,CAAA;IACrC,gDAAgD;IAChD,QAAQ,IAAI,aAAa,CAAC,cAAc,CAAC,CAAA;IACzC,kEAAkE;IAClE,KAAK,IAAI,IAAI,CAAA;CACd;AAcD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,IAAI,UAAU,CAwB7C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,UAAU,GAAG,SAAS,CAmCxE"}