@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/harness-cli.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* CLI integration test harness.
|
|
3
3
|
*
|
|
4
|
-
* Builds CLI commands from
|
|
4
|
+
* Builds CLI commands from a graph, executes them in-process,
|
|
5
5
|
* and captures stdout/stderr.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { deriveCliCommands } from '@ontrails/cli';
|
|
8
|
+
import { mergeTestContext } from './context.js';
|
|
9
9
|
// ---------------------------------------------------------------------------
|
|
10
10
|
// Tokenizer
|
|
11
11
|
// ---------------------------------------------------------------------------
|
|
@@ -17,33 +17,20 @@ const parseCommandString = (input) => input
|
|
|
17
17
|
// ---------------------------------------------------------------------------
|
|
18
18
|
// Command resolution
|
|
19
19
|
// ---------------------------------------------------------------------------
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
const match = commands.find((c) => c.group === firstToken && c.name === secondToken);
|
|
26
|
-
if (match === undefined) {
|
|
20
|
+
const matchesPath = (path, tokens) => path.length <= tokens.length &&
|
|
21
|
+
path.every((segment, index) => tokens[index] === segment);
|
|
22
|
+
/** Resolve a command from tokens using the longest matching command path. */
|
|
23
|
+
const resolveCommand = (commands, tokens) => {
|
|
24
|
+
if (tokens.length === 0) {
|
|
27
25
|
return undefined;
|
|
28
26
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const tryDirectMatch = (commands, firstToken, tokens) => {
|
|
33
|
-
const match = commands.find((c) => c.name === firstToken && c.group === undefined);
|
|
27
|
+
const [match] = commands
|
|
28
|
+
.filter((command) => matchesPath(command.path, tokens))
|
|
29
|
+
.toSorted((a, b) => b.path.length - a.path.length);
|
|
34
30
|
if (match === undefined) {
|
|
35
31
|
return undefined;
|
|
36
32
|
}
|
|
37
|
-
return { command: match, flagTokens: tokens.slice(
|
|
38
|
-
};
|
|
39
|
-
/** Resolve a command from tokens, handling group.name patterns. */
|
|
40
|
-
const resolveCommand = (commands, tokens) => {
|
|
41
|
-
const [firstToken, secondToken] = tokens;
|
|
42
|
-
if (firstToken === undefined) {
|
|
43
|
-
return undefined;
|
|
44
|
-
}
|
|
45
|
-
return (tryGroupMatch(commands, firstToken, secondToken, tokens) ??
|
|
46
|
-
tryDirectMatch(commands, firstToken, tokens));
|
|
33
|
+
return { command: match, flagTokens: tokens.slice(match.path.length) };
|
|
47
34
|
};
|
|
48
35
|
// ---------------------------------------------------------------------------
|
|
49
36
|
// Flag parsing
|
|
@@ -155,8 +142,8 @@ const buildErrorResult = (error, streams) => {
|
|
|
155
142
|
};
|
|
156
143
|
};
|
|
157
144
|
/** Execute a resolved command and return the result. */
|
|
158
|
-
const executeCommand = async (command, flags, streams) => {
|
|
159
|
-
const ctx =
|
|
145
|
+
const executeCommand = async (command, flags, streams, ctxOverrides) => {
|
|
146
|
+
const ctx = mergeTestContext(ctxOverrides);
|
|
160
147
|
const result = await command.execute({}, flags, ctx);
|
|
161
148
|
streams.restore();
|
|
162
149
|
if (result.isErr()) {
|
|
@@ -169,7 +156,7 @@ const executeCommand = async (command, flags, streams) => {
|
|
|
169
156
|
return formatSuccessResult(result.value, flags, streams);
|
|
170
157
|
};
|
|
171
158
|
/** Run the full command pipeline: resolve, parse, execute. */
|
|
172
|
-
const runCommand = async (commands, commandString) => {
|
|
159
|
+
const runCommand = async (commands, commandString, ctxOverrides) => {
|
|
173
160
|
const parts = parseCommandString(commandString);
|
|
174
161
|
const resolved = resolveCommand(commands, parts);
|
|
175
162
|
if (resolved === undefined) {
|
|
@@ -183,7 +170,7 @@ const runCommand = async (commands, commandString) => {
|
|
|
183
170
|
const flags = parseFlagTokens(flagTokens);
|
|
184
171
|
const streams = captureStreams();
|
|
185
172
|
try {
|
|
186
|
-
return await executeCommand(command, flags, streams);
|
|
173
|
+
return await executeCommand(command, flags, streams, ctxOverrides);
|
|
187
174
|
}
|
|
188
175
|
catch (error) {
|
|
189
176
|
return buildErrorResult(error, streams);
|
|
@@ -195,19 +182,24 @@ const runCommand = async (commands, commandString) => {
|
|
|
195
182
|
/**
|
|
196
183
|
* Create a CLI harness for integration testing.
|
|
197
184
|
*
|
|
198
|
-
* Builds commands from the
|
|
185
|
+
* Builds commands from the graph's topo and provides a `run()` method
|
|
199
186
|
* that parses command strings and executes them in-process.
|
|
200
187
|
*
|
|
201
188
|
* ```ts
|
|
202
|
-
* const harness = createCliHarness({
|
|
189
|
+
* const harness = createCliHarness({ graph });
|
|
203
190
|
* const result = await harness.run("entity show --name Alpha --output json");
|
|
204
191
|
* expect(result.exitCode).toBe(0);
|
|
205
192
|
* ```
|
|
206
193
|
*/
|
|
207
194
|
export const createCliHarness = (options) => {
|
|
208
|
-
const
|
|
195
|
+
const { ctx, graph, ...deriveOptions } = options;
|
|
196
|
+
const commandsResult = deriveCliCommands(graph, deriveOptions);
|
|
197
|
+
if (commandsResult.isErr()) {
|
|
198
|
+
throw commandsResult.error;
|
|
199
|
+
}
|
|
200
|
+
const commands = commandsResult.value;
|
|
209
201
|
return {
|
|
210
|
-
run: (commandString) => runCommand(commands, commandString),
|
|
202
|
+
run: (commandString) => runCommand(commands, commandString, ctx),
|
|
211
203
|
};
|
|
212
204
|
};
|
|
213
205
|
//# sourceMappingURL=harness-cli.js.map
|
package/dist/harness-cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"harness-cli.js","sourceRoot":"","sources":["../src/harness-cli.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"harness-cli.js","sourceRoot":"","sources":["../src/harness-cli.ts"],"names":[],"mappings":"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"}
|
package/dist/harness-mcp.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP integration test harness.
|
|
3
3
|
*
|
|
4
|
-
* Builds MCP tools from
|
|
4
|
+
* Builds MCP tools from a graph, invokes them directly (no transport),
|
|
5
5
|
* and returns the MCP tool response.
|
|
6
6
|
*/
|
|
7
7
|
import type { McpHarness, McpHarnessOptions } from './types.js';
|
|
8
8
|
/**
|
|
9
9
|
* Create an MCP harness for integration testing.
|
|
10
10
|
*
|
|
11
|
-
* Builds MCP tools from the
|
|
11
|
+
* Builds MCP tools from the graph's topo and provides a `callTool()` method
|
|
12
12
|
* that invokes tools directly without any transport boundary.
|
|
13
13
|
*
|
|
14
14
|
* ```ts
|
|
15
|
-
* const harness = createMcpHarness({
|
|
15
|
+
* const harness = createMcpHarness({ graph });
|
|
16
16
|
* const result = await harness.callTool("myapp_entity_show", { name: "Alpha" });
|
|
17
17
|
* expect(result.isError).toBe(false);
|
|
18
18
|
* ```
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"harness-mcp.d.ts","sourceRoot":"","sources":["../src/harness-mcp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EACV,UAAU,EACV,iBAAiB,EAElB,MAAM,YAAY,CAAC;AAMpB;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gBAAgB,GAAI,SAAS,iBAAiB,KAAG,
|
|
1
|
+
{"version":3,"file":"harness-mcp.d.ts","sourceRoot":"","sources":["../src/harness-mcp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EACV,UAAU,EACV,iBAAiB,EAElB,MAAM,YAAY,CAAC;AAMpB;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gBAAgB,GAAI,SAAS,iBAAiB,KAAG,UAoC7D,CAAC"}
|
package/dist/harness-mcp.js
CHANGED
|
@@ -1,27 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP integration test harness.
|
|
3
3
|
*
|
|
4
|
-
* Builds MCP tools from
|
|
4
|
+
* Builds MCP tools from a graph, invokes them directly (no transport),
|
|
5
5
|
* and returns the MCP tool response.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import { deriveMcpTools } from '@ontrails/mcp';
|
|
8
8
|
// ---------------------------------------------------------------------------
|
|
9
9
|
// createMcpHarness
|
|
10
10
|
// ---------------------------------------------------------------------------
|
|
11
11
|
/**
|
|
12
12
|
* Create an MCP harness for integration testing.
|
|
13
13
|
*
|
|
14
|
-
* Builds MCP tools from the
|
|
14
|
+
* Builds MCP tools from the graph's topo and provides a `callTool()` method
|
|
15
15
|
* that invokes tools directly without any transport boundary.
|
|
16
16
|
*
|
|
17
17
|
* ```ts
|
|
18
|
-
* const harness = createMcpHarness({
|
|
18
|
+
* const harness = createMcpHarness({ graph });
|
|
19
19
|
* const result = await harness.callTool("myapp_entity_show", { name: "Alpha" });
|
|
20
20
|
* expect(result.isError).toBe(false);
|
|
21
21
|
* ```
|
|
22
22
|
*/
|
|
23
23
|
export const createMcpHarness = (options) => {
|
|
24
|
-
const
|
|
24
|
+
const { extra, graph, ...deriveOptions } = options;
|
|
25
|
+
const toolsResult = deriveMcpTools(graph, deriveOptions);
|
|
25
26
|
if (toolsResult.isErr()) {
|
|
26
27
|
throw toolsResult.error;
|
|
27
28
|
}
|
|
@@ -39,9 +40,9 @@ export const createMcpHarness = (options) => {
|
|
|
39
40
|
};
|
|
40
41
|
}
|
|
41
42
|
const result = await tool.handler(args, {
|
|
42
|
-
abortSignal:
|
|
43
|
-
progressToken:
|
|
44
|
-
sendProgress:
|
|
43
|
+
abortSignal: extra?.abortSignal,
|
|
44
|
+
progressToken: extra?.progressToken,
|
|
45
|
+
sendProgress: extra?.sendProgress,
|
|
45
46
|
});
|
|
46
47
|
return {
|
|
47
48
|
content: result.content,
|
package/dist/harness-mcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"harness-mcp.js","sourceRoot":"","sources":["../src/harness-mcp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"harness-mcp.js","sourceRoot":"","sources":["../src/harness-mcp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAS/C,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAA0B,EAAc,EAAE;IACzE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,aAAa,EAAE,GAAG,OAAO,CAAC;IACnD,MAAM,WAAW,GAAG,cAAc,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IACzD,IAAI,WAAW,CAAC,KAAK,EAAE,EAAE,CAAC;QACxB,MAAM,WAAW,CAAC,KAAK,CAAC;IAC1B,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,GAAG,EAA6B,CAAC;IACrD,KAAK,MAAM,IAAI,IAAI,WAAW,CAAC,KAAK,EAAE,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC/B,CAAC;IAED,OAAO;QACL,KAAK,CAAC,QAAQ,CACZ,IAAY,EACZ,IAA6B;YAE7B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACvB,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;oBAC1D,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;gBACtC,WAAW,EAAE,KAAK,EAAE,WAAW;gBAC/B,aAAa,EAAE,KAAK,EAAE,aAAa;gBACnC,YAAY,EAAE,KAAK,EAAE,YAAY;aAClC,CAAC,CAAC;YAEH,OAAO;gBACL,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,KAAK;aACjC,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
export { testAll } from './all.js';
|
|
2
|
+
export { testAllEstablished } from './all.js';
|
|
2
3
|
export { testExamples } from './examples.js';
|
|
3
4
|
export { testCrosses } from './crosses.js';
|
|
4
5
|
export { testTrail } from './trail.js';
|
|
5
6
|
export { testContracts } from './contracts.js';
|
|
6
7
|
export { testDetours } from './detours.js';
|
|
7
|
-
export { assertErrorMatch, assertFullMatch, assertSchemaMatch, expectErr, expectOk, } from './assertions.js';
|
|
8
|
-
export {
|
|
8
|
+
export { assertErrorMatch, assertFullMatch, assertPartialMatch, assertSchemaMatch, errResultMatch, expectErr, expectOk, okResultMatch, } from './assertions.js';
|
|
9
|
+
export { executeScenarioSteps, ref, scenario } from './scenario.js';
|
|
10
|
+
export { createCrossContext, createTestContext, defaultCreatePermit, } from './context.js';
|
|
9
11
|
export { createTestLogger } from './logger.js';
|
|
10
12
|
export { createCliHarness } from './harness-cli.js';
|
|
11
13
|
export { createMcpHarness } from './harness-mcp.js';
|
|
12
14
|
export type { CreateCrossContextOptions } from './context.js';
|
|
13
|
-
export type {
|
|
15
|
+
export type { PermittedTrail, MinimalPermit, TestExecutionOptions, } from './context.js';
|
|
14
16
|
export type { TestCrossOptions } from './crosses.js';
|
|
15
|
-
export type { CrossScenario, TestScenario, TestLogger, TestTrailContextOptions, CliHarness, CliHarnessOptions, CliHarnessResult, McpHarness, McpHarnessOptions, McpHarnessResult, } from './types.js';
|
|
17
|
+
export type { CrossScenario, RefToken, ScenarioStep, TestAllEstablishedOptions, TestScenario, TestLogger, TestTrailContextOptions, CliHarness, CliHarnessOptions, CliHarnessResult, McpHarness, McpHarnessOptions, McpHarnessResult, } from './types.js';
|
|
16
18
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAG3C,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,SAAS,EACT,QAAQ,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAG3C,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,SAAS,EACT,QAAQ,EACR,aAAa,GACd,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,oBAAoB,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGpE,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGpD,YAAY,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAC9D,YAAY,EACV,cAAc,EACd,aAAa,EACb,oBAAoB,GACrB,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,YAAY,EACV,aAAa,EACb,QAAQ,EACR,YAAY,EACZ,yBAAyB,EACzB,YAAY,EACZ,UAAU,EACV,uBAAuB,EACvB,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
// Contract-driven testing
|
|
2
2
|
export { testAll } from './all.js';
|
|
3
|
+
export { testAllEstablished } from './all.js';
|
|
3
4
|
export { testExamples } from './examples.js';
|
|
4
5
|
export { testCrosses } from './crosses.js';
|
|
5
6
|
export { testTrail } from './trail.js';
|
|
6
7
|
export { testContracts } from './contracts.js';
|
|
7
8
|
export { testDetours } from './detours.js';
|
|
8
9
|
// Assertions
|
|
9
|
-
export { assertErrorMatch, assertFullMatch, assertSchemaMatch, expectErr, expectOk, } from './assertions.js';
|
|
10
|
+
export { assertErrorMatch, assertFullMatch, assertPartialMatch, assertSchemaMatch, errResultMatch, expectErr, expectOk, okResultMatch, } from './assertions.js';
|
|
11
|
+
// Scenario testing
|
|
12
|
+
export { executeScenarioSteps, ref, scenario } from './scenario.js';
|
|
10
13
|
// Mock factories
|
|
11
|
-
export { createCrossContext, createTestContext,
|
|
14
|
+
export { createCrossContext, createTestContext, defaultCreatePermit, } from './context.js';
|
|
12
15
|
export { createTestLogger } from './logger.js';
|
|
13
16
|
// Trailhead harnesses
|
|
14
17
|
export { createCliHarness } from './harness-cli.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,aAAa;AACb,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,SAAS,EACT,QAAQ,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,aAAa;AACb,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,SAAS,EACT,QAAQ,EACR,aAAa,GACd,MAAM,iBAAiB,CAAC;AAEzB,mBAAmB;AACnB,OAAO,EAAE,oBAAoB,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEpE,iBAAiB;AACjB,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,sBAAsB;AACtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-step scenario runner for composition testing.
|
|
3
|
+
*
|
|
4
|
+
* Scenarios express multi-trail flows as structured data — arrays of steps
|
|
5
|
+
* with cross-step references via `ref()`. Each step invokes a trail through
|
|
6
|
+
* the normal execution pipeline (validation, layers, blaze, Result).
|
|
7
|
+
*/
|
|
8
|
+
import type { Topo } from '@ontrails/core';
|
|
9
|
+
import type { RefToken, ScenarioStep } from './types.js';
|
|
10
|
+
/**
|
|
11
|
+
* Create a reference marker for cross-step data in scenario inputs.
|
|
12
|
+
*
|
|
13
|
+
* `ref('create.id')` resolves to the `id` field of the step aliased as
|
|
14
|
+
* `create`. Dot-paths are supported for nested access.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* scenario('Fork flow', app, [
|
|
19
|
+
* { cross: createGist, input: { name: 'Hello' }, as: 'original' },
|
|
20
|
+
* { cross: forkGist, input: { id: ref('original.id') } },
|
|
21
|
+
* ]);
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare const ref: (path: string) => RefToken;
|
|
25
|
+
/**
|
|
26
|
+
* Recursively walk a value, replacing RefToken instances with resolved values.
|
|
27
|
+
*/
|
|
28
|
+
export declare const deriveRefs: (value: unknown, outputs: Map<string, unknown>) => unknown;
|
|
29
|
+
/**
|
|
30
|
+
* Execute scenario steps sequentially, resolving mock resources once upfront.
|
|
31
|
+
*
|
|
32
|
+
* Exported for direct use in tests that need to assert on step execution
|
|
33
|
+
* without the describe/test wrapper that `scenario()` provides.
|
|
34
|
+
*/
|
|
35
|
+
export declare const executeScenarioSteps: (app: Topo, steps: readonly ScenarioStep[]) => Promise<void>;
|
|
36
|
+
export declare const scenario: (name: string, app: Topo, steps: readonly ScenarioStep[]) => void;
|
|
37
|
+
//# sourceMappingURL=scenario.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scenario.d.ts","sourceRoot":"","sources":["../src/scenario.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAMV,IAAI,EACL,MAAM,gBAAgB,CAAC;AAexB,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AASzD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,GAAG,GAAI,MAAM,MAAM,KAAG,QAAmC,CAAC;AA6DvE;;GAEG;AACH,eAAO,MAAM,UAAU,GACrB,OAAO,OAAO,EACd,SAAS,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,OAkBF,CAAC;AAyMF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAC/B,KAAK,IAAI,EACT,OAAO,SAAS,YAAY,EAAE,KAC7B,OAAO,CAAC,IAAI,CAOd,CAAC;AAEF,eAAO,MAAM,QAAQ,GACnB,MAAM,MAAM,EACZ,KAAK,IAAI,EACT,OAAO,SAAS,YAAY,EAAE,KAC7B,IAMF,CAAC"}
|
package/dist/scenario.js
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-step scenario runner for composition testing.
|
|
3
|
+
*
|
|
4
|
+
* Scenarios express multi-trail flows as structured data — arrays of steps
|
|
5
|
+
* with cross-step references via `ref()`. Each step invokes a trail through
|
|
6
|
+
* the normal execution pipeline (validation, layers, blaze, Result).
|
|
7
|
+
*/
|
|
8
|
+
import { describe, test } from 'bun:test';
|
|
9
|
+
import { buildCrossValidationSchema, executeTrail, InternalError, Result as R, } from '@ontrails/core';
|
|
10
|
+
import { claimNextCrossBatchIndex, createCrossBatchValidationResults, normalizeCrossBatchConcurrency, } from '@ontrails/core/internal/cross-batch';
|
|
11
|
+
import { assertPartialMatch, expectOk } from './assertions.js';
|
|
12
|
+
import { createTestContext, createMockResources } from './context.js';
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// ref() — cross-step reference marker
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
/**
|
|
17
|
+
* Create a reference marker for cross-step data in scenario inputs.
|
|
18
|
+
*
|
|
19
|
+
* `ref('create.id')` resolves to the `id` field of the step aliased as
|
|
20
|
+
* `create`. Dot-paths are supported for nested access.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* scenario('Fork flow', app, [
|
|
25
|
+
* { cross: createGist, input: { name: 'Hello' }, as: 'original' },
|
|
26
|
+
* { cross: forkGist, input: { id: ref('original.id') } },
|
|
27
|
+
* ]);
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export const ref = (path) => ({ __ref: true, path });
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Internals
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
/** Type guard for RefToken. */
|
|
35
|
+
const isRef = (value) => typeof value === 'object' &&
|
|
36
|
+
value !== null &&
|
|
37
|
+
'__ref' in value &&
|
|
38
|
+
value['__ref'] === true &&
|
|
39
|
+
'path' in value;
|
|
40
|
+
/**
|
|
41
|
+
* Resolve a dot-path against the outputs map.
|
|
42
|
+
*
|
|
43
|
+
* `ref('create.id')` splits into step name `create` and field path `id`.
|
|
44
|
+
* The first segment is the step alias; remaining segments are property lookups.
|
|
45
|
+
*/
|
|
46
|
+
/**
|
|
47
|
+
* Walk remaining segments of a dot-path, drilling into the step output.
|
|
48
|
+
*/
|
|
49
|
+
const drillPath = (path, segments, start) => {
|
|
50
|
+
let current = start;
|
|
51
|
+
for (let i = 1; i < segments.length; i += 1) {
|
|
52
|
+
const segment = segments[i];
|
|
53
|
+
if (segment === undefined) {
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
if (typeof current !== 'object' || current === null) {
|
|
57
|
+
throw new Error(`ref('${path}'): cannot access '${segment}' on ${typeof current}`);
|
|
58
|
+
}
|
|
59
|
+
current = current[segment];
|
|
60
|
+
}
|
|
61
|
+
return current;
|
|
62
|
+
};
|
|
63
|
+
const resolvePath = (path, outputs) => {
|
|
64
|
+
const segments = path.split('.');
|
|
65
|
+
const [stepName] = segments;
|
|
66
|
+
if (stepName === undefined) {
|
|
67
|
+
throw new Error(`ref(): empty path`);
|
|
68
|
+
}
|
|
69
|
+
const stepOutput = outputs.get(stepName);
|
|
70
|
+
if (stepOutput === undefined) {
|
|
71
|
+
throw new Error(`ref('${path}'): no step output found for alias '${stepName}'`);
|
|
72
|
+
}
|
|
73
|
+
return drillPath(path, segments, stepOutput);
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Recursively walk a value, replacing RefToken instances with resolved values.
|
|
77
|
+
*/
|
|
78
|
+
export const deriveRefs = (value, outputs) => {
|
|
79
|
+
if (isRef(value)) {
|
|
80
|
+
return resolvePath(value.path, outputs);
|
|
81
|
+
}
|
|
82
|
+
if (Array.isArray(value)) {
|
|
83
|
+
return value.map((item) => deriveRefs(item, outputs));
|
|
84
|
+
}
|
|
85
|
+
if (typeof value === 'object' && value !== null) {
|
|
86
|
+
const result = {};
|
|
87
|
+
for (const [key, val] of Object.entries(value)) {
|
|
88
|
+
result[key] = deriveRefs(val, outputs);
|
|
89
|
+
}
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
return value;
|
|
93
|
+
};
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
// scenario() — the public API
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
/**
|
|
98
|
+
* Define a multi-step scenario test for composition flows.
|
|
99
|
+
*
|
|
100
|
+
* Each step invokes a trail through the normal execution pipeline.
|
|
101
|
+
* Steps can reference prior step outputs via `ref()`. If any step
|
|
102
|
+
* fails, the scenario stops and reports which step failed.
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```typescript
|
|
106
|
+
* scenario('Create and show', app, [
|
|
107
|
+
* { cross: createItem, input: { name: 'Test' }, as: 'created' },
|
|
108
|
+
* { cross: showItem, input: { id: ref('created.id') },
|
|
109
|
+
* expectedMatch: { found: true } },
|
|
110
|
+
* ]);
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
/** Assert the result of a step against its expectations and record output. */
|
|
114
|
+
const assertStepExpectations = async (step, result, outputs) => {
|
|
115
|
+
const value = expectOk(result);
|
|
116
|
+
if (step.expected !== undefined) {
|
|
117
|
+
const { expect } = await import('bun:test');
|
|
118
|
+
expect(value).toEqual(deriveRefs(step.expected, outputs));
|
|
119
|
+
}
|
|
120
|
+
else if (step.expectedMatch !== undefined) {
|
|
121
|
+
assertPartialMatch(result, deriveRefs(step.expectedMatch, outputs));
|
|
122
|
+
}
|
|
123
|
+
if (step.as !== undefined) {
|
|
124
|
+
outputs.set(step.as, value);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
const executeUnlimitedCrossBatch = async (calls, runCall) => await Promise.all(calls.map((call, branchIndex) => runCall(call, branchIndex)));
|
|
128
|
+
const executeLimitedCrossBatch = async (calls, runCall, limit) => {
|
|
129
|
+
const results = Array.from({ length: calls.length });
|
|
130
|
+
const nextIndex = { value: 0 };
|
|
131
|
+
const runWorker = async () => {
|
|
132
|
+
while (true) {
|
|
133
|
+
const branchIndex = claimNextCrossBatchIndex(nextIndex, calls);
|
|
134
|
+
if (branchIndex === undefined) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const call = calls[branchIndex];
|
|
138
|
+
if (call === undefined) {
|
|
139
|
+
// Defensive: `claimNextCrossBatchIndex` only returns indices within
|
|
140
|
+
// bounds, so this slot should always be populated. If it ever isn't,
|
|
141
|
+
// surface a clear InternalError in place of the missing slot and keep
|
|
142
|
+
// the worker loop running so sibling branches still get processed.
|
|
143
|
+
results[branchIndex] = R.err(new InternalError(`unreachable: concurrent cross batch call missing at index ${branchIndex}`));
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
results[branchIndex] = await runCall(call, branchIndex);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
await Promise.all(Array.from({ length: limit }, runWorker));
|
|
150
|
+
return results;
|
|
151
|
+
};
|
|
152
|
+
/**
|
|
153
|
+
* Build a cross function that resolves trails from the topo and executes
|
|
154
|
+
* them through the standard pipeline. Mirrors the pattern in crosses.ts
|
|
155
|
+
* `executeFromMap` but without recording or injection.
|
|
156
|
+
*/
|
|
157
|
+
const createScenarioCross = (app, resources) => {
|
|
158
|
+
const invokeCross = async (idOrTrail, input, self) => {
|
|
159
|
+
const id = typeof idOrTrail === 'string' ? idOrTrail : idOrTrail.id;
|
|
160
|
+
const trailDef = app.get(id);
|
|
161
|
+
if (trailDef === undefined) {
|
|
162
|
+
return R.err(new InternalError(`cross: trail "${id}" not found in topo`));
|
|
163
|
+
}
|
|
164
|
+
const baseCtx = createTestContext();
|
|
165
|
+
return await executeTrail(trailDef, input, {
|
|
166
|
+
ctx: { ...baseCtx, cross: self },
|
|
167
|
+
resources,
|
|
168
|
+
topo: app,
|
|
169
|
+
validationSchema: buildCrossValidationSchema(trailDef),
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
const executeCrossBatch = async (calls, self, options) => {
|
|
173
|
+
if (calls.length === 0) {
|
|
174
|
+
return [];
|
|
175
|
+
}
|
|
176
|
+
const concurrency = normalizeCrossBatchConcurrency(options);
|
|
177
|
+
if (concurrency.isErr()) {
|
|
178
|
+
return createCrossBatchValidationResults(calls, concurrency.error);
|
|
179
|
+
}
|
|
180
|
+
const runCall = async ([target, batchInput], _branchIndex) => await invokeCross(target, batchInput, self);
|
|
181
|
+
const limit = concurrency.value ?? calls.length;
|
|
182
|
+
return limit >= calls.length
|
|
183
|
+
? await executeUnlimitedCrossBatch(calls, runCall)
|
|
184
|
+
: await executeLimitedCrossBatch(calls, runCall, limit);
|
|
185
|
+
};
|
|
186
|
+
const cross = async function cross(idOrTrail, inputOrOptions) {
|
|
187
|
+
if (Array.isArray(idOrTrail)) {
|
|
188
|
+
return await executeCrossBatch(idOrTrail, cross, inputOrOptions);
|
|
189
|
+
}
|
|
190
|
+
return await invokeCross(idOrTrail, inputOrOptions, cross);
|
|
191
|
+
};
|
|
192
|
+
return cross;
|
|
193
|
+
};
|
|
194
|
+
/**
|
|
195
|
+
* Execute a single scenario step: run the trail, assert expectations,
|
|
196
|
+
* and record outputs.
|
|
197
|
+
*/
|
|
198
|
+
const executeStep = async (step, index, app, outputs, resources) => {
|
|
199
|
+
if (step.as !== undefined && outputs.has(step.as)) {
|
|
200
|
+
throw new Error(`scenario: duplicate step alias "${step.as}" — each alias must be unique`);
|
|
201
|
+
}
|
|
202
|
+
const scenarioCross = createScenarioCross(app, resources);
|
|
203
|
+
const baseCtx = createTestContext();
|
|
204
|
+
const resolvedInput = deriveRefs(step.input, outputs);
|
|
205
|
+
const result = await executeTrail(step.cross, resolvedInput, {
|
|
206
|
+
ctx: { ...baseCtx, cross: scenarioCross },
|
|
207
|
+
resources,
|
|
208
|
+
topo: app,
|
|
209
|
+
});
|
|
210
|
+
if (result.isErr()) {
|
|
211
|
+
throw new Error(`Step ${String(index + 1)} ("${step.as ?? step.cross.id}") failed: ${result.error.message}`);
|
|
212
|
+
}
|
|
213
|
+
await assertStepExpectations(step, result, outputs);
|
|
214
|
+
};
|
|
215
|
+
/**
|
|
216
|
+
* Execute scenario steps sequentially, resolving mock resources once upfront.
|
|
217
|
+
*
|
|
218
|
+
* Exported for direct use in tests that need to assert on step execution
|
|
219
|
+
* without the describe/test wrapper that `scenario()` provides.
|
|
220
|
+
*/
|
|
221
|
+
export const executeScenarioSteps = async (app, steps) => {
|
|
222
|
+
const outputs = new Map();
|
|
223
|
+
const resources = await createMockResources(app);
|
|
224
|
+
for (const [index, step] of steps.entries()) {
|
|
225
|
+
await executeStep(step, index, app, outputs, resources);
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
export const scenario = (name, app, steps) => {
|
|
229
|
+
describe(name, () => {
|
|
230
|
+
test('executes all steps', async () => {
|
|
231
|
+
await executeScenarioSteps(app, steps);
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
};
|
|
235
|
+
//# sourceMappingURL=scenario.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scenario.js","sourceRoot":"","sources":["../src/scenario.ts"],"names":[],"mappings":"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"}
|