@ontrails/testing 1.0.0-beta.13 → 1.0.0-beta.15
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/.turbo/turbo-lint.log +1 -1
- package/CHANGELOG.md +28 -0
- package/README.md +11 -11
- package/dist/all.d.ts +10 -5
- package/dist/all.d.ts.map +1 -1
- package/dist/all.js +78 -26
- package/dist/all.js.map +1 -1
- package/dist/assertions.d.ts +23 -0
- package/dist/assertions.d.ts.map +1 -1
- package/dist/assertions.js +154 -0
- package/dist/assertions.js.map +1 -1
- package/dist/context.d.ts +17 -16
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +31 -20
- package/dist/context.js.map +1 -1
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +9 -5
- package/dist/contracts.js.map +1 -1
- package/dist/crosses.d.ts +4 -4
- package/dist/crosses.d.ts.map +1 -1
- package/dist/crosses.js +49 -39
- package/dist/crosses.js.map +1 -1
- package/dist/detours.d.ts +5 -4
- package/dist/detours.d.ts.map +1 -1
- package/dist/detours.js +93 -14
- package/dist/detours.js.map +1 -1
- package/dist/effective-examples.d.ts +30 -0
- package/dist/effective-examples.d.ts.map +1 -0
- package/dist/effective-examples.js +227 -0
- package/dist/effective-examples.js.map +1 -0
- package/dist/examples.d.ts +1 -1
- package/dist/examples.d.ts.map +1 -1
- package/dist/examples.js +79 -41
- package/dist/examples.js.map +1 -1
- package/dist/harness-cli.d.ts +3 -3
- package/dist/harness-cli.d.ts.map +1 -1
- package/dist/harness-cli.js +25 -33
- package/dist/harness-cli.js.map +1 -1
- package/dist/harness-mcp.d.ts +3 -3
- package/dist/harness-mcp.d.ts.map +1 -1
- package/dist/harness-mcp.js +9 -8
- package/dist/harness-mcp.js.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/scenario.d.ts +37 -0
- package/dist/scenario.d.ts.map +1 -0
- package/dist/scenario.js +235 -0
- package/dist/scenario.js.map +1 -0
- package/dist/types.d.ts +38 -5
- package/dist/types.d.ts.map +1 -1
- package/package.json +9 -5
- package/src/__tests__/all.test.ts +217 -29
- package/src/__tests__/context.test.ts +32 -12
- package/src/__tests__/contracts.test.ts +72 -18
- package/src/__tests__/crosses.test.ts +78 -78
- package/src/__tests__/detours.test.ts +176 -19
- package/src/__tests__/effective-examples.test.ts +203 -0
- package/src/__tests__/examples.test.ts +152 -50
- package/src/__tests__/harness-cli.test.ts +90 -0
- package/src/__tests__/harness-mcp.test.ts +37 -0
- package/src/__tests__/partial-match.test.ts +126 -0
- package/src/__tests__/scenario.test.ts +381 -0
- package/src/all.ts +149 -12
- package/src/assertions.ts +253 -0
- package/src/context.ts +64 -38
- package/src/contracts.ts +14 -8
- package/src/crosses.ts +93 -51
- package/src/detours.ts +155 -18
- package/src/effective-examples.ts +350 -0
- package/src/examples.ts +127 -59
- package/src/harness-cli.ts +33 -49
- package/src/harness-mcp.ts +9 -8
- package/src/index.ts +13 -3
- package/src/scenario.ts +370 -0
- package/src/types.ts +63 -5
- package/tsconfig.tests.json +10 -0
- package/tsconfig.tsbuildinfo +1 -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/context.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Test context factory for creating TrailContext instances suitable for testing.
|
|
3
3
|
*/
|
|
4
|
-
import { Result,
|
|
4
|
+
import { Result, buildCrossValidationSchema, createResourceLookup, passthroughTrace, } from '@ontrails/core';
|
|
5
5
|
import { createTestLogger } from './logger.js';
|
|
6
6
|
// ---------------------------------------------------------------------------
|
|
7
7
|
// createTestContext
|
|
@@ -22,10 +22,11 @@ export const createTestContext = (overrides) => {
|
|
|
22
22
|
extensions: undefined,
|
|
23
23
|
logger: overrides?.logger ?? createTestLogger(),
|
|
24
24
|
requestId: overrides?.requestId ?? 'test-request-001',
|
|
25
|
+
trace: overrides?.trace ?? passthroughTrace,
|
|
25
26
|
workspaceRoot: cwd,
|
|
26
27
|
};
|
|
27
|
-
const lookup =
|
|
28
|
-
ctx.
|
|
28
|
+
const lookup = createResourceLookup(() => ctx);
|
|
29
|
+
ctx.resource = lookup;
|
|
29
30
|
return ctx;
|
|
30
31
|
};
|
|
31
32
|
/**
|
|
@@ -44,19 +45,27 @@ export const createTestContext = (overrides) => {
|
|
|
44
45
|
*/
|
|
45
46
|
export const createCrossContext = (options) => {
|
|
46
47
|
const responses = options?.responses ?? {};
|
|
47
|
-
|
|
48
|
+
const respondToCross = (idOrTrail) => {
|
|
49
|
+
const id = typeof idOrTrail === 'string' ? idOrTrail : idOrTrail.id;
|
|
48
50
|
const response = responses[id];
|
|
49
51
|
if (response === undefined) {
|
|
50
52
|
return Promise.resolve(Result.err(new Error(`No mock response for cross("${id}")`)));
|
|
51
53
|
}
|
|
52
54
|
return Promise.resolve(response);
|
|
53
55
|
};
|
|
56
|
+
const cross = (async (idOrTrail, _input) => {
|
|
57
|
+
if (Array.isArray(idOrTrail)) {
|
|
58
|
+
return await Promise.all(idOrTrail.map(([target]) => respondToCross(target)));
|
|
59
|
+
}
|
|
60
|
+
return await respondToCross(idOrTrail);
|
|
61
|
+
});
|
|
62
|
+
return cross;
|
|
54
63
|
};
|
|
55
64
|
/**
|
|
56
|
-
* Default permit
|
|
65
|
+
* Default permit creator — reads `trail.permit.scopes` and produces a
|
|
57
66
|
* minimal permit object. No dependency on `@ontrails/permits`.
|
|
58
67
|
*/
|
|
59
|
-
export const
|
|
68
|
+
export const defaultCreatePermit = (trail) => {
|
|
60
69
|
if (!trail.permit || trail.permit === 'public') {
|
|
61
70
|
return undefined;
|
|
62
71
|
}
|
|
@@ -64,44 +73,46 @@ export const defaultMintPermit = (trail) => {
|
|
|
64
73
|
};
|
|
65
74
|
const isTestExecutionOptions = (input) => input !== undefined &&
|
|
66
75
|
(Object.hasOwn(input, 'ctx') ||
|
|
67
|
-
Object.hasOwn(input, '
|
|
76
|
+
Object.hasOwn(input, 'resources') ||
|
|
68
77
|
Object.hasOwn(input, 'strictPermits') ||
|
|
69
|
-
Object.hasOwn(input, '
|
|
78
|
+
Object.hasOwn(input, 'createPermit'));
|
|
70
79
|
export const normalizeTestExecutionOptions = (input) => isTestExecutionOptions(input) ? input : { ctx: input };
|
|
71
|
-
export const
|
|
80
|
+
export const mergeResourceOverrides = (autoResolved, ctx, explicit) => ({
|
|
72
81
|
...autoResolved,
|
|
73
82
|
...ctx?.extensions,
|
|
74
83
|
...explicit,
|
|
75
84
|
});
|
|
76
|
-
const
|
|
77
|
-
const
|
|
78
|
-
for (const
|
|
79
|
-
if (!
|
|
85
|
+
const buildMockResources = async (app) => {
|
|
86
|
+
const resources = {};
|
|
87
|
+
for (const declaredResource of app.listResources()) {
|
|
88
|
+
if (!declaredResource.mock) {
|
|
80
89
|
continue;
|
|
81
90
|
}
|
|
82
|
-
|
|
91
|
+
resources[declaredResource.id] = await declaredResource.mock();
|
|
83
92
|
}
|
|
84
|
-
return
|
|
93
|
+
return resources;
|
|
85
94
|
};
|
|
86
|
-
export const
|
|
95
|
+
export const createMockResources = async (app) => await buildMockResources(app);
|
|
96
|
+
// Re-export from core so existing consumers of this module continue to work.
|
|
97
|
+
export { buildCrossValidationSchema };
|
|
87
98
|
/**
|
|
88
99
|
* Merge a Partial<TrailContext> into a test context.
|
|
89
100
|
* Used internally when the public API accepts Partial<TrailContext>.
|
|
90
101
|
*/
|
|
91
|
-
export const mergeTestContext = (ctx,
|
|
102
|
+
export const mergeTestContext = (ctx, resources) => {
|
|
92
103
|
const base = createTestContext();
|
|
93
104
|
const extensions = {
|
|
94
105
|
...base.extensions,
|
|
95
106
|
...ctx?.extensions,
|
|
96
|
-
...
|
|
107
|
+
...resources,
|
|
97
108
|
};
|
|
98
109
|
const merged = {
|
|
99
110
|
...base,
|
|
100
111
|
...ctx,
|
|
101
112
|
extensions: Object.keys(extensions).length === 0 ? undefined : extensions,
|
|
102
113
|
};
|
|
103
|
-
const lookup =
|
|
104
|
-
merged.
|
|
114
|
+
const lookup = createResourceLookup(() => merged);
|
|
115
|
+
merged.resource = lookup;
|
|
105
116
|
return merged;
|
|
106
117
|
};
|
|
107
118
|
//# sourceMappingURL=context.js.map
|
package/dist/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,OAAO,
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
|
package/dist/contracts.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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;
|
|
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
CHANGED
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
import { describe, test } from 'bun:test';
|
|
9
9
|
import { executeTrail, formatZodIssues, validateInput } from '@ontrails/core';
|
|
10
10
|
import { expectOk } from './assertions.js';
|
|
11
|
-
import {
|
|
11
|
+
import { mergeResourceOverrides, mergeTestContext, normalizeTestExecutionOptions, createMockResources, } from './context.js';
|
|
12
|
+
import { deriveTrailExamples } from './effective-examples.js';
|
|
12
13
|
// ---------------------------------------------------------------------------
|
|
13
14
|
// Helpers
|
|
14
15
|
// ---------------------------------------------------------------------------
|
|
@@ -38,13 +39,16 @@ const validateOutputSchema = (outputSchema, value, trailId, exampleName) => {
|
|
|
38
39
|
*/
|
|
39
40
|
export const testContracts = (app, ctxOrFactory) => {
|
|
40
41
|
const resolveInput = typeof ctxOrFactory === 'function' ? ctxOrFactory : () => ctxOrFactory;
|
|
41
|
-
const allEntries = app.list()
|
|
42
|
+
const allEntries = app.list().map((trailDef) => ({
|
|
43
|
+
...trailDef,
|
|
44
|
+
examples: deriveTrailExamples(trailDef),
|
|
45
|
+
}));
|
|
42
46
|
describe('contracts', () => {
|
|
43
47
|
describe.each(allEntries)('$id', (t) => {
|
|
44
48
|
if (t.output === undefined) {
|
|
45
49
|
return;
|
|
46
50
|
}
|
|
47
|
-
if (t.examples
|
|
51
|
+
if (t.examples.length === 0) {
|
|
48
52
|
return;
|
|
49
53
|
}
|
|
50
54
|
if (needsCrossContext(t, resolveInput)) {
|
|
@@ -54,13 +58,13 @@ export const testContracts = (app, ctxOrFactory) => {
|
|
|
54
58
|
const successExamples = examples.filter((e) => e.error === undefined);
|
|
55
59
|
test.each(successExamples)('contract: $name', async (example) => {
|
|
56
60
|
const resolved = normalizeTestExecutionOptions(resolveInput());
|
|
57
|
-
const
|
|
61
|
+
const resources = mergeResourceOverrides(await createMockResources(app), resolved.ctx, resolved.resources);
|
|
58
62
|
const testCtx = mergeTestContext(resolved.ctx);
|
|
59
63
|
const validated = validateInput(t.input, example.input);
|
|
60
64
|
expectOk(validated);
|
|
61
65
|
const result = await executeTrail(t, example.input, {
|
|
62
66
|
ctx: testCtx,
|
|
63
|
-
|
|
67
|
+
resources,
|
|
64
68
|
});
|
|
65
69
|
const resultValue = expectOk(result);
|
|
66
70
|
validateOutputSchema(outputSchema, resultValue, t.id, example.name);
|
package/dist/contracts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contracts.js","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAG1C,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG9E,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"contracts.js","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAG1C,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAG9E,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAChB,6BAA6B,EAC7B,mBAAmB,GACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAE9D,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,4EAA4E;AAC5E,MAAM,iBAAiB,GAAG,CACxB,CAAU,EACV,UAA0E,EACjE,EAAE;IACX,MAAM,IAAI,GAAG,CAAoC,CAAC;IAClD,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/C,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,CAAC,6BAA6B,CAAC,UAAU,EAAE,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC;AACjE,CAAC,CAAC;AAEF,MAAM,oBAAoB,GAAG,CAC3B,YAAuB,EACvB,KAAc,EACd,OAAe,EACf,WAAmB,EACb,EAAE;IACR,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC7C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACpD,MAAM,IAAI,KAAK,CACb,sCAAsC,OAAO,eAAe,WAAW,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,sBAAsB,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAC7K,CAAC;IACJ,CAAC;AACH,CAAC,CAAC;AAEF,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,GAAS,EACT,YAGwD,EAClD,EAAE;IACR,MAAM,YAAY,GAChB,OAAO,YAAY,KAAK,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC;IACzE,MAAM,UAAU,GAAI,GAAG,CAAC,IAAI,EAAyC,CAAC,GAAG,CACvE,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACb,GAAG,QAAQ;QACX,QAAQ,EAAE,mBAAmB,CAAC,QAAQ,CAAC;KACxC,CAAC,CACH,CAAC;IAEF,QAAQ,CAAC,WAAW,EAAE,GAAG,EAAE;QACzB,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE;YACrC,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAC3B,OAAO;YACT,CAAC;YACD,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5B,OAAO;YACT,CAAC;YACD,IAAI,iBAAiB,CAAC,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC;gBACvC,OAAO;YACT,CAAC;YAED,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,CAAC,CAAC;YAC7C,MAAM,eAAe,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC;YAEtE,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CACxB,iBAAiB,EACjB,KAAK,EAAE,OAAuC,EAAE,EAAE;gBAChD,MAAM,QAAQ,GAAG,6BAA6B,CAAC,YAAY,EAAE,CAAC,CAAC;gBAC/D,MAAM,SAAS,GAAG,sBAAsB,CACtC,MAAM,mBAAmB,CAAC,GAAG,CAAC,EAC9B,QAAQ,CAAC,GAAG,EACZ,QAAQ,CAAC,SAAS,CACnB,CAAC;gBACF,MAAM,OAAO,GAAG,gBAAgB,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;gBAE/C,MAAM,SAAS,GAAG,aAAa,CAAC,CAAC,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;gBACxD,QAAQ,CAAC,SAAS,CAAC,CAAC;gBAEpB,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,KAAK,EAAE;oBAClD,GAAG,EAAE,OAAO;oBACZ,SAAS;iBACV,CAAC,CAAC;gBACH,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;gBAErC,oBAAoB,CAAC,YAAY,EAAE,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;YACtE,CAAC,CACF,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
|
package/dist/crosses.d.ts
CHANGED
|
@@ -4,18 +4,18 @@
|
|
|
4
4
|
* Tests the crossing graph: which trails were crossed, in what order,
|
|
5
5
|
* and supports failure injection from crossed trail examples.
|
|
6
6
|
*/
|
|
7
|
-
import type { AnyTrail,
|
|
7
|
+
import type { AnyTrail, ResourceOverrideMap, TrailContext } from '@ontrails/core';
|
|
8
8
|
import type { CrossScenario } from './types.js';
|
|
9
9
|
/** Options for testCrosses that provide trail definitions for injection. */
|
|
10
10
|
export interface TestCrossOptions {
|
|
11
11
|
/** Partial context overrides. */
|
|
12
12
|
readonly ctx?: Partial<TrailContext> | undefined;
|
|
13
13
|
/**
|
|
14
|
-
* Explicit
|
|
14
|
+
* Explicit resource overrides merged on top of auto-resolved mocks for every
|
|
15
15
|
* scenario. Values are passed by reference — provide immutable objects, or
|
|
16
|
-
* use `mock()` on the
|
|
16
|
+
* use `mock()` on the resource definition to get a fresh instance per run.
|
|
17
17
|
*/
|
|
18
|
-
readonly
|
|
18
|
+
readonly resources?: ResourceOverrideMap | undefined;
|
|
19
19
|
/** Map of trail ID to trail definition, used for injectFromExample. */
|
|
20
20
|
readonly trails?: ReadonlyMap<string, AnyTrail> | undefined;
|
|
21
21
|
}
|
package/dist/crosses.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crosses.d.ts","sourceRoot":"","sources":["../src/crosses.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EACV,QAAQ,EAER,
|
|
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
CHANGED
|
@@ -5,20 +5,20 @@
|
|
|
5
5
|
* and supports failure injection from crossed trail examples.
|
|
6
6
|
*/
|
|
7
7
|
import { describe, expect, test } from 'bun:test';
|
|
8
|
-
import { executeTrail, InternalError, Result, ValidationError, validateInput, } from '@ontrails/core';
|
|
8
|
+
import { buildCrossValidationSchema, executeTrail, InternalError, Result, ValidationError, validateInput, } from '@ontrails/core';
|
|
9
9
|
import { assertErrorMatch, assertFullMatch, assertSchemaMatch, } from './assertions.js';
|
|
10
|
-
import {
|
|
11
|
-
const
|
|
12
|
-
const
|
|
10
|
+
import { mergeResourceOverrides, mergeTestContext } from './context.js';
|
|
11
|
+
const collectDeclaredResources = (trailDef, trailsMap) => {
|
|
12
|
+
const seenResourceIds = new Set();
|
|
13
13
|
const seenTrailIds = new Set();
|
|
14
|
-
const
|
|
14
|
+
const resources = [];
|
|
15
15
|
const collect = (candidate) => {
|
|
16
|
-
for (const
|
|
17
|
-
if (
|
|
16
|
+
for (const declaredResource of candidate.resources) {
|
|
17
|
+
if (seenResourceIds.has(declaredResource.id)) {
|
|
18
18
|
continue;
|
|
19
19
|
}
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
seenResourceIds.add(declaredResource.id);
|
|
21
|
+
resources.push(declaredResource);
|
|
22
22
|
}
|
|
23
23
|
};
|
|
24
24
|
const visit = (candidate) => {
|
|
@@ -35,17 +35,17 @@ const collectDeclaredProvisions = (trailDef, trailsMap) => {
|
|
|
35
35
|
}
|
|
36
36
|
};
|
|
37
37
|
visit(trailDef);
|
|
38
|
-
return
|
|
38
|
+
return resources;
|
|
39
39
|
};
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
for (const
|
|
43
|
-
if (!
|
|
40
|
+
const resolveCrossMockResources = async (trailDef, trailsMap) => {
|
|
41
|
+
const resources = {};
|
|
42
|
+
for (const declaredResource of collectDeclaredResources(trailDef, trailsMap)) {
|
|
43
|
+
if (!declaredResource.mock) {
|
|
44
44
|
continue;
|
|
45
45
|
}
|
|
46
|
-
|
|
46
|
+
resources[declaredResource.id] = await declaredResource.mock();
|
|
47
47
|
}
|
|
48
|
-
return
|
|
48
|
+
return resources;
|
|
49
49
|
};
|
|
50
50
|
// ---------------------------------------------------------------------------
|
|
51
51
|
// Injection helpers
|
|
@@ -77,10 +77,7 @@ const tryInjectError = (id, scenario, trailsMap) => {
|
|
|
77
77
|
}
|
|
78
78
|
return Result.err(new Error(errorName));
|
|
79
79
|
};
|
|
80
|
-
|
|
81
|
-
* Execute a trail from the map, validating input first.
|
|
82
|
-
*/
|
|
83
|
-
const executeFromMap = (id, input, trailsMap, ctx, provisions, cross) => {
|
|
80
|
+
const executeFromMap = (id, input, trailsMap, ctx, resources, cross) => {
|
|
84
81
|
const trailDef = trailsMap?.get(id);
|
|
85
82
|
if (trailDef === undefined) {
|
|
86
83
|
return undefined;
|
|
@@ -88,32 +85,45 @@ const executeFromMap = (id, input, trailsMap, ctx, provisions, cross) => {
|
|
|
88
85
|
const nestedCtx = cross ? { ...ctx, cross } : ctx;
|
|
89
86
|
return executeTrail(trailDef, input, {
|
|
90
87
|
ctx: nestedCtx,
|
|
91
|
-
|
|
88
|
+
resources,
|
|
89
|
+
validationSchema: buildCrossValidationSchema(trailDef),
|
|
92
90
|
});
|
|
93
91
|
};
|
|
92
|
+
/** Extract trail ID from either a trail object or a string. */
|
|
93
|
+
const resolveCrossId = (idOrTrail) => typeof idOrTrail === 'string' ? idOrTrail : idOrTrail.id;
|
|
94
94
|
// ---------------------------------------------------------------------------
|
|
95
95
|
// Cross factory
|
|
96
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
|
+
};
|
|
97
105
|
/**
|
|
98
106
|
* Build a recording cross function that optionally injects errors.
|
|
99
107
|
*/
|
|
100
|
-
const createRecordingCross = (trace, scenario, trailsMap, baseCross, ctx,
|
|
108
|
+
const createRecordingCross = (trace, scenario, trailsMap, baseCross, ctx, resources) => {
|
|
101
109
|
// The generic O on CrossFn is erased at runtime; the cast is safe
|
|
102
110
|
// because callers narrow via isOk/isErr before accessing the value.
|
|
103
|
-
const
|
|
111
|
+
const invokeCross = async (idOrTrail, input, self) => {
|
|
112
|
+
const id = resolveCrossId(idOrTrail);
|
|
104
113
|
trace.push({ id, input });
|
|
105
114
|
const injected = tryInjectError(id, scenario, trailsMap);
|
|
106
115
|
if (injected !== undefined) {
|
|
107
|
-
return
|
|
108
|
-
}
|
|
109
|
-
if (baseCross !== undefined) {
|
|
110
|
-
return baseCross(id, input);
|
|
116
|
+
return injected;
|
|
111
117
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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)));
|
|
115
125
|
}
|
|
116
|
-
return
|
|
126
|
+
return await invokeCross(idOrTrail, input, cross);
|
|
117
127
|
};
|
|
118
128
|
return cross;
|
|
119
129
|
};
|
|
@@ -167,21 +177,21 @@ const handleValidationError = (validated, scenario) => {
|
|
|
167
177
|
// ---------------------------------------------------------------------------
|
|
168
178
|
// Scenario runner
|
|
169
179
|
// ---------------------------------------------------------------------------
|
|
170
|
-
const buildTestContext = (scenario, ctx, trailsMap,
|
|
180
|
+
const buildTestContext = (scenario, ctx, trailsMap, resources) => {
|
|
171
181
|
const trace = [];
|
|
172
182
|
const baseCtx = mergeTestContext(ctx);
|
|
173
|
-
const cross = createRecordingCross(trace, scenario, trailsMap, baseCtx.cross, baseCtx,
|
|
183
|
+
const cross = createRecordingCross(trace, scenario, trailsMap, baseCtx.cross, baseCtx, resources);
|
|
174
184
|
return { testCtx: { ...baseCtx, cross }, trace };
|
|
175
185
|
};
|
|
176
|
-
const runScenario = async (trailDef, scenario, ctx, trailsMap,
|
|
186
|
+
const runScenario = async (trailDef, scenario, ctx, trailsMap, resources) => {
|
|
177
187
|
const validated = validateInput(trailDef.input, scenario.input);
|
|
178
188
|
if (handleValidationError(validated, scenario)) {
|
|
179
189
|
return;
|
|
180
190
|
}
|
|
181
|
-
const { trace, testCtx } = buildTestContext(scenario, ctx, trailsMap,
|
|
191
|
+
const { trace, testCtx } = buildTestContext(scenario, ctx, trailsMap, resources);
|
|
182
192
|
const result = await executeTrail(trailDef, scenario.input, {
|
|
183
193
|
ctx: testCtx,
|
|
184
|
-
|
|
194
|
+
resources,
|
|
185
195
|
});
|
|
186
196
|
assertCrossTrace(trace, scenario);
|
|
187
197
|
assertScenarioResult(result, scenario, trailDef);
|
|
@@ -202,11 +212,11 @@ const runScenario = async (trailDef, scenario, ctx, trailsMap, provisions) => {
|
|
|
202
212
|
* ```
|
|
203
213
|
*/
|
|
204
214
|
export const testCrosses = (trailDef, scenarios, options) => {
|
|
205
|
-
const
|
|
215
|
+
const explicitResources = options?.resources;
|
|
206
216
|
describe(trailDef.id, () => {
|
|
207
217
|
test.each([...scenarios])('$description', async (scenario) => {
|
|
208
|
-
const
|
|
209
|
-
await runScenario(trailDef, scenario, options?.ctx, options?.trails,
|
|
218
|
+
const resources = mergeResourceOverrides(await resolveCrossMockResources(trailDef, options?.trails), options?.ctx, explicitResources);
|
|
219
|
+
await runScenario(trailDef, scenario, options?.ctx, options?.trails, resources);
|
|
210
220
|
});
|
|
211
221
|
});
|
|
212
222
|
};
|
package/dist/crosses.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crosses.js","sourceRoot":"","sources":["../src/crosses.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAQlD,OAAO,EACL,YAAY,EACZ,aAAa,EACb,MAAM,EACN,eAAe,EACf,aAAa,GACd,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,iBAAiB,GAClB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"crosses.js","sourceRoot":"","sources":["../src/crosses.ts"],"names":[],"mappings":"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"}
|
package/dist/detours.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* testDetours —
|
|
2
|
+
* testDetours — validate the live detour contract for every trail.
|
|
3
3
|
*
|
|
4
|
-
* Pure structural validation. No
|
|
4
|
+
* Pure structural validation. No blaze or detour recovery execution needed.
|
|
5
5
|
*/
|
|
6
6
|
import type { Topo } from '@ontrails/core';
|
|
7
7
|
/**
|
|
8
|
-
* Verify that every trail's
|
|
9
|
-
*
|
|
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.
|
|
10
11
|
*/
|
|
11
12
|
export declare const testDetours: (app: Topo) => void;
|
|
12
13
|
//# sourceMappingURL=detours.d.ts.map
|
package/dist/detours.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detours.d.ts","sourceRoot":"","sources":["../src/detours.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
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
CHANGED
|
@@ -1,28 +1,107 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* testDetours —
|
|
2
|
+
* testDetours — validate the live detour contract for every trail.
|
|
3
3
|
*
|
|
4
|
-
* Pure structural validation. No
|
|
4
|
+
* Pure structural validation. No blaze or detour recovery execution needed.
|
|
5
5
|
*/
|
|
6
|
-
import { describe,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
+
};
|
|
10
79
|
/**
|
|
11
|
-
* Verify that every trail's
|
|
12
|
-
*
|
|
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.
|
|
13
83
|
*/
|
|
14
84
|
export const testDetours = (app) => {
|
|
15
85
|
const trailEntries = [...app.trails];
|
|
16
86
|
describe('detours', () => {
|
|
17
87
|
describe.each(trailEntries)('%s', (_id, trailDef) => {
|
|
18
|
-
const
|
|
19
|
-
if (
|
|
88
|
+
const trail = trailDef;
|
|
89
|
+
if (trail.detours.length === 0) {
|
|
20
90
|
return;
|
|
21
91
|
}
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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);
|
|
26
105
|
});
|
|
27
106
|
});
|
|
28
107
|
});
|
package/dist/detours.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detours.js","sourceRoot":"","sources":["../src/detours.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"detours.js","sourceRoot":"","sources":["../src/detours.ts"],"names":[],"mappings":"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"}
|