@ontrails/testing 1.0.0-beta.14 → 1.0.0-beta.16
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/CHANGELOG.md +69 -0
- package/README.md +12 -12
- package/package.json +15 -6
- package/src/all.ts +153 -16
- package/src/assertions.ts +253 -0
- package/src/context.ts +67 -38
- package/src/contracts.ts +15 -24
- package/src/crosses.ts +93 -51
- package/src/detours.ts +155 -18
- package/src/effective-examples.ts +350 -0
- package/src/examples.ts +139 -63
- package/src/harness-cli.ts +19 -11
- package/src/harness-mcp.ts +9 -8
- package/src/index.ts +14 -4
- package/src/logger.ts +3 -1
- package/src/scenario.ts +368 -0
- package/src/signals.ts +221 -0
- package/src/types.ts +64 -6
- package/.turbo/turbo-build.log +0 -1
- package/.turbo/turbo-lint.log +0 -3
- package/.turbo/turbo-typecheck.log +0 -1
- package/dist/all.d.ts +0 -31
- package/dist/all.d.ts.map +0 -1
- package/dist/all.js +0 -47
- package/dist/all.js.map +0 -1
- package/dist/assertions.d.ts +0 -49
- package/dist/assertions.d.ts.map +0 -1
- package/dist/assertions.js +0 -84
- package/dist/assertions.js.map +0 -1
- package/dist/context.d.ts +0 -75
- package/dist/context.d.ts.map +0 -1
- package/dist/context.js +0 -107
- package/dist/context.js.map +0 -1
- package/dist/contracts.d.ts +0 -17
- package/dist/contracts.d.ts.map +0 -1
- package/dist/contracts.js +0 -71
- package/dist/contracts.js.map +0 -1
- package/dist/crosses.d.ts +0 -38
- package/dist/crosses.d.ts.map +0 -1
- package/dist/crosses.js +0 -213
- package/dist/crosses.js.map +0 -1
- package/dist/detours.d.ts +0 -12
- package/dist/detours.d.ts.map +0 -1
- package/dist/detours.js +0 -30
- package/dist/detours.js.map +0 -1
- package/dist/examples.d.ts +0 -23
- package/dist/examples.d.ts.map +0 -1
- package/dist/examples.js +0 -202
- package/dist/examples.js.map +0 -1
- package/dist/follows.d.ts +0 -38
- package/dist/follows.d.ts.map +0 -1
- package/dist/follows.js +0 -212
- package/dist/follows.js.map +0 -1
- package/dist/harness-cli.d.ts +0 -21
- package/dist/harness-cli.d.ts.map +0 -1
- package/dist/harness-cli.js +0 -200
- package/dist/harness-cli.js.map +0 -1
- package/dist/harness-mcp.d.ts +0 -21
- package/dist/harness-mcp.d.ts.map +0 -1
- package/dist/harness-mcp.js +0 -53
- package/dist/harness-mcp.js.map +0 -1
- package/dist/index.d.ts +0 -16
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -16
- package/dist/index.js.map +0 -1
- package/dist/logger.d.ts +0 -15
- package/dist/logger.d.ts.map +0 -1
- package/dist/logger.js +0 -87
- package/dist/logger.js.map +0 -1
- package/dist/trail.d.ts +0 -20
- package/dist/trail.d.ts.map +0 -1
- package/dist/trail.js +0 -80
- package/dist/trail.js.map +0 -1
- package/dist/types.d.ts +0 -80
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -5
- package/dist/types.js.map +0 -1
- package/src/__tests__/all.test.ts +0 -135
- package/src/__tests__/context.test.ts +0 -150
- package/src/__tests__/contracts.test.ts +0 -185
- package/src/__tests__/crosses.test.ts +0 -587
- package/src/__tests__/detours.test.ts +0 -55
- package/src/__tests__/examples.test.ts +0 -534
- package/src/__tests__/harness-cli.test.ts +0 -66
- package/src/__tests__/logger.test.ts +0 -136
- package/src/__tests__/trail.test.ts +0 -99
- package/tsconfig.json +0 -9
- package/tsconfig.tsbuildinfo +0 -1
package/dist/crosses.js
DELETED
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* testCrosses — crossing-aware scenario testing for trails with crossings.
|
|
3
|
-
*
|
|
4
|
-
* Tests the crossing graph: which trails were crossed, in what order,
|
|
5
|
-
* and supports failure injection from crossed trail examples.
|
|
6
|
-
*/
|
|
7
|
-
import { describe, expect, test } from 'bun:test';
|
|
8
|
-
import { executeTrail, InternalError, Result, ValidationError, validateInput, } from '@ontrails/core';
|
|
9
|
-
import { assertErrorMatch, assertFullMatch, assertSchemaMatch, } from './assertions.js';
|
|
10
|
-
import { mergeProvisionOverrides, mergeTestContext } from './context.js';
|
|
11
|
-
const collectDeclaredProvisions = (trailDef, trailsMap) => {
|
|
12
|
-
const seenProvisionIds = new Set();
|
|
13
|
-
const seenTrailIds = new Set();
|
|
14
|
-
const provisions = [];
|
|
15
|
-
const collect = (candidate) => {
|
|
16
|
-
for (const declaredProvision of candidate.provisions) {
|
|
17
|
-
if (seenProvisionIds.has(declaredProvision.id)) {
|
|
18
|
-
continue;
|
|
19
|
-
}
|
|
20
|
-
seenProvisionIds.add(declaredProvision.id);
|
|
21
|
-
provisions.push(declaredProvision);
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
const visit = (candidate) => {
|
|
25
|
-
if (seenTrailIds.has(candidate.id)) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
seenTrailIds.add(candidate.id);
|
|
29
|
-
collect(candidate);
|
|
30
|
-
for (const crossedId of candidate.crosses) {
|
|
31
|
-
const crossedTrail = trailsMap?.get(crossedId);
|
|
32
|
-
if (crossedTrail) {
|
|
33
|
-
visit(crossedTrail);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
visit(trailDef);
|
|
38
|
-
return provisions;
|
|
39
|
-
};
|
|
40
|
-
const resolveCrossMockProvisions = async (trailDef, trailsMap) => {
|
|
41
|
-
const provisions = {};
|
|
42
|
-
for (const declaredProvision of collectDeclaredProvisions(trailDef, trailsMap)) {
|
|
43
|
-
if (!declaredProvision.mock) {
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
provisions[declaredProvision.id] = await declaredProvision.mock();
|
|
47
|
-
}
|
|
48
|
-
return provisions;
|
|
49
|
-
};
|
|
50
|
-
// ---------------------------------------------------------------------------
|
|
51
|
-
// Injection helpers
|
|
52
|
-
// ---------------------------------------------------------------------------
|
|
53
|
-
/**
|
|
54
|
-
* Find an error example on a trail by name or description substring.
|
|
55
|
-
*/
|
|
56
|
-
const findErrorExample = (trailDef, description) => {
|
|
57
|
-
const example = trailDef.examples?.find((ex) => ex.error !== undefined &&
|
|
58
|
-
(ex.description?.includes(description) || ex.name.includes(description)));
|
|
59
|
-
return example?.error;
|
|
60
|
-
};
|
|
61
|
-
/**
|
|
62
|
-
* Try to inject an error from a crossed trail's example.
|
|
63
|
-
* Returns undefined when no injection is configured for this trail ID.
|
|
64
|
-
*/
|
|
65
|
-
const tryInjectError = (id, scenario, trailsMap) => {
|
|
66
|
-
const injection = scenario.injectFromExample?.[id];
|
|
67
|
-
if (injection === undefined) {
|
|
68
|
-
return undefined;
|
|
69
|
-
}
|
|
70
|
-
const trailDef = trailsMap?.get(id);
|
|
71
|
-
if (trailDef === undefined) {
|
|
72
|
-
return Result.err(new InternalError(`Cannot inject: trail "${id}" not in topo`));
|
|
73
|
-
}
|
|
74
|
-
const errorName = findErrorExample(trailDef, injection);
|
|
75
|
-
if (errorName === undefined) {
|
|
76
|
-
return Result.err(new InternalError(`No error example matching "${injection}" on trail "${id}"`));
|
|
77
|
-
}
|
|
78
|
-
return Result.err(new Error(errorName));
|
|
79
|
-
};
|
|
80
|
-
/**
|
|
81
|
-
* Execute a trail from the map, validating input first.
|
|
82
|
-
*/
|
|
83
|
-
const executeFromMap = (id, input, trailsMap, ctx, provisions, cross) => {
|
|
84
|
-
const trailDef = trailsMap?.get(id);
|
|
85
|
-
if (trailDef === undefined) {
|
|
86
|
-
return undefined;
|
|
87
|
-
}
|
|
88
|
-
const nestedCtx = cross ? { ...ctx, cross } : ctx;
|
|
89
|
-
return executeTrail(trailDef, input, {
|
|
90
|
-
ctx: nestedCtx,
|
|
91
|
-
provisions,
|
|
92
|
-
});
|
|
93
|
-
};
|
|
94
|
-
// ---------------------------------------------------------------------------
|
|
95
|
-
// Cross factory
|
|
96
|
-
// ---------------------------------------------------------------------------
|
|
97
|
-
/**
|
|
98
|
-
* Build a recording cross function that optionally injects errors.
|
|
99
|
-
*/
|
|
100
|
-
const createRecordingCross = (trace, scenario, trailsMap, baseCross, ctx, provisions) => {
|
|
101
|
-
// The generic O on CrossFn is erased at runtime; the cast is safe
|
|
102
|
-
// because callers narrow via isOk/isErr before accessing the value.
|
|
103
|
-
const cross = (id, input) => {
|
|
104
|
-
trace.push({ id, input });
|
|
105
|
-
const injected = tryInjectError(id, scenario, trailsMap);
|
|
106
|
-
if (injected !== undefined) {
|
|
107
|
-
return Promise.resolve(injected);
|
|
108
|
-
}
|
|
109
|
-
if (baseCross !== undefined) {
|
|
110
|
-
return baseCross(id, input);
|
|
111
|
-
}
|
|
112
|
-
const executed = executeFromMap(id, input, trailsMap, ctx, provisions, cross);
|
|
113
|
-
if (executed !== undefined) {
|
|
114
|
-
return Promise.resolve(executed);
|
|
115
|
-
}
|
|
116
|
-
return Promise.resolve(Result.ok());
|
|
117
|
-
};
|
|
118
|
-
return cross;
|
|
119
|
-
};
|
|
120
|
-
// ---------------------------------------------------------------------------
|
|
121
|
-
// Scenario assertions
|
|
122
|
-
// ---------------------------------------------------------------------------
|
|
123
|
-
const assertScenarioResult = (result, scenario, trailDef) => {
|
|
124
|
-
if (scenario.expectValue !== undefined) {
|
|
125
|
-
assertFullMatch(result, scenario.expectValue);
|
|
126
|
-
}
|
|
127
|
-
else if (scenario.expectErr !== undefined) {
|
|
128
|
-
assertErrorMatch(result, scenario.expectErr, scenario.expectErrMessage);
|
|
129
|
-
}
|
|
130
|
-
else if (scenario.expectErrMessage !== undefined) {
|
|
131
|
-
expect(result.isErr()).toBe(true);
|
|
132
|
-
if (result.isErr()) {
|
|
133
|
-
expect(result.error.message).toContain(scenario.expectErrMessage);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
else if (scenario.expectOk === true) {
|
|
137
|
-
expect(result.isOk()).toBe(true);
|
|
138
|
-
assertSchemaMatch(result, trailDef.output);
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
const assertCrossTrace = (trace, scenario) => {
|
|
142
|
-
if (scenario.expectCrossed !== undefined) {
|
|
143
|
-
const crossedIds = trace.map((r) => r.id);
|
|
144
|
-
expect(crossedIds).toEqual([...scenario.expectCrossed]);
|
|
145
|
-
}
|
|
146
|
-
if (scenario.expectCrossedCount !== undefined) {
|
|
147
|
-
const counts = {};
|
|
148
|
-
for (const record of trace) {
|
|
149
|
-
counts[record.id] = (counts[record.id] ?? 0) + 1;
|
|
150
|
-
}
|
|
151
|
-
expect(counts).toEqual({ ...scenario.expectCrossedCount });
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
const handleValidationError = (validated, scenario) => {
|
|
155
|
-
if (!validated.isErr()) {
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
if (scenario.expectErr === ValidationError) {
|
|
159
|
-
expect(validated.error).toBeInstanceOf(ValidationError);
|
|
160
|
-
if (scenario.expectErrMessage !== undefined) {
|
|
161
|
-
expect(validated.error.message).toContain(scenario.expectErrMessage);
|
|
162
|
-
}
|
|
163
|
-
return true;
|
|
164
|
-
}
|
|
165
|
-
throw new Error(`Input validation failed unexpectedly: ${validated.error.message}`);
|
|
166
|
-
};
|
|
167
|
-
// ---------------------------------------------------------------------------
|
|
168
|
-
// Scenario runner
|
|
169
|
-
// ---------------------------------------------------------------------------
|
|
170
|
-
const buildTestContext = (scenario, ctx, trailsMap, provisions) => {
|
|
171
|
-
const trace = [];
|
|
172
|
-
const baseCtx = mergeTestContext(ctx);
|
|
173
|
-
const cross = createRecordingCross(trace, scenario, trailsMap, baseCtx.cross, baseCtx, provisions);
|
|
174
|
-
return { testCtx: { ...baseCtx, cross }, trace };
|
|
175
|
-
};
|
|
176
|
-
const runScenario = async (trailDef, scenario, ctx, trailsMap, provisions) => {
|
|
177
|
-
const validated = validateInput(trailDef.input, scenario.input);
|
|
178
|
-
if (handleValidationError(validated, scenario)) {
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
const { trace, testCtx } = buildTestContext(scenario, ctx, trailsMap, provisions);
|
|
182
|
-
const result = await executeTrail(trailDef, scenario.input, {
|
|
183
|
-
ctx: testCtx,
|
|
184
|
-
provisions,
|
|
185
|
-
});
|
|
186
|
-
assertCrossTrace(trace, scenario);
|
|
187
|
-
assertScenarioResult(result, scenario, trailDef);
|
|
188
|
-
};
|
|
189
|
-
/**
|
|
190
|
-
* Generate a describe block for a trail with crossings with one test per scenario.
|
|
191
|
-
*
|
|
192
|
-
* @example
|
|
193
|
-
* ```ts
|
|
194
|
-
* testCrosses(onboardTrail, [
|
|
195
|
-
* {
|
|
196
|
-
* description: "crosses add then relate",
|
|
197
|
-
* input: { name: "Alpha" },
|
|
198
|
-
* expectOk: true,
|
|
199
|
-
* expectCrossed: ["entity.add", "entity.relate"],
|
|
200
|
-
* },
|
|
201
|
-
* ]);
|
|
202
|
-
* ```
|
|
203
|
-
*/
|
|
204
|
-
export const testCrosses = (trailDef, scenarios, options) => {
|
|
205
|
-
const explicitProvisions = options?.provisions;
|
|
206
|
-
describe(trailDef.id, () => {
|
|
207
|
-
test.each([...scenarios])('$description', async (scenario) => {
|
|
208
|
-
const provisions = mergeProvisionOverrides(await resolveCrossMockProvisions(trailDef, options?.trails), options?.ctx, explicitProvisions);
|
|
209
|
-
await runScenario(trailDef, scenario, options?.ctx, options?.trails, provisions);
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
};
|
|
213
|
-
//# sourceMappingURL=crosses.js.map
|
package/dist/crosses.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"crosses.js","sourceRoot":"","sources":["../src/crosses.ts"],"names":[],"mappings":"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"}
|
package/dist/detours.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* testDetours — verify that all detour targets exist in the topo.
|
|
3
|
-
*
|
|
4
|
-
* Pure structural validation. No implementation execution needed.
|
|
5
|
-
*/
|
|
6
|
-
import type { Topo } from '@ontrails/core';
|
|
7
|
-
/**
|
|
8
|
-
* Verify that every trail's detour targets reference trails that
|
|
9
|
-
* actually exist in the app's topo.
|
|
10
|
-
*/
|
|
11
|
-
export declare const testDetours: (app: Topo) => void;
|
|
12
|
-
//# sourceMappingURL=detours.d.ts.map
|
package/dist/detours.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"detours.d.ts","sourceRoot":"","sources":["../src/detours.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,IAAI,EAAS,MAAM,gBAAgB,CAAC;AAMlD;;;GAGG;AACH,eAAO,MAAM,WAAW,GAAI,KAAK,IAAI,KAAG,IAyBvC,CAAC"}
|
package/dist/detours.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* testDetours — verify that all detour targets exist in the topo.
|
|
3
|
-
*
|
|
4
|
-
* Pure structural validation. No implementation execution needed.
|
|
5
|
-
*/
|
|
6
|
-
import { describe, expect, test } from 'bun:test';
|
|
7
|
-
// ---------------------------------------------------------------------------
|
|
8
|
-
// testDetours
|
|
9
|
-
// ---------------------------------------------------------------------------
|
|
10
|
-
/**
|
|
11
|
-
* Verify that every trail's detour targets reference trails that
|
|
12
|
-
* actually exist in the app's topo.
|
|
13
|
-
*/
|
|
14
|
-
export const testDetours = (app) => {
|
|
15
|
-
const trailEntries = [...app.trails];
|
|
16
|
-
describe('detours', () => {
|
|
17
|
-
describe.each(trailEntries)('%s', (_id, trailDef) => {
|
|
18
|
-
const t = trailDef;
|
|
19
|
-
if (t.detours === undefined) {
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
const { detours } = t;
|
|
23
|
-
const testCases = Object.entries(detours).flatMap(([detourName, targets]) => targets.map((targetId) => ({ detourName, targetId })));
|
|
24
|
-
test.each(testCases)('detour "$detourName" -> "$targetId" exists', ({ targetId }) => {
|
|
25
|
-
expect(app.has(targetId)).toBe(true);
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
});
|
|
29
|
-
};
|
|
30
|
-
//# sourceMappingURL=detours.js.map
|
package/dist/detours.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"detours.js","sourceRoot":"","sources":["../src/detours.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAIlD,8EAA8E;AAC9E,cAAc;AACd,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,GAAS,EAAQ,EAAE;IAC7C,MAAM,YAAY,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;IAErC,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE;QACvB,QAAQ,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE;YAClD,MAAM,CAAC,GAAG,QAAmC,CAAC;YAE9C,IAAI,CAAC,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC5B,OAAO;YACT,CAAC;YAED,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;YACtB,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,OAAO,CAC/C,CAAC,CAAC,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE,CACxB,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC,CACxD,CAAC;YAEF,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAClB,4CAA4C,EAC5C,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;gBACf,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvC,CAAC,CACF,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
|
package/dist/examples.d.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* testExamples — the headline one-liner.
|
|
3
|
-
*
|
|
4
|
-
* Iterates every trail in the app's topo. For each trail with examples,
|
|
5
|
-
* generates describe/test blocks using bun:test. Progressive assertion
|
|
6
|
-
* determines which check to run per example. For trails with `crosses`
|
|
7
|
-
* declarations, checks that every declared crossing was called at least once.
|
|
8
|
-
*/
|
|
9
|
-
import type { Topo, TrailContext } from '@ontrails/core';
|
|
10
|
-
import type { TestExecutionOptions } from './context.js';
|
|
11
|
-
/**
|
|
12
|
-
* Generate describe/test blocks for every trail example in the app.
|
|
13
|
-
*
|
|
14
|
-
* For trails with `crosses` declarations and examples, also verifies that
|
|
15
|
-
* every declared crossed ID was called at least once across all examples.
|
|
16
|
-
*
|
|
17
|
-
* One line in your test file:
|
|
18
|
-
* ```ts
|
|
19
|
-
* testExamples(app);
|
|
20
|
-
* ```
|
|
21
|
-
*/
|
|
22
|
-
export declare const testExamples: (app: Topo, ctxOrFactory?: Partial<TrailContext> | TestExecutionOptions | (() => Partial<TrailContext> | TestExecutionOptions)) => void;
|
|
23
|
-
//# sourceMappingURL=examples.d.ts.map
|
package/dist/examples.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"examples.d.ts","sourceRoot":"","sources":["../src/examples.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAGV,IAAI,EAGJ,YAAY,EACb,MAAM,gBAAgB,CAAC;AAmCxB,OAAO,KAAK,EAAiB,oBAAoB,EAAE,MAAM,cAAc,CAAC;AA6MxE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,GACvB,KAAK,IAAI,EACT,eACI,OAAO,CAAC,YAAY,CAAC,GACrB,oBAAoB,GACpB,CAAC,MAAM,OAAO,CAAC,YAAY,CAAC,GAAG,oBAAoB,CAAC,KACvD,IA0EF,CAAC"}
|
package/dist/examples.js
DELETED
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* testExamples — the headline one-liner.
|
|
3
|
-
*
|
|
4
|
-
* Iterates every trail in the app's topo. For each trail with examples,
|
|
5
|
-
* generates describe/test blocks using bun:test. Progressive assertion
|
|
6
|
-
* determines which check to run per example. For trails with `crosses`
|
|
7
|
-
* declarations, checks that every declared crossing was called at least once.
|
|
8
|
-
*/
|
|
9
|
-
import { describe, expect, test } from 'bun:test';
|
|
10
|
-
import { AlreadyExistsError, AmbiguousError, AssertionError, AuthError, CancelledError, ConflictError, InternalError, NetworkError, NotFoundError, PermissionError, RateLimitError, executeTrail, Result, TimeoutError, TrailsError, ValidationError, validateInput, } from '@ontrails/core';
|
|
11
|
-
import { assertErrorMatch, assertFullMatch, assertSchemaMatch, } from './assertions.js';
|
|
12
|
-
import { defaultMintPermit, mergeProvisionOverrides, mergeTestContext, normalizeTestExecutionOptions, resolveMockProvisions, } from './context.js';
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
|
-
// Error class name -> constructor map
|
|
15
|
-
// ---------------------------------------------------------------------------
|
|
16
|
-
const ERROR_MAP = {
|
|
17
|
-
AlreadyExistsError: AlreadyExistsError,
|
|
18
|
-
AmbiguousError: AmbiguousError,
|
|
19
|
-
AssertionError: AssertionError,
|
|
20
|
-
AuthError: AuthError,
|
|
21
|
-
CancelledError: CancelledError,
|
|
22
|
-
ConflictError: ConflictError,
|
|
23
|
-
InternalError: InternalError,
|
|
24
|
-
NetworkError: NetworkError,
|
|
25
|
-
NotFoundError: NotFoundError,
|
|
26
|
-
PermissionError: PermissionError,
|
|
27
|
-
RateLimitError: RateLimitError,
|
|
28
|
-
TimeoutError: TimeoutError,
|
|
29
|
-
TrailsError: TrailsError,
|
|
30
|
-
ValidationError: ValidationError,
|
|
31
|
-
};
|
|
32
|
-
/**
|
|
33
|
-
* Resolve an error class name string to the actual constructor.
|
|
34
|
-
* Falls back to generic Error if the name is not in the core taxonomy.
|
|
35
|
-
*/
|
|
36
|
-
const resolveErrorClass = (name) => ERROR_MAP[name] ?? Error;
|
|
37
|
-
// ---------------------------------------------------------------------------
|
|
38
|
-
// Helpers
|
|
39
|
-
// ---------------------------------------------------------------------------
|
|
40
|
-
const assertProgressiveMatch = (result, example, output) => {
|
|
41
|
-
if (example.expected !== undefined) {
|
|
42
|
-
assertFullMatch(result, example.expected);
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
if (example.error !== undefined) {
|
|
46
|
-
const errorClass = resolveErrorClass(example.error);
|
|
47
|
-
assertErrorMatch(result, errorClass);
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
assertSchemaMatch(result, output);
|
|
51
|
-
};
|
|
52
|
-
/**
|
|
53
|
-
* Handle input validation failure for an example.
|
|
54
|
-
* Returns true if the validation error was expected (and assertions passed).
|
|
55
|
-
* Throws if the validation error was unexpected.
|
|
56
|
-
*/
|
|
57
|
-
const handleValidationError = (validated, example) => {
|
|
58
|
-
if (!validated.isErr()) {
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
61
|
-
if (example.error !== undefined) {
|
|
62
|
-
const errorClass = resolveErrorClass(example.error);
|
|
63
|
-
expect(validated.error).toBeInstanceOf(errorClass);
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
throw new Error(`Example "${example.name}" has invalid input: ${validated.error.message}`);
|
|
67
|
-
};
|
|
68
|
-
/**
|
|
69
|
-
* Apply auto-minting: if the trail declares scoped permits and the context
|
|
70
|
-
* doesn't already have a permit, mint one and merge it into the context.
|
|
71
|
-
*/
|
|
72
|
-
const applyAutoMint = (ctx, trailDef, opts) => {
|
|
73
|
-
if (opts.strictPermits) {
|
|
74
|
-
return ctx;
|
|
75
|
-
}
|
|
76
|
-
if (ctx.permit !== undefined) {
|
|
77
|
-
return ctx;
|
|
78
|
-
}
|
|
79
|
-
const mint = opts.mintPermit ?? defaultMintPermit;
|
|
80
|
-
const permit = mint(trailDef);
|
|
81
|
-
if (!permit) {
|
|
82
|
-
return ctx;
|
|
83
|
-
}
|
|
84
|
-
return { ...ctx, permit };
|
|
85
|
-
};
|
|
86
|
-
/**
|
|
87
|
-
* Run a single example against a trail.
|
|
88
|
-
* Handles validation, execution, and assertions.
|
|
89
|
-
*/
|
|
90
|
-
const runExample = async (t, example, output, testCtx, provisions, opts) => {
|
|
91
|
-
const validated = validateInput(t.input, example.input);
|
|
92
|
-
if (handleValidationError(validated, example)) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
const ctx = opts ? applyAutoMint(testCtx, t, opts) : testCtx;
|
|
96
|
-
const result = await executeTrail(t, example.input, {
|
|
97
|
-
ctx,
|
|
98
|
-
provisions: provisions ?? opts?.provisions,
|
|
99
|
-
});
|
|
100
|
-
assertProgressiveMatch(result, example, output);
|
|
101
|
-
};
|
|
102
|
-
// ---------------------------------------------------------------------------
|
|
103
|
-
// Crossing coverage for trails with crossings
|
|
104
|
-
// ---------------------------------------------------------------------------
|
|
105
|
-
/**
|
|
106
|
-
* Build a recording cross function that tracks which trail IDs are called.
|
|
107
|
-
*
|
|
108
|
-
* Delegates to `baseCross` when available, otherwise looks up the trail
|
|
109
|
-
* in the topo and executes it with validated input. Falls back to
|
|
110
|
-
* `Result.ok()` when neither is available.
|
|
111
|
-
*/
|
|
112
|
-
const createCoverageCross = (called, baseCross, topo, ctx, provisions) => {
|
|
113
|
-
const cross = (id, input) => {
|
|
114
|
-
called.add(id);
|
|
115
|
-
if (baseCross !== undefined) {
|
|
116
|
-
return baseCross(id, input);
|
|
117
|
-
}
|
|
118
|
-
const trailDef = topo.get(id);
|
|
119
|
-
if (trailDef !== undefined) {
|
|
120
|
-
return executeTrail(trailDef, input, {
|
|
121
|
-
ctx: { ...ctx, cross },
|
|
122
|
-
provisions,
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
return Promise.resolve(Result.ok());
|
|
126
|
-
};
|
|
127
|
-
return cross;
|
|
128
|
-
};
|
|
129
|
-
/**
|
|
130
|
-
* Run a single example against a trail with crossings, recording cross calls.
|
|
131
|
-
*/
|
|
132
|
-
const runCompositionExample = async (trailDef, example, output, baseCtx, called, topo, provisions, opts) => {
|
|
133
|
-
const validated = validateInput(trailDef.input, example.input);
|
|
134
|
-
if (handleValidationError(validated, example)) {
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
const mintedCtx = opts ? applyAutoMint(baseCtx, trailDef, opts) : baseCtx;
|
|
138
|
-
const cross = createCoverageCross(called, mintedCtx.cross, topo, mintedCtx, provisions);
|
|
139
|
-
const testCtx = { ...mintedCtx, cross };
|
|
140
|
-
const result = await executeTrail(trailDef, example.input, {
|
|
141
|
-
ctx: testCtx,
|
|
142
|
-
provisions: provisions ?? opts?.provisions,
|
|
143
|
-
});
|
|
144
|
-
assertProgressiveMatch(result, example, output);
|
|
145
|
-
};
|
|
146
|
-
// ---------------------------------------------------------------------------
|
|
147
|
-
// testExamples
|
|
148
|
-
// ---------------------------------------------------------------------------
|
|
149
|
-
/**
|
|
150
|
-
* Generate describe/test blocks for every trail example in the app.
|
|
151
|
-
*
|
|
152
|
-
* For trails with `crosses` declarations and examples, also verifies that
|
|
153
|
-
* every declared crossed ID was called at least once across all examples.
|
|
154
|
-
*
|
|
155
|
-
* One line in your test file:
|
|
156
|
-
* ```ts
|
|
157
|
-
* testExamples(app);
|
|
158
|
-
* ```
|
|
159
|
-
*/
|
|
160
|
-
export const testExamples = (app, ctxOrFactory) => {
|
|
161
|
-
const resolveInput = typeof ctxOrFactory === 'function' ? ctxOrFactory : () => ctxOrFactory;
|
|
162
|
-
const allTrails = app.list();
|
|
163
|
-
const withExamples = allTrails.filter((t) => t.examples !== undefined && t.examples.length > 0);
|
|
164
|
-
const simpleTrails = withExamples.filter((t) => t.crosses.length === 0);
|
|
165
|
-
const compositionTrails = withExamples.filter((t) => t.crosses.length > 0);
|
|
166
|
-
// Simple trails: run examples directly
|
|
167
|
-
if (simpleTrails.length > 0) {
|
|
168
|
-
describe.each(simpleTrails)('$id', (t) => {
|
|
169
|
-
const { examples, output } = t;
|
|
170
|
-
if (!examples) {
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
test.each([...examples])('example: $name', async (example) => {
|
|
174
|
-
const resolved = normalizeTestExecutionOptions(resolveInput());
|
|
175
|
-
const provisions = mergeProvisionOverrides(await resolveMockProvisions(app), resolved.ctx, resolved.provisions);
|
|
176
|
-
const testCtx = mergeTestContext(resolved.ctx);
|
|
177
|
-
await runExample(t, example, output, testCtx, provisions, resolved);
|
|
178
|
-
});
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
// Composition trails: use recording cross and check coverage
|
|
182
|
-
if (compositionTrails.length > 0) {
|
|
183
|
-
describe.each(compositionTrails)('$id', (t) => {
|
|
184
|
-
const { examples, output } = t;
|
|
185
|
-
if (!examples) {
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
const called = new Set();
|
|
189
|
-
test.each([...examples])('example: $name', async (example) => {
|
|
190
|
-
const resolved = normalizeTestExecutionOptions(resolveInput());
|
|
191
|
-
const provisions = mergeProvisionOverrides(await resolveMockProvisions(app), resolved.ctx, resolved.provisions);
|
|
192
|
-
const baseCtx = mergeTestContext(resolved.ctx);
|
|
193
|
-
await runCompositionExample(t, example, output, baseCtx, called, app, provisions, resolved);
|
|
194
|
-
});
|
|
195
|
-
test('crossing coverage', () => {
|
|
196
|
-
const uncovered = t.crosses.filter((id) => !called.has(id));
|
|
197
|
-
expect(uncovered).toEqual([]);
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
};
|
|
202
|
-
//# sourceMappingURL=examples.js.map
|
package/dist/examples.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"examples.js","sourceRoot":"","sources":["../src/examples.ts"],"names":[],"mappings":"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"}
|
package/dist/follows.d.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* testFollows — composition-aware scenario testing for trails with follow.
|
|
3
|
-
*
|
|
4
|
-
* Tests the follow graph: which trails were followed, in what order,
|
|
5
|
-
* and supports failure injection from followed trail examples.
|
|
6
|
-
*/
|
|
7
|
-
import type { AnyTrail, ServiceOverrideMap, TrailContext } from '@ontrails/core';
|
|
8
|
-
import type { FollowScenario } from './types.js';
|
|
9
|
-
/** Options for testFollows that provide trail definitions for injection. */
|
|
10
|
-
export interface TestFollowOptions {
|
|
11
|
-
/** Partial context overrides. */
|
|
12
|
-
readonly ctx?: Partial<TrailContext> | undefined;
|
|
13
|
-
/**
|
|
14
|
-
* Explicit service overrides merged on top of auto-resolved mocks for every
|
|
15
|
-
* scenario. Values are passed by reference — provide immutable objects, or
|
|
16
|
-
* use `mock()` on the service definition to get a fresh instance per run.
|
|
17
|
-
*/
|
|
18
|
-
readonly services?: ServiceOverrideMap | undefined;
|
|
19
|
-
/** Map of trail ID to trail definition, used for injectFromExample. */
|
|
20
|
-
readonly trails?: ReadonlyMap<string, AnyTrail> | undefined;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Generate a describe block for a composition trail with one test per scenario.
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* ```ts
|
|
27
|
-
* testFollows(onboardTrail, [
|
|
28
|
-
* {
|
|
29
|
-
* description: "follows add then relate",
|
|
30
|
-
* input: { name: "Alpha" },
|
|
31
|
-
* expectOk: true,
|
|
32
|
-
* expectFollowed: ["entity.add", "entity.relate"],
|
|
33
|
-
* },
|
|
34
|
-
* ]);
|
|
35
|
-
* ```
|
|
36
|
-
*/
|
|
37
|
-
export declare const testFollows: (trailDef: AnyTrail, scenarios: readonly FollowScenario[], options?: TestFollowOptions) => void;
|
|
38
|
-
//# sourceMappingURL=follows.d.ts.map
|
package/dist/follows.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"follows.d.ts","sourceRoot":"","sources":["../src/follows.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EACV,QAAQ,EAER,kBAAkB,EAClB,YAAY,EACb,MAAM,gBAAgB,CAAC;AAexB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAuSjD,4EAA4E;AAC5E,MAAM,WAAW,iBAAiB;IAChC,iCAAiC;IACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC;IACjD;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IACnD,uEAAuE;IACvE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,SAAS,CAAC;CAC7D;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,WAAW,GACtB,UAAU,QAAQ,EAClB,WAAW,SAAS,cAAc,EAAE,EACpC,UAAU,iBAAiB,KAC1B,IAoBF,CAAC"}
|