@ontrails/testing 1.0.0-beta.1 → 1.0.0-beta.10

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.
Files changed (49) hide show
  1. package/.turbo/turbo-lint.log +1 -1
  2. package/CHANGELOG.md +138 -0
  3. package/README.md +25 -7
  4. package/dist/context.d.ts +20 -1
  5. package/dist/context.d.ts.map +1 -1
  6. package/dist/context.js +25 -0
  7. package/dist/context.js.map +1 -1
  8. package/dist/contracts.d.ts +1 -1
  9. package/dist/contracts.d.ts.map +1 -1
  10. package/dist/contracts.js +15 -5
  11. package/dist/contracts.js.map +1 -1
  12. package/dist/examples.d.ts +2 -2
  13. package/dist/examples.d.ts.map +1 -1
  14. package/dist/examples.js +43 -55
  15. package/dist/examples.js.map +1 -1
  16. package/dist/follows.d.ts +32 -0
  17. package/dist/follows.d.ts.map +1 -0
  18. package/dist/{hike.js → follows.js} +15 -15
  19. package/dist/follows.js.map +1 -0
  20. package/dist/harness-mcp.d.ts.map +1 -1
  21. package/dist/harness-mcp.js +5 -2
  22. package/dist/harness-mcp.js.map +1 -1
  23. package/dist/index.d.ts +5 -4
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +2 -2
  26. package/dist/index.js.map +1 -1
  27. package/dist/trail.js +1 -1
  28. package/dist/trail.js.map +1 -1
  29. package/dist/types.d.ts +2 -2
  30. package/dist/types.d.ts.map +1 -1
  31. package/package.json +6 -6
  32. package/src/__tests__/context.test.ts +36 -1
  33. package/src/__tests__/contracts.test.ts +30 -4
  34. package/src/__tests__/detours.test.ts +3 -3
  35. package/src/__tests__/examples.test.ts +21 -22
  36. package/src/__tests__/{hike.test.ts → follows.test.ts} +27 -28
  37. package/src/__tests__/trail.test.ts +4 -4
  38. package/src/context.ts +42 -1
  39. package/src/contracts.ts +19 -6
  40. package/src/examples.ts +55 -91
  41. package/src/{hike.ts → follows.ts} +30 -30
  42. package/src/harness-mcp.ts +5 -2
  43. package/src/index.ts +5 -4
  44. package/src/trail.ts +1 -1
  45. package/src/types.ts +3 -3
  46. package/tsconfig.tsbuildinfo +1 -1
  47. package/dist/hike.d.ts +0 -32
  48. package/dist/hike.d.ts.map +0 -1
  49. package/dist/hike.js.map +0 -1
@@ -1,7 +1,7 @@
1
1
  /**
2
- * testHike — composition-aware scenario testing for hikes.
2
+ * testFollows — composition-aware scenario testing for trails with follow.
3
3
  *
4
- * Tests the composition graph: which trails were followed, in what order,
4
+ * Tests the follow graph: which trails were followed, in what order,
5
5
  * and supports failure injection from followed trail examples.
6
6
  */
7
7
  import { describe, expect, test } from 'bun:test';
@@ -50,7 +50,7 @@ const executeFromMap = (id, input, trailsMap, ctx) => {
50
50
  if (validated.isErr()) {
51
51
  return validated;
52
52
  }
53
- return trailDef.implementation(validated.value, ctx);
53
+ return trailDef.run(validated.value, ctx);
54
54
  };
55
55
  // ---------------------------------------------------------------------------
56
56
  // Follow factory
@@ -81,7 +81,7 @@ const createRecordingFollow = (trace, scenario, trailsMap, baseFollow, ctx) => {
81
81
  // ---------------------------------------------------------------------------
82
82
  // Scenario assertions
83
83
  // ---------------------------------------------------------------------------
84
- const assertScenarioResult = (result, scenario, hikeDef) => {
84
+ const assertScenarioResult = (result, scenario, trailDef) => {
85
85
  if (scenario.expectValue !== undefined) {
86
86
  assertFullMatch(result, scenario.expectValue);
87
87
  }
@@ -96,7 +96,7 @@ const assertScenarioResult = (result, scenario, hikeDef) => {
96
96
  }
97
97
  else if (scenario.expectOk === true) {
98
98
  expect(result.isOk()).toBe(true);
99
- assertSchemaMatch(result, hikeDef.output);
99
+ assertSchemaMatch(result, trailDef.output);
100
100
  }
101
101
  };
102
102
  const assertFollowTrace = (trace, scenario) => {
@@ -134,22 +134,22 @@ const buildTestContext = (scenario, ctx, trailsMap) => {
134
134
  const follow = createRecordingFollow(trace, scenario, trailsMap, baseCtx.follow, baseCtx);
135
135
  return { testCtx: { ...baseCtx, follow }, trace };
136
136
  };
137
- const runScenario = async (hikeDef, scenario, ctx, trailsMap) => {
138
- const validated = validateInput(hikeDef.input, scenario.input);
137
+ const runScenario = async (trailDef, scenario, ctx, trailsMap) => {
138
+ const validated = validateInput(trailDef.input, scenario.input);
139
139
  if (handleValidationError(validated, scenario)) {
140
140
  return;
141
141
  }
142
142
  const { trace, testCtx } = buildTestContext(scenario, ctx, trailsMap);
143
- const result = await hikeDef.implementation(expectOk(validated), testCtx);
143
+ const result = await trailDef.run(expectOk(validated), testCtx);
144
144
  assertFollowTrace(trace, scenario);
145
- assertScenarioResult(result, scenario, hikeDef);
145
+ assertScenarioResult(result, scenario, trailDef);
146
146
  };
147
147
  /**
148
- * Generate a describe block for a hike with one test per scenario.
148
+ * Generate a describe block for a composition trail with one test per scenario.
149
149
  *
150
150
  * @example
151
151
  * ```ts
152
- * testHike(onboardHike, [
152
+ * testFollows(onboardTrail, [
153
153
  * {
154
154
  * description: "follows add then relate",
155
155
  * input: { name: "Alpha" },
@@ -159,11 +159,11 @@ const runScenario = async (hikeDef, scenario, ctx, trailsMap) => {
159
159
  * ]);
160
160
  * ```
161
161
  */
162
- export const testHike = (hikeDef, scenarios, options) => {
163
- describe(hikeDef.id, () => {
162
+ export const testFollows = (trailDef, scenarios, options) => {
163
+ describe(trailDef.id, () => {
164
164
  test.each([...scenarios])('$description', async (scenario) => {
165
- await runScenario(hikeDef, scenario, options?.ctx, options?.trails);
165
+ await runScenario(trailDef, scenario, options?.ctx, options?.trails);
166
166
  });
167
167
  });
168
168
  };
169
- //# sourceMappingURL=hike.js.map
169
+ //# sourceMappingURL=follows.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"follows.js","sourceRoot":"","sources":["../src/follows.ts"],"names":[],"mappings":"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"}
@@ -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,UAgC7D,CAAC"}
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,UAmC7D,CAAC"}
@@ -21,9 +21,12 @@ import { buildMcpTools } from '@ontrails/mcp';
21
21
  * ```
22
22
  */
23
23
  export const createMcpHarness = (options) => {
24
- const tools = buildMcpTools(options.app);
24
+ const toolsResult = buildMcpTools(options.app);
25
+ if (toolsResult.isErr()) {
26
+ throw toolsResult.error;
27
+ }
25
28
  const toolMap = new Map();
26
- for (const tool of tools) {
29
+ for (const tool of toolsResult.value) {
27
30
  toolMap.set(tool.name, tool);
28
31
  }
29
32
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"harness-mcp.js","sourceRoot":"","sources":["../src/harness-mcp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAS9C,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAA0B,EAAc,EAAE;IACzE,MAAM,KAAK,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,IAAI,GAAG,EAA6B,CAAC;IACrD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,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,aAAa,EAAE,SAAS;gBACxB,YAAY,EAAE,SAAS;gBACvB,MAAM,EAAE,SAAS;aAClB,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"}
1
+ {"version":3,"file":"harness-mcp.js","sourceRoot":"","sources":["../src/harness-mcp.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAS9C,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAA0B,EAAc,EAAE;IACzE,MAAM,WAAW,GAAG,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/C,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,aAAa,EAAE,SAAS;gBACxB,YAAY,EAAE,SAAS;gBACvB,MAAM,EAAE,SAAS;aAClB,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,14 +1,15 @@
1
1
  export { testAll } from './all.js';
2
2
  export { testExamples } from './examples.js';
3
- export { testHike } from './hike.js';
3
+ export { testFollows } from './follows.js';
4
4
  export { testTrail } from './trail.js';
5
5
  export { testContracts } from './contracts.js';
6
6
  export { testDetours } from './detours.js';
7
7
  export { assertErrorMatch, assertFullMatch, assertSchemaMatch, expectErr, expectOk, } from './assertions.js';
8
- export { createTestContext } from './context.js';
8
+ export { createFollowContext, createTestContext } from './context.js';
9
9
  export { createTestLogger } from './logger.js';
10
10
  export { createCliHarness } from './harness-cli.js';
11
11
  export { createMcpHarness } from './harness-mcp.js';
12
- export type { TestHikeOptions } from './hike.js';
13
- export type { HikeScenario, TestScenario, TestLogger, TestTrailContextOptions, CliHarness, CliHarnessOptions, CliHarnessResult, McpHarness, McpHarnessOptions, McpHarnessResult, } from './types.js';
12
+ export type { CreateFollowContextOptions } from './context.js';
13
+ export type { TestFollowOptions } from './follows.js';
14
+ export type { FollowScenario, TestScenario, TestLogger, TestTrailContextOptions, CliHarness, CliHarnessOptions, CliHarnessResult, McpHarness, McpHarnessOptions, McpHarnessResult, } from './types.js';
14
15
  //# sourceMappingURL=index.d.ts.map
@@ -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,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,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,GACT,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,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,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjD,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,uBAAuB,EACvB,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,UAAU,EACV,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,YAAY,CAAC"}
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,GACT,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtE,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,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAC/D,YAAY,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEtD,YAAY,EACV,cAAc,EACd,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,14 @@
1
1
  // Contract-driven testing
2
2
  export { testAll } from './all.js';
3
3
  export { testExamples } from './examples.js';
4
- export { testHike } from './hike.js';
4
+ export { testFollows } from './follows.js';
5
5
  export { testTrail } from './trail.js';
6
6
  export { testContracts } from './contracts.js';
7
7
  export { testDetours } from './detours.js';
8
8
  // Assertions
9
9
  export { assertErrorMatch, assertFullMatch, assertSchemaMatch, expectErr, expectOk, } from './assertions.js';
10
10
  // Mock factories
11
- export { createTestContext } from './context.js';
11
+ export { createFollowContext, createTestContext } from './context.js';
12
12
  export { createTestLogger } from './logger.js';
13
13
  // Surface harnesses
14
14
  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,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,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,GACT,MAAM,iBAAiB,CAAC;AAEzB,iBAAiB;AACjB,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,oBAAoB;AACpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
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,GACT,MAAM,iBAAiB,CAAC;AAEzB,iBAAiB;AACjB,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,oBAAoB;AACpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/trail.js CHANGED
@@ -54,7 +54,7 @@ const runScenario = async (trailDef, scenario, ctx) => {
54
54
  return;
55
55
  }
56
56
  const validatedInput = expectOk(validated);
57
- const result = await trailDef.implementation(validatedInput, testCtx);
57
+ const result = await trailDef.run(validatedInput, testCtx);
58
58
  assertScenarioResult(result, scenario, trailDef);
59
59
  };
60
60
  // ---------------------------------------------------------------------------
package/dist/trail.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"trail.js","sourceRoot":"","sources":["../src/trail.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAGlD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEhE,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,QAAQ,GACT,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGhD,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,MAAM,oBAAoB,GAAG,CAC3B,MAA8B,EAC9B,QAAsB,EACtB,QAAkB,EACZ,EAAE;IACR,IAAI,QAAQ,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QACvC,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC;IAChD,CAAC;SAAM,IAAI,QAAQ,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5C,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;IAC1E,CAAC;SAAM,IAAI,QAAQ,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;QACnD,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC;YACnB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;SAAM,IAAI,QAAQ,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjC,iBAAiB,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,qBAAqB,GAAG,CAC5B,SAAiC,EACjC,QAAsB,EACb,EAAE;IACX,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,QAAQ,CAAC,SAAS,KAAK,eAAe,EAAE,CAAC;QAC3C,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;QACxD,IAAI,QAAQ,CAAC,gBAAgB,KAAK,SAAS,EAAE,CAAC;YAC5C,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;QACvE,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,IAAI,KAAK,CACb,yCAAyC,SAAS,CAAC,KAAK,CAAC,OAAO,EAAE,CACnE,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,KAAK,EACvB,QAAkB,EAClB,QAAsB,EACtB,GAAsC,EACvB,EAAE;IACjB,MAAM,OAAO,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,SAAS,GAAG,aAAa,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;IAEhE,IAAI,qBAAqB,CAAC,SAAS,EAAE,QAAQ,CAAC,EAAE,CAAC;QAC/C,OAAO;IACT,CAAC;IACD,MAAM,cAAc,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;IAE3C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,cAAc,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;IACtE,oBAAoB,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;AACnD,CAAC,CAAC;AAEF,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CACvB,QAAkB,EAClB,SAAkC,EAClC,GAA2B,EACrB,EAAE;IACR,QAAQ,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE;QACzB,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CACvB,cAAc,EACd,KAAK,EAAE,QAAsB,EAAE,EAAE;YAC/B,MAAM,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAC;QAC7C,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
1
+ {"version":3,"file":"trail.js","sourceRoot":"","sources":["../src/trail.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -18,8 +18,8 @@ export interface TestScenario {
18
18
  /** Input to pass to the implementation. */
19
19
  readonly input: unknown;
20
20
  }
21
- /** A test scenario for a hike's composition graph. */
22
- export interface HikeScenario extends TestScenario {
21
+ /** A test scenario for a trail's composition graph. */
22
+ export interface FollowScenario extends TestScenario {
23
23
  /** Assert these trail IDs were followed, in order. */
24
24
  readonly expectFollowed?: readonly string[] | undefined;
25
25
  /** Assert follow counts per trail ID. */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ontrails/testing",
3
- "version": "1.0.0-beta.1",
3
+ "version": "1.0.0-beta.10",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./src/index.ts",
@@ -14,10 +14,10 @@
14
14
  "clean": "rm -rf dist *.tsbuildinfo"
15
15
  },
16
16
  "peerDependencies": {
17
- "@ontrails/cli": "workspace:^",
18
- "@ontrails/core": "workspace:^",
19
- "@ontrails/logging": "workspace:^",
20
- "@ontrails/mcp": "workspace:^",
21
- "zod": "catalog:"
17
+ "@ontrails/cli": "^1.0.0-beta.8",
18
+ "@ontrails/core": "^1.0.0-beta.8",
19
+ "@ontrails/logging": "^1.0.0-beta.8",
20
+ "@ontrails/mcp": "^1.0.0-beta.8",
21
+ "zod": "^4.3.5"
22
22
  }
23
23
  }
@@ -1,6 +1,8 @@
1
1
  import { describe, expect, test } from 'bun:test';
2
2
 
3
- import { createTestContext } from '../context.js';
3
+ import { Result } from '@ontrails/core';
4
+
5
+ import { createFollowContext, createTestContext } from '../context.js';
4
6
  import type { TestLogger } from '../types.js';
5
7
 
6
8
  // ---------------------------------------------------------------------------
@@ -58,3 +60,36 @@ describe('createTestContext', () => {
58
60
  expect(env).toEqual({ CUSTOM: '1', NODE_ENV: 'test' });
59
61
  });
60
62
  });
63
+
64
+ describe('createFollowContext', () => {
65
+ test('returns configured ok response for registered id', async () => {
66
+ const follow = createFollowContext({
67
+ responses: { 'entity.add': Result.ok({ id: '1', name: 'Alpha' }) },
68
+ });
69
+ const result = await follow('entity.add', { name: 'Alpha' });
70
+ expect(result.unwrap()).toEqual({ id: '1', name: 'Alpha' });
71
+ });
72
+
73
+ test('returns configured err response for registered id', async () => {
74
+ const err = new Error('conflict');
75
+ const follow = createFollowContext({
76
+ responses: { 'entity.add': Result.err(err) },
77
+ });
78
+ const result = await follow('entity.add', {});
79
+ expect(result.isErr()).toBe(true);
80
+ expect(result.error?.message).toBe('conflict');
81
+ });
82
+
83
+ test('returns err with descriptive message for unregistered id', async () => {
84
+ const follow = createFollowContext();
85
+ const result = await follow('unknown.trail', {});
86
+ expect(result.isErr()).toBe(true);
87
+ expect(result.error?.message).toContain('unknown.trail');
88
+ });
89
+
90
+ test('no options defaults to empty responses', async () => {
91
+ const follow = createFollowContext();
92
+ const result = await follow('any.id', {});
93
+ expect(result.isErr()).toBe(true);
94
+ });
95
+ });
@@ -18,24 +18,43 @@ const validTrail = trail('valid', {
18
18
  name: 'Valid output',
19
19
  },
20
20
  ],
21
- implementation: (input: { name: string }) =>
22
- Result.ok({ id: 1, name: input.name }),
23
21
  input: z.object({ name: z.string() }),
24
22
  output: z.object({ id: z.number(), name: z.string() }),
23
+ run: (input: { name: string }) => Result.ok({ id: 1, name: input.name }),
25
24
  });
26
25
 
27
26
  /** Trail without output schema -- should be skipped. */
28
27
  const noSchemaTrail = trail('noschema', {
29
28
  examples: [{ expected: 10, input: { x: 5 }, name: 'No schema' }],
30
- implementation: (input: { x: number }) => Result.ok(input.x * 2),
31
29
  input: z.object({ x: z.number() }),
30
+ run: (input: { x: number }) => Result.ok(input.x * 2),
32
31
  });
33
32
 
34
33
  /** Trail without examples -- should be skipped. */
35
34
  const noExamplesTrail = trail('noexamples', {
36
- implementation: (input: { x: number }) => Result.ok({ value: input.x }),
37
35
  input: z.object({ x: z.number() }),
38
36
  output: z.object({ value: z.number() }),
37
+ run: (input: { x: number }) => Result.ok({ value: input.x }),
38
+ });
39
+
40
+ // ---------------------------------------------------------------------------
41
+ // Composition trail
42
+ // ---------------------------------------------------------------------------
43
+
44
+ /** Composition trail whose implementation matches the output schema. */
45
+ const compositionTrail = trail('composition.valid', {
46
+ examples: [
47
+ {
48
+ expected: { total: 3 },
49
+ input: { a: 1, b: 2 },
50
+ name: 'Valid composition output',
51
+ },
52
+ ],
53
+ follow: ['valid'],
54
+ input: z.object({ a: z.number(), b: z.number() }),
55
+ output: z.object({ total: z.number() }),
56
+ run: (input: { a: number; b: number }) =>
57
+ Result.ok({ total: input.a + input.b }),
39
58
  });
40
59
 
41
60
  // ---------------------------------------------------------------------------
@@ -66,3 +85,10 @@ describe('testContracts: skips trails without examples', () => {
66
85
  // Trail without examples is skipped -- no contract tests generated
67
86
  });
68
87
  });
88
+
89
+ describe('testContracts: validates composition trail output schemas', () => {
90
+ // eslint-disable-next-line jest/require-hook
91
+ testContracts(
92
+ topo('test-app', { compositionTrail } as Record<string, unknown>)
93
+ );
94
+ });
@@ -13,18 +13,18 @@ const showTrail = trail('entity.show', {
13
13
  detours: {
14
14
  related: ['entity.list'],
15
15
  },
16
- implementation: (input: { id: string }) => Result.ok({ id: input.id }),
17
16
  input: z.object({ id: z.string() }),
17
+ run: (input: { id: string }) => Result.ok({ id: input.id }),
18
18
  });
19
19
 
20
20
  const listTrail = trail('entity.list', {
21
- implementation: () => Result.ok([]),
22
21
  input: z.object({}),
22
+ run: () => Result.ok([]),
23
23
  });
24
24
 
25
25
  const noDetoursTrail = trail('entity.plain', {
26
- implementation: () => Result.ok('ok'),
27
26
  input: z.object({}),
27
+ run: () => Result.ok('ok'),
28
28
  });
29
29
 
30
30
  // ---------------------------------------------------------------------------
@@ -1,6 +1,6 @@
1
1
  import { describe, test } from 'bun:test';
2
2
 
3
- import { NotFoundError, Result, hike, trail, topo } from '@ontrails/core';
3
+ import { NotFoundError, Result, trail, topo } from '@ontrails/core';
4
4
  import { z } from 'zod';
5
5
 
6
6
  import { testExamples } from '../examples.js';
@@ -18,10 +18,10 @@ const greetTrail = trail('greet', {
18
18
  name: 'Greet Alice',
19
19
  },
20
20
  ],
21
- implementation: (input: { name: string }) =>
22
- Result.ok({ greeting: `Hello, ${input.name}` }),
23
21
  input: z.object({ name: z.string() }),
24
22
  output: z.object({ greeting: z.string() }),
23
+ run: (input: { name: string }) =>
24
+ Result.ok({ greeting: `Hello, ${input.name}` }),
25
25
  });
26
26
 
27
27
  const searchTrail = trail('search', {
@@ -32,10 +32,10 @@ const searchTrail = trail('search', {
32
32
  name: 'Schema-only search',
33
33
  },
34
34
  ],
35
- implementation: (input: { query: string }) =>
36
- Result.ok({ results: [`result for ${input.query}`] }),
37
35
  input: z.object({ query: z.string() }),
38
36
  output: z.object({ results: z.array(z.string()) }),
37
+ run: (input: { query: string }) =>
38
+ Result.ok({ results: [`result for ${input.query}`] }),
39
39
  });
40
40
 
41
41
  const entityTrail = trail('entity.show', {
@@ -52,42 +52,41 @@ const entityTrail = trail('entity.show', {
52
52
  name: 'Entity not found returns NotFoundError',
53
53
  },
54
54
  ],
55
- implementation: (input: { name: string }) => {
55
+ input: z.object({ name: z.string() }),
56
+ output: z.object({ id: z.number(), name: z.string() }),
57
+ run: (input: { name: string }) => {
56
58
  if (input.name === 'missing') {
57
59
  return Result.err(new NotFoundError('Entity not found'));
58
60
  }
59
61
  return Result.ok({ id: 1, name: input.name });
60
62
  },
61
- input: z.object({ name: z.string() }),
62
- output: z.object({ id: z.number(), name: z.string() }),
63
63
  });
64
64
 
65
65
  const noExamplesTrail = trail('noexamples', {
66
- implementation: (input: { x: number }) => Result.ok(input.x * 2),
67
66
  input: z.object({ x: z.number() }),
67
+ run: (input: { x: number }) => Result.ok(input.x * 2),
68
68
  });
69
69
 
70
70
  // ---------------------------------------------------------------------------
71
- // Test hikes (for follows coverage)
71
+ // Composition trails (for follow coverage)
72
72
  // ---------------------------------------------------------------------------
73
73
 
74
74
  const addTrail = trail('entity.add', {
75
75
  description: 'Add an entity',
76
- implementation: (input: { name: string }) =>
77
- Result.ok({ id: '1', name: input.name }),
78
76
  input: z.object({ name: z.string() }),
79
77
  output: z.object({ id: z.string(), name: z.string() }),
78
+ run: (input: { name: string }) => Result.ok({ id: '1', name: input.name }),
80
79
  });
81
80
 
82
81
  const relateTrail = trail('entity.relate', {
83
82
  description: 'Relate entities',
84
- implementation: (input: { from: string; to: string }) =>
85
- Result.ok({ from: input.from, to: input.to }),
86
83
  input: z.object({ from: z.string(), to: z.string() }),
87
84
  output: z.object({ from: z.string(), to: z.string() }),
85
+ run: (input: { from: string; to: string }) =>
86
+ Result.ok({ from: input.from, to: input.to }),
88
87
  });
89
88
 
90
- const onboardHike = hike('entity.onboard', {
89
+ const onboardTrail = trail('entity.onboard', {
91
90
  description: 'Onboard a new entity',
92
91
  examples: [
93
92
  {
@@ -96,8 +95,10 @@ const onboardHike = hike('entity.onboard', {
96
95
  name: 'Onboard Alpha',
97
96
  },
98
97
  ],
99
- follows: ['entity.add', 'entity.relate'],
100
- implementation: async (input: { name: string }, ctx) => {
98
+ follow: ['entity.add', 'entity.relate'],
99
+ input: z.object({ name: z.string() }),
100
+ output: z.object({ id: z.string(), name: z.string() }),
101
+ run: async (input: { name: string }, ctx) => {
101
102
  if (!ctx.follow) {
102
103
  return Result.err(new Error('follow not available'));
103
104
  }
@@ -114,8 +115,6 @@ const onboardHike = hike('entity.onboard', {
114
115
  }
115
116
  return Result.ok({ id: '1', name: input.name });
116
117
  },
117
- input: z.object({ name: z.string() }),
118
- output: z.object({ id: z.string(), name: z.string() }),
119
118
  });
120
119
 
121
120
  // ---------------------------------------------------------------------------
@@ -164,12 +163,12 @@ describe('testExamples skips trails with no examples', () => {
164
163
  });
165
164
  });
166
165
 
167
- describe('testExamples follows coverage for hikes', () => {
166
+ describe('testExamples follow coverage for composition trails', () => {
168
167
  // eslint-disable-next-line jest/require-hook
169
168
  testExamples(
170
- topo('hike-app', {
169
+ topo('composition-app', {
171
170
  addTrail,
172
- onboardHike,
171
+ onboardTrail,
173
172
  relateTrail,
174
173
  } as Record<string, unknown>)
175
174
  );
@@ -1,13 +1,13 @@
1
1
  import { describe } from 'bun:test';
2
2
 
3
3
  import type { AnyTrail, TrailContext } from '@ontrails/core';
4
- import { Result, hike, trail } from '@ontrails/core';
4
+ import { Result, trail } from '@ontrails/core';
5
5
  import { z } from 'zod';
6
6
 
7
- import { testHike } from '../hike.js';
7
+ import { testFollows } from '../follows.js';
8
8
 
9
9
  // ---------------------------------------------------------------------------
10
- // Test trails (followed by hikes)
10
+ // Test trails (followed by composition trail)
11
11
  // ---------------------------------------------------------------------------
12
12
 
13
13
  const addTrail = trail('entity.add', {
@@ -21,27 +21,28 @@ const addTrail = trail('entity.add', {
21
21
  name: 'duplicate',
22
22
  },
23
23
  ],
24
- implementation: (input: { name: string }) =>
25
- Result.ok({ id: '1', name: input.name }),
26
24
  input: z.object({ name: z.string() }),
27
25
  output: z.object({ id: z.string(), name: z.string() }),
26
+ run: (input: { name: string }) => Result.ok({ id: '1', name: input.name }),
28
27
  });
29
28
 
30
29
  const relateTrail = trail('entity.relate', {
31
30
  description: 'Relate two entities',
32
- implementation: (input: { from: string; to: string }) =>
33
- Result.ok({ from: input.from, to: input.to }),
34
31
  input: z.object({ from: z.string(), to: z.string() }),
35
32
  output: z.object({ from: z.string(), to: z.string() }),
33
+ run: (input: { from: string; to: string }) =>
34
+ Result.ok({ from: input.from, to: input.to }),
36
35
  });
37
36
 
38
37
  // ---------------------------------------------------------------------------
39
- // Test hike
38
+ // Composition trail
40
39
  // ---------------------------------------------------------------------------
41
40
 
42
- const onboardHike = hike('entity.onboard', {
43
- follows: ['entity.add', 'entity.relate'],
44
- implementation: async (
41
+ const onboardTrail = trail('entity.onboard', {
42
+ follow: ['entity.add', 'entity.relate'],
43
+ input: z.object({ name: z.string(), relatedTo: z.string() }),
44
+ output: z.object({ name: z.string(), relatedTo: z.string() }),
45
+ run: async (
45
46
  input: { name: string; relatedTo: string },
46
47
  ctx: TrailContext
47
48
  ) => {
@@ -69,8 +70,6 @@ const onboardHike = hike('entity.onboard', {
69
70
  relatedTo: relateResult.value.to,
70
71
  });
71
72
  },
72
- input: z.object({ name: z.string(), relatedTo: z.string() }),
73
- output: z.object({ name: z.string(), relatedTo: z.string() }),
74
73
  });
75
74
 
76
75
  const trailsMap = new Map<string, AnyTrail>([
@@ -84,10 +83,10 @@ const trailsMap = new Map<string, AnyTrail>([
84
83
 
85
84
  const opts = { trails: trailsMap };
86
85
 
87
- describe('testHike: expectOk', () => {
86
+ describe('testFollows: expectOk', () => {
88
87
  // eslint-disable-next-line jest/require-hook
89
- testHike(
90
- onboardHike,
88
+ testFollows(
89
+ onboardTrail,
91
90
  [
92
91
  {
93
92
  description: 'basic onboard succeeds',
@@ -99,10 +98,10 @@ describe('testHike: expectOk', () => {
99
98
  );
100
99
  });
101
100
 
102
- describe('testHike: expectFollowed', () => {
101
+ describe('testFollows: expectFollowed', () => {
103
102
  // eslint-disable-next-line jest/require-hook
104
- testHike(
105
- onboardHike,
103
+ testFollows(
104
+ onboardTrail,
106
105
  [
107
106
  {
108
107
  description: 'follows add then relate in order',
@@ -115,10 +114,10 @@ describe('testHike: expectFollowed', () => {
115
114
  );
116
115
  });
117
116
 
118
- describe('testHike: expectFollowedCount', () => {
117
+ describe('testFollows: expectFollowedCount', () => {
119
118
  // eslint-disable-next-line jest/require-hook
120
- testHike(
121
- onboardHike,
119
+ testFollows(
120
+ onboardTrail,
122
121
  [
123
122
  {
124
123
  description: 'each trail followed exactly once',
@@ -131,10 +130,10 @@ describe('testHike: expectFollowedCount', () => {
131
130
  );
132
131
  });
133
132
 
134
- describe('testHike: injectFromExample', () => {
133
+ describe('testFollows: injectFromExample', () => {
135
134
  // eslint-disable-next-line jest/require-hook
136
- testHike(
137
- onboardHike,
135
+ testFollows(
136
+ onboardTrail,
138
137
  [
139
138
  {
140
139
  description: 'inject duplicate error from add trail example',
@@ -148,10 +147,10 @@ describe('testHike: injectFromExample', () => {
148
147
  );
149
148
  });
150
149
 
151
- describe('testHike: expectValue', () => {
150
+ describe('testFollows: expectValue', () => {
152
151
  // eslint-disable-next-line jest/require-hook
153
- testHike(
154
- onboardHike,
152
+ testFollows(
153
+ onboardTrail,
155
154
  [
156
155
  {
157
156
  description: 'exact value match',