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

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.
@@ -1 +1 @@
1
- {"version":3,"file":"follows.js","sourceRoot":"","sources":["../src/follows.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"follows.js","sourceRoot":"","sources":["../src/follows.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -10,6 +10,7 @@ export { createTestLogger } from './logger.js';
10
10
  export { createCliHarness } from './harness-cli.js';
11
11
  export { createMcpHarness } from './harness-mcp.js';
12
12
  export type { CreateFollowContextOptions } from './context.js';
13
+ export type { TestExecutionOptions } from './context.js';
13
14
  export type { TestFollowOptions } from './follows.js';
14
15
  export type { FollowScenario, TestScenario, TestLogger, TestTrailContextOptions, CliHarness, CliHarnessOptions, CliHarnessResult, McpHarness, McpHarnessOptions, McpHarnessResult, } from './types.js';
15
16
  //# 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,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"}
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,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACzD,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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ontrails/testing",
3
- "version": "1.0.0-beta.10",
3
+ "version": "1.0.0-beta.11",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./src/index.ts",
@@ -0,0 +1,64 @@
1
+ import { describe } from 'bun:test';
2
+
3
+ import { Result, service, trail, topo } from '@ontrails/core';
4
+ import { z } from 'zod';
5
+
6
+ import { testAll } from '../all.js';
7
+
8
+ const mockDbService = service('db.mock.all', {
9
+ create: () => Result.ok({ source: 'factory' }),
10
+ mock: () => ({ source: 'mock' }),
11
+ });
12
+
13
+ const mockedTrail = trail('service.mocked.all', {
14
+ description: 'Trail that uses a mocked service through testAll',
15
+ examples: [
16
+ {
17
+ expected: { source: 'mock' },
18
+ input: {},
19
+ name: 'Uses auto-resolved service mock',
20
+ },
21
+ ],
22
+ input: z.object({}),
23
+ output: z.object({ source: z.string() }),
24
+ run: (_input, ctx) => Result.ok({ source: mockDbService.from(ctx).source }),
25
+ services: [mockDbService],
26
+ });
27
+
28
+ const overrideTrail = trail('service.override.all', {
29
+ description: 'Trail that prefers explicit overrides over mock factories',
30
+ examples: [
31
+ {
32
+ expected: { source: 'override' },
33
+ input: {},
34
+ name: 'Explicit service override wins',
35
+ },
36
+ ],
37
+ input: z.object({}),
38
+ output: z.object({ source: z.string() }),
39
+ run: (_input, ctx) => Result.ok({ source: mockDbService.from(ctx).source }),
40
+ services: [mockDbService],
41
+ });
42
+
43
+ describe('testAll service mocks', () => {
44
+ // eslint-disable-next-line jest/require-hook
45
+ testAll(
46
+ topo('test-all-service-mock-app', {
47
+ mockDbService,
48
+ mockedTrail,
49
+ } as Record<string, unknown>)
50
+ );
51
+ });
52
+
53
+ describe('testAll explicit service overrides', () => {
54
+ // eslint-disable-next-line jest/require-hook
55
+ testAll(
56
+ topo('test-all-service-override-app', {
57
+ mockDbService,
58
+ overrideTrail,
59
+ } as Record<string, unknown>),
60
+ {
61
+ services: { 'db.mock.all': { source: 'override' } },
62
+ }
63
+ );
64
+ });
@@ -1,8 +1,13 @@
1
1
  import { describe, expect, test } from 'bun:test';
2
2
 
3
- import { Result } from '@ontrails/core';
3
+ import { Result, service, topo } from '@ontrails/core';
4
4
 
5
- import { createFollowContext, createTestContext } from '../context.js';
5
+ import {
6
+ createFollowContext,
7
+ createTestContext,
8
+ mergeTestContext,
9
+ resolveMockServices,
10
+ } from '../context.js';
6
11
  import type { TestLogger } from '../types.js';
7
12
 
8
13
  // ---------------------------------------------------------------------------
@@ -12,11 +17,12 @@ import type { TestLogger } from '../types.js';
12
17
  describe('createTestContext', () => {
13
18
  test('produces a valid TrailContext with no args', () => {
14
19
  const ctx = createTestContext();
20
+ expect(ctx.cwd).toBe(process.cwd());
15
21
  expect(ctx.requestId).toBe('test-request-001');
16
22
  expect(ctx.signal).toBeDefined();
17
23
  expect(ctx.signal.aborted).toBe(false);
18
24
  expect(ctx.logger).toBeDefined();
19
- expect(ctx.workspaceRoot).toBeDefined();
25
+ expect(ctx.workspaceRoot).toBe(process.cwd());
20
26
  });
21
27
 
22
28
  test('default logger is a TestLogger', () => {
@@ -49,6 +55,7 @@ describe('createTestContext', () => {
49
55
 
50
56
  test('overrides cwd', () => {
51
57
  const ctx = createTestContext({ cwd: '/tmp/test' });
58
+ expect(ctx.cwd).toBe('/tmp/test');
52
59
  expect(ctx.workspaceRoot).toBe('/tmp/test');
53
60
  });
54
61
 
@@ -93,3 +100,51 @@ describe('createFollowContext', () => {
93
100
  expect(result.isErr()).toBe(true);
94
101
  });
95
102
  });
103
+
104
+ describe('mergeTestContext', () => {
105
+ test('merges service overrides into extensions and the service accessor', () => {
106
+ const ctx = mergeTestContext(
107
+ {
108
+ extensions: { existing: true },
109
+ },
110
+ { 'db.main': { source: 'mock' } }
111
+ );
112
+
113
+ expect(ctx.extensions).toEqual({
114
+ 'db.main': { source: 'mock' },
115
+ existing: true,
116
+ });
117
+ expect(ctx.service<{ source: string }>('db.main').source).toBe('mock');
118
+ });
119
+ });
120
+
121
+ describe('resolveMockServices', () => {
122
+ test('creates fresh mock services for each invocation', async () => {
123
+ let mockCalls = 0;
124
+ const mockable = service(`service.mock.${Bun.randomUUIDv7()}`, {
125
+ create: () => Result.ok({ source: 'factory' }),
126
+ mock: () => {
127
+ mockCalls += 1;
128
+ return Promise.resolve({ source: 'mock' });
129
+ },
130
+ });
131
+ const app = topo('mock-app', { mockable } as Record<string, unknown>);
132
+
133
+ const first = await resolveMockServices(app);
134
+ const second = await resolveMockServices(app);
135
+
136
+ expect(first).toEqual({ [mockable.id]: { source: 'mock' } });
137
+ expect(second).toEqual(first);
138
+ expect(second[mockable.id]).not.toBe(first[mockable.id]);
139
+ expect(mockCalls).toBe(2);
140
+ });
141
+
142
+ test('skips services without mock factories', async () => {
143
+ const plain = service(`service.plain.${Bun.randomUUIDv7()}`, {
144
+ create: () => Result.ok({ source: 'factory' }),
145
+ });
146
+ const app = topo('plain-app', { plain } as Record<string, unknown>);
147
+
148
+ expect(await resolveMockServices(app)).toEqual({});
149
+ });
150
+ });
@@ -1,6 +1,6 @@
1
1
  import { describe, test } from 'bun:test';
2
2
 
3
- import { Result, trail, topo } from '@ontrails/core';
3
+ import { Result, service, trail, topo } from '@ontrails/core';
4
4
  import { z } from 'zod';
5
5
 
6
6
  import { testContracts } from '../contracts.js';
@@ -57,6 +57,63 @@ const compositionTrail = trail('composition.valid', {
57
57
  Result.ok({ total: input.a + input.b }),
58
58
  });
59
59
 
60
+ const transformedInputTrail = trail('contract.transformed', {
61
+ examples: [
62
+ {
63
+ expected: { value: 2 },
64
+ input: { value: '1' },
65
+ name: 'Raw contract input is only transformed once',
66
+ },
67
+ ],
68
+ input: z
69
+ .object({ value: z.string() })
70
+ .transform(({ value }) => ({ value: Number(value) + 1 })),
71
+ output: z.object({ value: z.number() }),
72
+ run: (input: { value: number }) => Result.ok({ value: input.value }),
73
+ });
74
+
75
+ const undeclaredContractDbService = service('db.undeclared.contracts', {
76
+ create: () => Result.ok({ source: 'factory' }),
77
+ mock: () => ({ source: 'mock' }),
78
+ });
79
+
80
+ const undeclaredContractTrail = trail('service.undeclared.contracts', {
81
+ examples: [
82
+ {
83
+ expected: { hasInjectedService: false },
84
+ input: {},
85
+ name: 'Undeclared services are not preloaded into contract contexts',
86
+ },
87
+ ],
88
+ input: z.object({}),
89
+ output: z.object({ hasInjectedService: z.literal(false) }),
90
+ run: (_input, ctx) =>
91
+ Result.ok({
92
+ hasInjectedService:
93
+ ctx.extensions?.[undeclaredContractDbService.id] !== undefined,
94
+ }),
95
+ });
96
+
97
+ const ctxOverrideContractService = service('db.mock.contracts', {
98
+ create: () => Result.ok({ source: 'factory' }),
99
+ mock: () => ({ source: 'mock' }),
100
+ });
101
+
102
+ const ctxOverrideContractTrail = trail('service.ctx.contracts', {
103
+ examples: [
104
+ {
105
+ expected: { source: 'ctx' },
106
+ input: {},
107
+ name: 'Context extensions beat auto-resolved contract mocks',
108
+ },
109
+ ],
110
+ input: z.object({}),
111
+ output: z.object({ source: z.literal('ctx') }),
112
+ run: (_input, ctx) =>
113
+ Result.ok({ source: ctxOverrideContractService.from(ctx).source }),
114
+ services: [ctxOverrideContractService],
115
+ });
116
+
60
117
  // ---------------------------------------------------------------------------
61
118
  // Tests
62
119
  // ---------------------------------------------------------------------------
@@ -92,3 +149,37 @@ describe('testContracts: validates composition trail output schemas', () => {
92
149
  topo('test-app', { compositionTrail } as Record<string, unknown>)
93
150
  );
94
151
  });
152
+
153
+ describe('testContracts: raw transformed input', () => {
154
+ // eslint-disable-next-line jest/require-hook
155
+ testContracts(
156
+ topo('transformed-contract-app', {
157
+ transformedInputTrail,
158
+ } as Record<string, unknown>)
159
+ );
160
+ });
161
+
162
+ describe('testContracts: context extension overrides', () => {
163
+ // eslint-disable-next-line jest/require-hook
164
+ testContracts(
165
+ topo('ctx-contract-app', {
166
+ ctxOverrideContractService,
167
+ ctxOverrideContractTrail,
168
+ } as Record<string, unknown>),
169
+ {
170
+ ctx: {
171
+ extensions: { 'db.mock.contracts': { source: 'ctx' } },
172
+ },
173
+ }
174
+ );
175
+ });
176
+
177
+ describe('testContracts service declarations', () => {
178
+ // eslint-disable-next-line jest/require-hook
179
+ testContracts(
180
+ topo('undeclared-contract-service-app', {
181
+ undeclaredContractDbService,
182
+ undeclaredContractTrail,
183
+ } as Record<string, unknown>)
184
+ );
185
+ });
@@ -1,6 +1,6 @@
1
1
  import { describe, test } from 'bun:test';
2
2
 
3
- import { NotFoundError, Result, trail, topo } from '@ontrails/core';
3
+ import { NotFoundError, Result, service, trail, topo } from '@ontrails/core';
4
4
  import { z } from 'zod';
5
5
 
6
6
  import { testExamples } from '../examples.js';
@@ -67,6 +67,136 @@ const noExamplesTrail = trail('noexamples', {
67
67
  run: (input: { x: number }) => Result.ok(input.x * 2),
68
68
  });
69
69
 
70
+ const mockDbService = service('db.mock.examples', {
71
+ create: () => Result.ok({ source: 'factory' }),
72
+ mock: () => ({ source: 'mock' }),
73
+ });
74
+
75
+ const mockServiceTrail = trail('service.mocked', {
76
+ description: 'Trail that reads from a mocked service',
77
+ examples: [
78
+ {
79
+ expected: { source: 'mock' },
80
+ input: {},
81
+ name: 'Uses auto-resolved service mock',
82
+ },
83
+ ],
84
+ input: z.object({}),
85
+ output: z.object({ source: z.string() }),
86
+ run: (_input, ctx) => Result.ok({ source: mockDbService.from(ctx).source }),
87
+ services: [mockDbService],
88
+ });
89
+
90
+ const explicitOverrideTrail = trail('service.override', {
91
+ description: 'Trail whose service mock can be overridden explicitly',
92
+ examples: [
93
+ {
94
+ expected: { source: 'override' },
95
+ input: {},
96
+ name: 'Explicit service override wins over mock factory',
97
+ },
98
+ ],
99
+ input: z.object({}),
100
+ output: z.object({ source: z.string() }),
101
+ run: (_input, ctx) => Result.ok({ source: mockDbService.from(ctx).source }),
102
+ services: [mockDbService],
103
+ });
104
+
105
+ const transformedInputTrail = trail('example.transformed', {
106
+ description: 'Trail whose input schema transforms once',
107
+ examples: [
108
+ {
109
+ expected: { value: 2 },
110
+ input: { value: '1' },
111
+ name: 'Raw example input is only transformed once',
112
+ },
113
+ ],
114
+ input: z
115
+ .object({ value: z.string() })
116
+ .transform(({ value }) => ({ value: Number(value) + 1 })),
117
+ output: z.object({ value: z.number() }),
118
+ run: (input: { value: number }) => Result.ok({ value: input.value }),
119
+ });
120
+
121
+ const ctxOverrideTrail = trail('service.ctx-override', {
122
+ description: 'Trail whose service mock can be overridden by ctx.extensions',
123
+ examples: [
124
+ {
125
+ expected: { source: 'ctx' },
126
+ input: {},
127
+ name: 'Context extensions beat auto-resolved mock services',
128
+ },
129
+ ],
130
+ input: z.object({}),
131
+ output: z.object({ source: z.string() }),
132
+ run: (_input, ctx) => Result.ok({ source: mockDbService.from(ctx).source }),
133
+ services: [mockDbService],
134
+ });
135
+
136
+ const undeclaredDbService = service('db.undeclared.examples', {
137
+ create: () => Result.ok({ source: 'factory' }),
138
+ mock: () => ({ source: 'mock' }),
139
+ });
140
+
141
+ const undeclaredServiceTrail = trail('service.undeclared.examples', {
142
+ description: 'Trail that uses a service without declaring it',
143
+ examples: [
144
+ {
145
+ error: 'InternalError',
146
+ input: {},
147
+ name: 'Undeclared services stay unavailable during example execution',
148
+ },
149
+ ],
150
+ input: z.object({}),
151
+ output: z.object({ source: z.string() }),
152
+ run: (_input, ctx) =>
153
+ Result.ok({ source: undeclaredDbService.from(ctx).source }),
154
+ });
155
+ const followedDbService = service('db.mock.examples.follow', {
156
+ create: () => Result.ok({ source: 'factory' }),
157
+ mock: () => ({ source: 'mock' }),
158
+ });
159
+
160
+ const followedLeafTrail = trail('service.follow.leaf', {
161
+ description: 'Leaf trail that resolves a service inside a follow chain',
162
+ input: z.object({}),
163
+ output: z.object({ childSource: z.string() }),
164
+ run: (_input, ctx) =>
165
+ Result.ok({ childSource: followedDbService.from(ctx).source }),
166
+ services: [followedDbService],
167
+ });
168
+
169
+ const followedRootTrail = trail('service.follow.root', {
170
+ description: 'Root trail that follows a child trail using services',
171
+ examples: [
172
+ {
173
+ expected: { childSource: 'mock', rootSource: 'mock' },
174
+ input: {},
175
+ name: 'Propagates service mocks through follow execution',
176
+ },
177
+ ],
178
+ follow: ['service.follow.leaf'],
179
+ input: z.object({}),
180
+ output: z.object({ childSource: z.string(), rootSource: z.string() }),
181
+ run: async (_input, ctx) => {
182
+ if (!ctx.follow) {
183
+ return Result.err(new Error('follow not available'));
184
+ }
185
+ const childResult = await ctx.follow<{ childSource: string }>(
186
+ 'service.follow.leaf',
187
+ {}
188
+ );
189
+ if (childResult.isErr()) {
190
+ return childResult;
191
+ }
192
+ return Result.ok({
193
+ childSource: childResult.value.childSource,
194
+ rootSource: followedDbService.from(ctx).source,
195
+ });
196
+ },
197
+ services: [followedDbService],
198
+ });
199
+
70
200
  // ---------------------------------------------------------------------------
71
201
  // Composition trails (for follow coverage)
72
202
  // ---------------------------------------------------------------------------
@@ -163,6 +293,63 @@ describe('testExamples skips trails with no examples', () => {
163
293
  });
164
294
  });
165
295
 
296
+ describe('testExamples service mocks', () => {
297
+ // eslint-disable-next-line jest/require-hook
298
+ testExamples(
299
+ topo('service-mock-app', {
300
+ mockDbService,
301
+ mockServiceTrail,
302
+ } as Record<string, unknown>)
303
+ );
304
+ });
305
+
306
+ describe('testExamples explicit service overrides', () => {
307
+ // eslint-disable-next-line jest/require-hook
308
+ testExamples(
309
+ topo('service-override-app', {
310
+ explicitOverrideTrail,
311
+ mockDbService,
312
+ } as Record<string, unknown>),
313
+ {
314
+ services: { 'db.mock.examples': { source: 'override' } },
315
+ }
316
+ );
317
+ });
318
+
319
+ describe('testExamples raw transformed input', () => {
320
+ // eslint-disable-next-line jest/require-hook
321
+ testExamples(
322
+ topo('transformed-input-app', {
323
+ transformedInputTrail,
324
+ } as Record<string, unknown>)
325
+ );
326
+ });
327
+
328
+ describe('testExamples context extension overrides', () => {
329
+ // eslint-disable-next-line jest/require-hook
330
+ testExamples(
331
+ topo('ctx-override-app', {
332
+ ctxOverrideTrail,
333
+ mockDbService,
334
+ } as Record<string, unknown>),
335
+ {
336
+ ctx: {
337
+ extensions: { 'db.mock.examples': { source: 'ctx' } },
338
+ },
339
+ }
340
+ );
341
+ });
342
+
343
+ describe('testExamples service declarations', () => {
344
+ // eslint-disable-next-line jest/require-hook
345
+ testExamples(
346
+ topo('undeclared-service-app', {
347
+ undeclaredDbService,
348
+ undeclaredServiceTrail,
349
+ } as Record<string, unknown>)
350
+ );
351
+ });
352
+
166
353
  describe('testExamples follow coverage for composition trails', () => {
167
354
  // eslint-disable-next-line jest/require-hook
168
355
  testExamples(
@@ -173,3 +360,80 @@ describe('testExamples follow coverage for composition trails', () => {
173
360
  } as Record<string, unknown>)
174
361
  );
175
362
  });
363
+
364
+ describe('testExamples service mocks through follow', () => {
365
+ // eslint-disable-next-line jest/require-hook
366
+ testExamples(
367
+ topo('service-follow-app', {
368
+ followedDbService,
369
+ followedLeafTrail,
370
+ followedRootTrail,
371
+ } as Record<string, unknown>)
372
+ );
373
+ });
374
+
375
+ // ---------------------------------------------------------------------------
376
+ // Nested follow chain: A → B → C
377
+ // ---------------------------------------------------------------------------
378
+
379
+ const leafTrail = trail('step.leaf', {
380
+ description: 'Leaf trail in a nested chain',
381
+ input: z.object({ value: z.string() }),
382
+ output: z.object({ leaf: z.string() }),
383
+ run: (input: { value: string }) => Result.ok({ leaf: input.value }),
384
+ });
385
+
386
+ const middleTrail = trail('step.middle', {
387
+ description: 'Middle trail that follows the leaf',
388
+ follow: ['step.leaf'],
389
+ input: z.object({ value: z.string() }),
390
+ output: z.object({ middle: z.string() }),
391
+ run: async (input: { value: string }, ctx) => {
392
+ if (!ctx.follow) {
393
+ return Result.err(new Error('follow not available'));
394
+ }
395
+ const leafResult = await ctx.follow<{ leaf: string }>('step.leaf', input);
396
+ if (leafResult.isErr()) {
397
+ return leafResult;
398
+ }
399
+ return Result.ok({ middle: leafResult.value.leaf });
400
+ },
401
+ });
402
+
403
+ const rootTrail = trail('step.root', {
404
+ description: 'Root trail that follows the middle trail',
405
+ examples: [
406
+ {
407
+ expected: { root: 'hello' },
408
+ input: { value: 'hello' },
409
+ name: 'Nested follow chain A→B→C',
410
+ },
411
+ ],
412
+ follow: ['step.middle'],
413
+ input: z.object({ value: z.string() }),
414
+ output: z.object({ root: z.string() }),
415
+ run: async (input: { value: string }, ctx) => {
416
+ if (!ctx.follow) {
417
+ return Result.err(new Error('follow not available'));
418
+ }
419
+ const midResult = await ctx.follow<{ middle: string }>(
420
+ 'step.middle',
421
+ input
422
+ );
423
+ if (midResult.isErr()) {
424
+ return midResult;
425
+ }
426
+ return Result.ok({ root: midResult.value.middle });
427
+ },
428
+ });
429
+
430
+ describe('testExamples nested follow chain (A → B → C)', () => {
431
+ // eslint-disable-next-line jest/require-hook
432
+ testExamples(
433
+ topo('nested-chain-app', {
434
+ leafTrail,
435
+ middleTrail,
436
+ rootTrail,
437
+ } as Record<string, unknown>)
438
+ );
439
+ });