@ontrails/testing 1.0.0-beta.0 → 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 +151 -0
  3. package/README.md +56 -168
  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
package/dist/examples.js CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Iterates every trail in the app's topo. For each trail with examples,
5
5
  * generates describe/test blocks using bun:test. Progressive assertion
6
- * determines which check to run per example. For hikes with `follows`
6
+ * determines which check to run per example. For trails with `follow`
7
7
  * declarations, checks that every declared follow was called at least once.
8
8
  */
9
9
  import { describe, expect, test } from 'bun:test';
@@ -75,11 +75,11 @@ const runExample = async (t, example, output, testCtx) => {
75
75
  return;
76
76
  }
77
77
  const validatedInput = expectOk(validated);
78
- const result = await t.implementation(validatedInput, testCtx);
78
+ const result = await t.run(validatedInput, testCtx);
79
79
  assertProgressiveMatch(result, example, output);
80
80
  };
81
81
  // ---------------------------------------------------------------------------
82
- // Follows coverage for hikes
82
+ // Follow coverage for composition trails
83
83
  // ---------------------------------------------------------------------------
84
84
  /**
85
85
  * Build a recording follow function that tracks which trail IDs are called.
@@ -100,67 +100,33 @@ const createCoverageFollow = (called, baseFollow, topo, ctx) => {
100
100
  if (validated.isErr()) {
101
101
  return Promise.resolve(validated);
102
102
  }
103
- return Promise.resolve(trailDef.implementation(validated.value, ctx));
103
+ return Promise.resolve(trailDef.run(validated.value, ctx));
104
104
  }
105
105
  return Promise.resolve(Result.ok());
106
106
  };
107
107
  return follow;
108
108
  };
109
109
  /**
110
- * Run a single example against a hike, recording follow calls.
110
+ * Run a single example against a composition trail, recording follow calls.
111
111
  */
112
- const runHikeExample = async (hikeDef, example, output, baseCtx, called, topo) => {
113
- const validated = validateInput(hikeDef.input, example.input);
112
+ const runCompositionExample = async (trailDef, example, output, baseCtx, called, topo) => {
113
+ const validated = validateInput(trailDef.input, example.input);
114
114
  if (handleValidationError(validated, example)) {
115
115
  return;
116
116
  }
117
117
  const validatedInput = expectOk(validated);
118
118
  const follow = createCoverageFollow(called, baseCtx.follow, topo, baseCtx);
119
119
  const testCtx = { ...baseCtx, follow };
120
- const result = await hikeDef.implementation(validatedInput, testCtx);
120
+ const result = await trailDef.run(validatedInput, testCtx);
121
121
  assertProgressiveMatch(result, example, output);
122
122
  };
123
- const collectHikesWithExamples = (app) => [...app.hikes]
124
- .filter(([, h]) => h.examples !== undefined && h.examples.length > 0)
125
- .map(([hikeId, hikeDef]) => ({
126
- examples: hikeDef.examples,
127
- hikeDef,
128
- hikeId,
129
- }));
130
- // ---------------------------------------------------------------------------
131
- // Hike example describe blocks
132
- // ---------------------------------------------------------------------------
133
- /**
134
- * Generate describe/test blocks for hikes with follows coverage.
135
- *
136
- * Always uses a recording follow so that follows coverage can be checked.
137
- * Hikes without `follows` still run their examples but skip the coverage test.
138
- */
139
- const describeHikeExamples = (hikesWithExamples, resolveCtx, topo) => {
140
- if (hikesWithExamples.length === 0) {
141
- return;
142
- }
143
- describe.each([...hikesWithExamples])('$hikeId', ({ hikeDef, examples }) => {
144
- const called = new Set();
145
- test.each([...examples])('example: $name', async (example) => {
146
- const baseCtx = mergeTestContext(resolveCtx());
147
- await runHikeExample(hikeDef, example, hikeDef.output, baseCtx, called, topo);
148
- });
149
- if (hikeDef.follows.length > 0) {
150
- test('follows coverage', () => {
151
- const uncovered = hikeDef.follows.filter((id) => !called.has(id));
152
- expect(uncovered).toEqual([]);
153
- });
154
- }
155
- });
156
- };
157
123
  // ---------------------------------------------------------------------------
158
124
  // testExamples
159
125
  // ---------------------------------------------------------------------------
160
126
  /**
161
127
  * Generate describe/test blocks for every trail example in the app.
162
128
  *
163
- * For hikes with `follows` declarations and examples, also verifies that
129
+ * For trails with `follow` declarations and examples, also verifies that
164
130
  * every declared follow ID was called at least once across all examples.
165
131
  *
166
132
  * One line in your test file:
@@ -170,18 +136,40 @@ const describeHikeExamples = (hikesWithExamples, resolveCtx, topo) => {
170
136
  */
171
137
  export const testExamples = (app, ctxOrFactory) => {
172
138
  const resolveCtx = typeof ctxOrFactory === 'function' ? ctxOrFactory : () => ctxOrFactory;
173
- const trailEntries = [...app.trails];
174
- describe.each(trailEntries)('%s', (_id, trailDef) => {
175
- const t = trailDef;
176
- if (t.examples === undefined || t.examples.length === 0) {
177
- return;
178
- }
179
- const { examples, output } = t;
180
- test.each([...examples])('example: $name', async (example) => {
181
- const testCtx = mergeTestContext(resolveCtx());
182
- await runExample(t, example, output, testCtx);
139
+ const allTrails = app.list();
140
+ const withExamples = allTrails.filter((t) => t.examples !== undefined && t.examples.length > 0);
141
+ const simpleTrails = withExamples.filter((t) => t.follow.length === 0);
142
+ const compositionTrails = withExamples.filter((t) => t.follow.length > 0);
143
+ // Simple trails: run examples directly
144
+ if (simpleTrails.length > 0) {
145
+ describe.each(simpleTrails)('$id', (t) => {
146
+ const { examples, output } = t;
147
+ if (!examples) {
148
+ return;
149
+ }
150
+ test.each([...examples])('example: $name', async (example) => {
151
+ const testCtx = mergeTestContext(resolveCtx());
152
+ await runExample(t, example, output, testCtx);
153
+ });
183
154
  });
184
- });
185
- describeHikeExamples(collectHikesWithExamples(app), resolveCtx, app);
155
+ }
156
+ // Composition trails: use recording follow and check coverage
157
+ if (compositionTrails.length > 0) {
158
+ describe.each(compositionTrails)('$id', (t) => {
159
+ const { examples, output } = t;
160
+ if (!examples) {
161
+ return;
162
+ }
163
+ const called = new Set();
164
+ test.each([...examples])('example: $name', async (example) => {
165
+ const baseCtx = mergeTestContext(resolveCtx());
166
+ await runCompositionExample(t, example, output, baseCtx, called, app);
167
+ });
168
+ test('follow coverage', () => {
169
+ const uncovered = t.follow.filter((id) => !called.has(id));
170
+ expect(uncovered).toEqual([]);
171
+ });
172
+ });
173
+ }
186
174
  };
187
175
  //# sourceMappingURL=examples.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"examples.js","sourceRoot":"","sources":["../src/examples.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"examples.js","sourceRoot":"","sources":["../src/examples.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * testFollows — composition-aware scenario testing for trails with follow.
3
+ *
4
+ * Tests the follow graph: which trails were followed, in what order,
5
+ * and supports failure injection from followed trail examples.
6
+ */
7
+ import type { AnyTrail, TrailContext } from '@ontrails/core';
8
+ import type { FollowScenario } from './types.js';
9
+ /** Options for testFollows that provide trail definitions for injection. */
10
+ export interface TestFollowOptions {
11
+ /** Partial context overrides. */
12
+ readonly ctx?: Partial<TrailContext> | undefined;
13
+ /** Map of trail ID to trail definition, used for injectFromExample. */
14
+ readonly trails?: ReadonlyMap<string, AnyTrail> | undefined;
15
+ }
16
+ /**
17
+ * Generate a describe block for a composition trail with one test per scenario.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * testFollows(onboardTrail, [
22
+ * {
23
+ * description: "follows add then relate",
24
+ * input: { name: "Alpha" },
25
+ * expectOk: true,
26
+ * expectFollowed: ["entity.add", "entity.relate"],
27
+ * },
28
+ * ]);
29
+ * ```
30
+ */
31
+ export declare const testFollows: (trailDef: AnyTrail, scenarios: readonly FollowScenario[], options?: TestFollowOptions) => void;
32
+ //# sourceMappingURL=follows.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"follows.d.ts","sourceRoot":"","sources":["../src/follows.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAY,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAevE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AA8NjD,4EAA4E;AAC5E,MAAM,WAAW,iBAAiB;IAChC,iCAAiC;IACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,SAAS,CAAC;IACjD,uEAAuE;IACvE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,GAAG,SAAS,CAAC;CAC7D;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,WAAW,GACtB,UAAU,QAAQ,EAClB,WAAW,SAAS,cAAc,EAAE,EACpC,UAAU,iBAAiB,KAC1B,IASF,CAAC"}
@@ -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":"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"}
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.0",
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
  // ---------------------------------------------------------------------------