@ontrails/testing 1.0.0-beta.15 → 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 +56 -1
- package/README.md +2 -2
- package/package.json +15 -7
- package/src/all.ts +7 -7
- package/src/context.ts +3 -0
- package/src/contracts.ts +1 -16
- package/src/examples.ts +19 -11
- package/src/index.ts +1 -1
- package/src/logger.ts +3 -1
- package/src/scenario.ts +3 -5
- package/src/signals.ts +221 -0
- package/src/types.ts +1 -1
- 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 -36
- package/dist/all.d.ts.map +0 -1
- package/dist/all.js +0 -99
- package/dist/all.js.map +0 -1
- package/dist/assertions.d.ts +0 -72
- package/dist/assertions.d.ts.map +0 -1
- package/dist/assertions.js +0 -238
- package/dist/assertions.js.map +0 -1
- package/dist/context.d.ts +0 -76
- package/dist/context.d.ts.map +0 -1
- package/dist/context.js +0 -118
- 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 -75
- 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 -223
- package/dist/crosses.js.map +0 -1
- package/dist/detours.d.ts +0 -13
- package/dist/detours.d.ts.map +0 -1
- package/dist/detours.js +0 -109
- package/dist/detours.js.map +0 -1
- package/dist/effective-examples.d.ts +0 -30
- package/dist/effective-examples.d.ts.map +0 -1
- package/dist/effective-examples.js +0 -227
- package/dist/effective-examples.js.map +0 -1
- package/dist/examples.d.ts +0 -23
- package/dist/examples.d.ts.map +0 -1
- package/dist/examples.js +0 -240
- package/dist/examples.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 -205
- 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 -54
- package/dist/harness-mcp.js.map +0 -1
- package/dist/index.d.ts +0 -18
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -19
- 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/scenario.d.ts +0 -37
- package/dist/scenario.d.ts.map +0 -1
- package/dist/scenario.js +0 -235
- package/dist/scenario.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 -113
- 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 -254
- package/src/__tests__/context.test.ts +0 -170
- package/src/__tests__/contracts.test.ts +0 -239
- package/src/__tests__/crosses.test.ts +0 -587
- package/src/__tests__/detours.test.ts +0 -212
- package/src/__tests__/effective-examples.test.ts +0 -203
- package/src/__tests__/examples.test.ts +0 -636
- package/src/__tests__/harness-cli.test.ts +0 -90
- package/src/__tests__/harness-mcp.test.ts +0 -37
- package/src/__tests__/logger.test.ts +0 -136
- package/src/__tests__/partial-match.test.ts +0 -126
- package/src/__tests__/scenario.test.ts +0 -381
- package/src/__tests__/trail.test.ts +0 -99
- package/tsconfig.json +0 -9
- package/tsconfig.tests.json +0 -10
- package/tsconfig.tsbuildinfo +0 -1
package/dist/contracts.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,IAAI,EAAuB,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAW9E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAsCzD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GACxB,KAAK,IAAI,EACT,eACI,OAAO,CAAC,YAAY,CAAC,GACrB,oBAAoB,GACpB,CAAC,MAAM,OAAO,CAAC,YAAY,CAAC,GAAG,oBAAoB,CAAC,KACvD,IAkDF,CAAC"}
|
package/dist/contracts.js
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* testContracts — output schema verification.
|
|
3
|
-
*
|
|
4
|
-
* For every trail that has both examples and an output schema,
|
|
5
|
-
* run each example and validate the implementation output against
|
|
6
|
-
* the declared schema.
|
|
7
|
-
*/
|
|
8
|
-
import { describe, test } from 'bun:test';
|
|
9
|
-
import { executeTrail, formatZodIssues, validateInput } from '@ontrails/core';
|
|
10
|
-
import { expectOk } from './assertions.js';
|
|
11
|
-
import { mergeResourceOverrides, mergeTestContext, normalizeTestExecutionOptions, createMockResources, } from './context.js';
|
|
12
|
-
import { deriveTrailExamples } from './effective-examples.js';
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
|
-
// Helpers
|
|
15
|
-
// ---------------------------------------------------------------------------
|
|
16
|
-
/** Check if a trail requires cross() but the context doesn't provide it. */
|
|
17
|
-
const needsCrossContext = (t, resolveCtx) => {
|
|
18
|
-
const spec = t;
|
|
19
|
-
if (!spec.crosses || spec.crosses.length === 0) {
|
|
20
|
-
return false;
|
|
21
|
-
}
|
|
22
|
-
return !normalizeTestExecutionOptions(resolveCtx()).ctx?.cross;
|
|
23
|
-
};
|
|
24
|
-
const validateOutputSchema = (outputSchema, value, trailId, exampleName) => {
|
|
25
|
-
const parsed = outputSchema.safeParse(value);
|
|
26
|
-
if (!parsed.success) {
|
|
27
|
-
const issues = formatZodIssues(parsed.error.issues);
|
|
28
|
-
throw new Error(`Output schema violation for trail "${trailId}", example "${exampleName}":\n${issues.map((i) => ` - ${i}`).join('\n')}\n\nActual output: ${JSON.stringify(value, null, 2)}`);
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
// testContracts
|
|
33
|
-
// ---------------------------------------------------------------------------
|
|
34
|
-
/**
|
|
35
|
-
* Verify that every trail implementation output matches its declared
|
|
36
|
-
* output schema. Catches implementation-schema drift.
|
|
37
|
-
*
|
|
38
|
-
* Trails without output schemas or examples are skipped.
|
|
39
|
-
*/
|
|
40
|
-
export const testContracts = (app, ctxOrFactory) => {
|
|
41
|
-
const resolveInput = typeof ctxOrFactory === 'function' ? ctxOrFactory : () => ctxOrFactory;
|
|
42
|
-
const allEntries = app.list().map((trailDef) => ({
|
|
43
|
-
...trailDef,
|
|
44
|
-
examples: deriveTrailExamples(trailDef),
|
|
45
|
-
}));
|
|
46
|
-
describe('contracts', () => {
|
|
47
|
-
describe.each(allEntries)('$id', (t) => {
|
|
48
|
-
if (t.output === undefined) {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
if (t.examples.length === 0) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
if (needsCrossContext(t, resolveInput)) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
const { examples, output: outputSchema } = t;
|
|
58
|
-
const successExamples = examples.filter((e) => e.error === undefined);
|
|
59
|
-
test.each(successExamples)('contract: $name', async (example) => {
|
|
60
|
-
const resolved = normalizeTestExecutionOptions(resolveInput());
|
|
61
|
-
const resources = mergeResourceOverrides(await createMockResources(app), resolved.ctx, resolved.resources);
|
|
62
|
-
const testCtx = mergeTestContext(resolved.ctx);
|
|
63
|
-
const validated = validateInput(t.input, example.input);
|
|
64
|
-
expectOk(validated);
|
|
65
|
-
const result = await executeTrail(t, example.input, {
|
|
66
|
-
ctx: testCtx,
|
|
67
|
-
resources,
|
|
68
|
-
});
|
|
69
|
-
const resultValue = expectOk(result);
|
|
70
|
-
validateOutputSchema(outputSchema, resultValue, t.id, example.name);
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
};
|
|
75
|
-
//# sourceMappingURL=contracts.js.map
|
package/dist/contracts.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"contracts.js","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"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"}
|
package/dist/crosses.d.ts
DELETED
|
@@ -1,38 +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 type { AnyTrail, ResourceOverrideMap, TrailContext } from '@ontrails/core';
|
|
8
|
-
import type { CrossScenario } from './types.js';
|
|
9
|
-
/** Options for testCrosses that provide trail definitions for injection. */
|
|
10
|
-
export interface TestCrossOptions {
|
|
11
|
-
/** Partial context overrides. */
|
|
12
|
-
readonly ctx?: Partial<TrailContext> | undefined;
|
|
13
|
-
/**
|
|
14
|
-
* Explicit resource 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 resource definition to get a fresh instance per run.
|
|
17
|
-
*/
|
|
18
|
-
readonly resources?: ResourceOverrideMap | 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 trail with crossings with one test per scenario.
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* ```ts
|
|
27
|
-
* testCrosses(onboardTrail, [
|
|
28
|
-
* {
|
|
29
|
-
* description: "crosses add then relate",
|
|
30
|
-
* input: { name: "Alpha" },
|
|
31
|
-
* expectOk: true,
|
|
32
|
-
* expectCrossed: ["entity.add", "entity.relate"],
|
|
33
|
-
* },
|
|
34
|
-
* ]);
|
|
35
|
-
* ```
|
|
36
|
-
*/
|
|
37
|
-
export declare const testCrosses: (trailDef: AnyTrail, scenarios: readonly CrossScenario[], options?: TestCrossOptions) => void;
|
|
38
|
-
//# sourceMappingURL=crosses.d.ts.map
|
package/dist/crosses.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"crosses.d.ts","sourceRoot":"","sources":["../src/crosses.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EACV,QAAQ,EAER,mBAAmB,EACnB,YAAY,EACb,MAAM,gBAAgB,CAAC;AAgBxB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAmVhD,4EAA4E;AAC5E,MAAM,WAAW,gBAAgB;IAC/B,iCAAiC;IACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC;IACjD;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,mBAAmB,GAAG,SAAS,CAAC;IACrD,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,aAAa,EAAE,EACnC,UAAU,gBAAgB,KACzB,IAsBF,CAAC"}
|
package/dist/crosses.js
DELETED
|
@@ -1,223 +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 { buildCrossValidationSchema, executeTrail, InternalError, Result, ValidationError, validateInput, } from '@ontrails/core';
|
|
9
|
-
import { assertErrorMatch, assertFullMatch, assertSchemaMatch, } from './assertions.js';
|
|
10
|
-
import { mergeResourceOverrides, mergeTestContext } from './context.js';
|
|
11
|
-
const collectDeclaredResources = (trailDef, trailsMap) => {
|
|
12
|
-
const seenResourceIds = new Set();
|
|
13
|
-
const seenTrailIds = new Set();
|
|
14
|
-
const resources = [];
|
|
15
|
-
const collect = (candidate) => {
|
|
16
|
-
for (const declaredResource of candidate.resources) {
|
|
17
|
-
if (seenResourceIds.has(declaredResource.id)) {
|
|
18
|
-
continue;
|
|
19
|
-
}
|
|
20
|
-
seenResourceIds.add(declaredResource.id);
|
|
21
|
-
resources.push(declaredResource);
|
|
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 resources;
|
|
39
|
-
};
|
|
40
|
-
const resolveCrossMockResources = async (trailDef, trailsMap) => {
|
|
41
|
-
const resources = {};
|
|
42
|
-
for (const declaredResource of collectDeclaredResources(trailDef, trailsMap)) {
|
|
43
|
-
if (!declaredResource.mock) {
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
resources[declaredResource.id] = await declaredResource.mock();
|
|
47
|
-
}
|
|
48
|
-
return resources;
|
|
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
|
-
const executeFromMap = (id, input, trailsMap, ctx, resources, cross) => {
|
|
81
|
-
const trailDef = trailsMap?.get(id);
|
|
82
|
-
if (trailDef === undefined) {
|
|
83
|
-
return undefined;
|
|
84
|
-
}
|
|
85
|
-
const nestedCtx = cross ? { ...ctx, cross } : ctx;
|
|
86
|
-
return executeTrail(trailDef, input, {
|
|
87
|
-
ctx: nestedCtx,
|
|
88
|
-
resources,
|
|
89
|
-
validationSchema: buildCrossValidationSchema(trailDef),
|
|
90
|
-
});
|
|
91
|
-
};
|
|
92
|
-
/** Extract trail ID from either a trail object or a string. */
|
|
93
|
-
const resolveCrossId = (idOrTrail) => typeof idOrTrail === 'string' ? idOrTrail : idOrTrail.id;
|
|
94
|
-
// ---------------------------------------------------------------------------
|
|
95
|
-
// Cross factory
|
|
96
|
-
// ---------------------------------------------------------------------------
|
|
97
|
-
/** Delegate to baseCross, executeFromMap, or fall back to Result.ok(). */
|
|
98
|
-
const delegateCross = (id, input, baseCross, trailsMap, ctx, resources, self) => {
|
|
99
|
-
if (baseCross !== undefined) {
|
|
100
|
-
return baseCross(id, input);
|
|
101
|
-
}
|
|
102
|
-
const executed = executeFromMap(id, input, trailsMap, ctx, resources, self);
|
|
103
|
-
return Promise.resolve(executed ?? Result.ok());
|
|
104
|
-
};
|
|
105
|
-
/**
|
|
106
|
-
* Build a recording cross function that optionally injects errors.
|
|
107
|
-
*/
|
|
108
|
-
const createRecordingCross = (trace, scenario, trailsMap, baseCross, ctx, resources) => {
|
|
109
|
-
// The generic O on CrossFn is erased at runtime; the cast is safe
|
|
110
|
-
// because callers narrow via isOk/isErr before accessing the value.
|
|
111
|
-
const invokeCross = async (idOrTrail, input, self) => {
|
|
112
|
-
const id = resolveCrossId(idOrTrail);
|
|
113
|
-
trace.push({ id, input });
|
|
114
|
-
const injected = tryInjectError(id, scenario, trailsMap);
|
|
115
|
-
if (injected !== undefined) {
|
|
116
|
-
return injected;
|
|
117
|
-
}
|
|
118
|
-
return await delegateCross(id, input, baseCross, trailsMap, ctx, resources, self);
|
|
119
|
-
};
|
|
120
|
-
// Accepts either a trail object (typed cross), a string id (untyped),
|
|
121
|
-
// or a batch of `[target, input]` tuples.
|
|
122
|
-
const cross = async function cross(idOrTrail, input) {
|
|
123
|
-
if (Array.isArray(idOrTrail)) {
|
|
124
|
-
return await Promise.all(idOrTrail.map(([target, batchInput]) => invokeCross(target, batchInput, cross)));
|
|
125
|
-
}
|
|
126
|
-
return await invokeCross(idOrTrail, input, cross);
|
|
127
|
-
};
|
|
128
|
-
return cross;
|
|
129
|
-
};
|
|
130
|
-
// ---------------------------------------------------------------------------
|
|
131
|
-
// Scenario assertions
|
|
132
|
-
// ---------------------------------------------------------------------------
|
|
133
|
-
const assertScenarioResult = (result, scenario, trailDef) => {
|
|
134
|
-
if (scenario.expectValue !== undefined) {
|
|
135
|
-
assertFullMatch(result, scenario.expectValue);
|
|
136
|
-
}
|
|
137
|
-
else if (scenario.expectErr !== undefined) {
|
|
138
|
-
assertErrorMatch(result, scenario.expectErr, scenario.expectErrMessage);
|
|
139
|
-
}
|
|
140
|
-
else if (scenario.expectErrMessage !== undefined) {
|
|
141
|
-
expect(result.isErr()).toBe(true);
|
|
142
|
-
if (result.isErr()) {
|
|
143
|
-
expect(result.error.message).toContain(scenario.expectErrMessage);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
else if (scenario.expectOk === true) {
|
|
147
|
-
expect(result.isOk()).toBe(true);
|
|
148
|
-
assertSchemaMatch(result, trailDef.output);
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
const assertCrossTrace = (trace, scenario) => {
|
|
152
|
-
if (scenario.expectCrossed !== undefined) {
|
|
153
|
-
const crossedIds = trace.map((r) => r.id);
|
|
154
|
-
expect(crossedIds).toEqual([...scenario.expectCrossed]);
|
|
155
|
-
}
|
|
156
|
-
if (scenario.expectCrossedCount !== undefined) {
|
|
157
|
-
const counts = {};
|
|
158
|
-
for (const record of trace) {
|
|
159
|
-
counts[record.id] = (counts[record.id] ?? 0) + 1;
|
|
160
|
-
}
|
|
161
|
-
expect(counts).toEqual({ ...scenario.expectCrossedCount });
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
const handleValidationError = (validated, scenario) => {
|
|
165
|
-
if (!validated.isErr()) {
|
|
166
|
-
return false;
|
|
167
|
-
}
|
|
168
|
-
if (scenario.expectErr === ValidationError) {
|
|
169
|
-
expect(validated.error).toBeInstanceOf(ValidationError);
|
|
170
|
-
if (scenario.expectErrMessage !== undefined) {
|
|
171
|
-
expect(validated.error.message).toContain(scenario.expectErrMessage);
|
|
172
|
-
}
|
|
173
|
-
return true;
|
|
174
|
-
}
|
|
175
|
-
throw new Error(`Input validation failed unexpectedly: ${validated.error.message}`);
|
|
176
|
-
};
|
|
177
|
-
// ---------------------------------------------------------------------------
|
|
178
|
-
// Scenario runner
|
|
179
|
-
// ---------------------------------------------------------------------------
|
|
180
|
-
const buildTestContext = (scenario, ctx, trailsMap, resources) => {
|
|
181
|
-
const trace = [];
|
|
182
|
-
const baseCtx = mergeTestContext(ctx);
|
|
183
|
-
const cross = createRecordingCross(trace, scenario, trailsMap, baseCtx.cross, baseCtx, resources);
|
|
184
|
-
return { testCtx: { ...baseCtx, cross }, trace };
|
|
185
|
-
};
|
|
186
|
-
const runScenario = async (trailDef, scenario, ctx, trailsMap, resources) => {
|
|
187
|
-
const validated = validateInput(trailDef.input, scenario.input);
|
|
188
|
-
if (handleValidationError(validated, scenario)) {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
const { trace, testCtx } = buildTestContext(scenario, ctx, trailsMap, resources);
|
|
192
|
-
const result = await executeTrail(trailDef, scenario.input, {
|
|
193
|
-
ctx: testCtx,
|
|
194
|
-
resources,
|
|
195
|
-
});
|
|
196
|
-
assertCrossTrace(trace, scenario);
|
|
197
|
-
assertScenarioResult(result, scenario, trailDef);
|
|
198
|
-
};
|
|
199
|
-
/**
|
|
200
|
-
* Generate a describe block for a trail with crossings with one test per scenario.
|
|
201
|
-
*
|
|
202
|
-
* @example
|
|
203
|
-
* ```ts
|
|
204
|
-
* testCrosses(onboardTrail, [
|
|
205
|
-
* {
|
|
206
|
-
* description: "crosses add then relate",
|
|
207
|
-
* input: { name: "Alpha" },
|
|
208
|
-
* expectOk: true,
|
|
209
|
-
* expectCrossed: ["entity.add", "entity.relate"],
|
|
210
|
-
* },
|
|
211
|
-
* ]);
|
|
212
|
-
* ```
|
|
213
|
-
*/
|
|
214
|
-
export const testCrosses = (trailDef, scenarios, options) => {
|
|
215
|
-
const explicitResources = options?.resources;
|
|
216
|
-
describe(trailDef.id, () => {
|
|
217
|
-
test.each([...scenarios])('$description', async (scenario) => {
|
|
218
|
-
const resources = mergeResourceOverrides(await resolveCrossMockResources(trailDef, options?.trails), options?.ctx, explicitResources);
|
|
219
|
-
await runScenario(trailDef, scenario, options?.ctx, options?.trails, resources);
|
|
220
|
-
});
|
|
221
|
-
});
|
|
222
|
-
};
|
|
223
|
-
//# 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,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* testDetours — validate the live detour contract for every trail.
|
|
3
|
-
*
|
|
4
|
-
* Pure structural validation. No blaze or detour recovery execution needed.
|
|
5
|
-
*/
|
|
6
|
-
import type { Topo } from '@ontrails/core';
|
|
7
|
-
/**
|
|
8
|
-
* Verify that every trail's detours match the live runtime contract:
|
|
9
|
-
* `on` must be an error constructor, `recover` must be callable, and
|
|
10
|
-
* later detours must not be shadowed by earlier broader `on` types.
|
|
11
|
-
*/
|
|
12
|
-
export declare const testDetours: (app: Topo) => void;
|
|
13
|
-
//# 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;AAKH,OAAO,KAAK,EAAE,IAAI,EAAS,MAAM,gBAAgB,CAAC;AA+HlD;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAI,KAAK,IAAI,KAAG,IAuCvC,CAAC"}
|
package/dist/detours.js
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* testDetours — validate the live detour contract for every trail.
|
|
3
|
-
*
|
|
4
|
-
* Pure structural validation. No blaze or detour recovery execution needed.
|
|
5
|
-
*/
|
|
6
|
-
import { describe, test } from 'bun:test';
|
|
7
|
-
import { TrailsError } from '@ontrails/core';
|
|
8
|
-
const isErrorConstructor = (value) => {
|
|
9
|
-
if (typeof value !== 'function') {
|
|
10
|
-
return false;
|
|
11
|
-
}
|
|
12
|
-
const { prototype } = value;
|
|
13
|
-
return prototype instanceof Error;
|
|
14
|
-
};
|
|
15
|
-
const detourLabel = (trailId, index, detour) => {
|
|
16
|
-
if (typeof detour.on === 'function') {
|
|
17
|
-
const { name } = detour.on;
|
|
18
|
-
if (typeof name === 'string' && name.length > 0) {
|
|
19
|
-
return `${trailId} detour[${index}] on ${name}`;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
return `${trailId} detour[${index}]`;
|
|
23
|
-
};
|
|
24
|
-
const assertValidOn = (trailId, index, detour) => {
|
|
25
|
-
if (isErrorConstructor(detour.on)) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
throw new Error(`${detourLabel(trailId, index, detour)} must declare a real error constructor in on:`);
|
|
29
|
-
};
|
|
30
|
-
const assertCallableRecover = (trailId, index, detour) => {
|
|
31
|
-
if (typeof detour.recover === 'function') {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
throw new Error(`${detourLabel(trailId, index, detour)} must declare a callable recover function`);
|
|
35
|
-
};
|
|
36
|
-
const sameOrSubtype = (candidate, ancestor) => {
|
|
37
|
-
if (candidate === ancestor) {
|
|
38
|
-
return true;
|
|
39
|
-
}
|
|
40
|
-
let current = Object.getPrototypeOf(candidate.prototype);
|
|
41
|
-
while (current && typeof current === 'object') {
|
|
42
|
-
const ctor = current.constructor;
|
|
43
|
-
if (ctor === ancestor) {
|
|
44
|
-
return true;
|
|
45
|
-
}
|
|
46
|
-
current = Object.getPrototypeOf(current);
|
|
47
|
-
}
|
|
48
|
-
return false;
|
|
49
|
-
};
|
|
50
|
-
const getShadowingDetour = (detours, index) => {
|
|
51
|
-
const detour = detours[index];
|
|
52
|
-
if (!detour || !isErrorConstructor(detour.on)) {
|
|
53
|
-
return undefined;
|
|
54
|
-
}
|
|
55
|
-
for (let previousIndex = 0; previousIndex < index; previousIndex += 1) {
|
|
56
|
-
const previous = detours[previousIndex];
|
|
57
|
-
if (!previous || !isErrorConstructor(previous.on)) {
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
if (sameOrSubtype(detour.on, previous.on)) {
|
|
61
|
-
return { index: previousIndex, on: previous.on };
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return undefined;
|
|
65
|
-
};
|
|
66
|
-
const assertNotShadowed = (trailId, detours, index) => {
|
|
67
|
-
const detour = detours[index];
|
|
68
|
-
if (!detour || !isErrorConstructor(detour.on)) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
const shadowing = getShadowingDetour(detours, index);
|
|
72
|
-
if (!shadowing) {
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
const previousName = shadowing.on.name || TrailsError.name;
|
|
76
|
-
const currentName = detour.on.name || TrailsError.name;
|
|
77
|
-
throw new Error(`${trailId} detour[${index}] on ${currentName} is shadowed by earlier detour[${shadowing.index}] on ${previousName}`);
|
|
78
|
-
};
|
|
79
|
-
/**
|
|
80
|
-
* Verify that every trail's detours match the live runtime contract:
|
|
81
|
-
* `on` must be an error constructor, `recover` must be callable, and
|
|
82
|
-
* later detours must not be shadowed by earlier broader `on` types.
|
|
83
|
-
*/
|
|
84
|
-
export const testDetours = (app) => {
|
|
85
|
-
const trailEntries = [...app.trails];
|
|
86
|
-
describe('detours', () => {
|
|
87
|
-
describe.each(trailEntries)('%s', (_id, trailDef) => {
|
|
88
|
-
const trail = trailDef;
|
|
89
|
-
if (trail.detours.length === 0) {
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
const detourCases = trail.detours.map((detour, index) => ({
|
|
93
|
-
detour,
|
|
94
|
-
index,
|
|
95
|
-
trailId: trail.id,
|
|
96
|
-
}));
|
|
97
|
-
test.each(detourCases)('$trailId detour[$index] uses an error constructor', ({ detour, index, trailId }) => {
|
|
98
|
-
assertValidOn(trailId, index, detour);
|
|
99
|
-
});
|
|
100
|
-
test.each(detourCases)('$trailId detour[$index] provides a callable recover', ({ detour, index, trailId }) => {
|
|
101
|
-
assertCallableRecover(trailId, index, detour);
|
|
102
|
-
});
|
|
103
|
-
test.each(detourCases)('$trailId detour[$index] is not shadowed by an earlier detour', ({ index, trailId }) => {
|
|
104
|
-
assertNotShadowed(trailId, trail.detours, index);
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
};
|
|
109
|
-
//# 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":"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"}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { Trail, TrailExample } from '@ontrails/core';
|
|
2
|
-
/**
|
|
3
|
-
* Returns `true` if the given example was synthesized from contour fixtures
|
|
4
|
-
* by `deriveTrailExamples`, `false` if it was authored on the trail.
|
|
5
|
-
*/
|
|
6
|
-
export declare const isDerivedExample: (example: TrailExample<unknown, unknown>) => boolean;
|
|
7
|
-
/**
|
|
8
|
-
* Prefer authored trail examples and fall back to contour-derived fixtures.
|
|
9
|
-
*
|
|
10
|
-
* Examples returned by this helper come from one of two provenances:
|
|
11
|
-
* - **Authored.** When `trail.examples` is non-empty, its entries are
|
|
12
|
-
* returned verbatim. These are the developer's stated intent and carry
|
|
13
|
-
* full invariants — including crossing-coverage assertions in
|
|
14
|
-
* `testExamples`.
|
|
15
|
-
* - **Derived.** When there are no authored examples but the trail has
|
|
16
|
-
* contours with examples, candidate inputs are synthesized from contour
|
|
17
|
-
* fixtures and validated against `trail.input`. These are opportunistic
|
|
18
|
-
* coverage that exists to let `testAll(app)` exercise contour-backed
|
|
19
|
-
* trails without per-test setup; they are not guaranteed to exercise
|
|
20
|
-
* every composition branch, so consumers should relax invariants that
|
|
21
|
-
* only make sense for authored inputs (see `isDerivedExample`).
|
|
22
|
-
*
|
|
23
|
-
* Contour examples stay as the raw input payload so Trails validation /
|
|
24
|
-
* transforms still happen exactly once inside the normal test execution
|
|
25
|
-
* path. Derived examples are additionally tagged via a module-level
|
|
26
|
-
* `WeakSet` so consumers can detect them without widening the public
|
|
27
|
-
* `TrailExample` shape.
|
|
28
|
-
*/
|
|
29
|
-
export declare const deriveTrailExamples: (trail: Trail<unknown, unknown, unknown>) => readonly TrailExample<unknown, unknown>[];
|
|
30
|
-
//# sourceMappingURL=effective-examples.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"effective-examples.d.ts","sourceRoot":"","sources":["../src/effective-examples.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAiBtE;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAC3B,SAAS,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,KACtC,OAAuC,CAAC;AAqQ3C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,mBAAmB,GAC9B,OAAO,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,KACtC,SAAS,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,EAyCzC,CAAC"}
|