@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.
- package/.turbo/turbo-lint.log +1 -1
- package/CHANGELOG.md +138 -0
- package/README.md +25 -7
- package/dist/context.d.ts +20 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +25 -0
- package/dist/context.js.map +1 -1
- package/dist/contracts.d.ts +1 -1
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +15 -5
- package/dist/contracts.js.map +1 -1
- package/dist/examples.d.ts +2 -2
- package/dist/examples.d.ts.map +1 -1
- package/dist/examples.js +43 -55
- package/dist/examples.js.map +1 -1
- package/dist/follows.d.ts +32 -0
- package/dist/follows.d.ts.map +1 -0
- package/dist/{hike.js → follows.js} +15 -15
- package/dist/follows.js.map +1 -0
- package/dist/harness-mcp.d.ts.map +1 -1
- package/dist/harness-mcp.js +5 -2
- package/dist/harness-mcp.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/trail.js +1 -1
- package/dist/trail.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/__tests__/context.test.ts +36 -1
- package/src/__tests__/contracts.test.ts +30 -4
- package/src/__tests__/detours.test.ts +3 -3
- package/src/__tests__/examples.test.ts +21 -22
- package/src/__tests__/{hike.test.ts → follows.test.ts} +27 -28
- package/src/__tests__/trail.test.ts +4 -4
- package/src/context.ts +42 -1
- package/src/contracts.ts +19 -6
- package/src/examples.ts +55 -91
- package/src/{hike.ts → follows.ts} +30 -30
- package/src/harness-mcp.ts +5 -2
- package/src/index.ts +5 -4
- package/src/trail.ts +1 -1
- package/src/types.ts +3 -3
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/hike.d.ts +0 -32
- package/dist/hike.d.ts.map +0 -1
- package/dist/hike.js.map +0 -1
package/.turbo/turbo-lint.log
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,143 @@
|
|
|
1
1
|
# @ontrails/testing
|
|
2
2
|
|
|
3
|
+
## 1.0.0-beta.10
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
- @ontrails/core@1.0.0-beta.10
|
|
9
|
+
- @ontrails/cli@1.0.0-beta.10
|
|
10
|
+
- @ontrails/mcp@1.0.0-beta.10
|
|
11
|
+
- @ontrails/logging@1.0.0-beta.10
|
|
12
|
+
|
|
13
|
+
## 1.0.0-beta.9
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- Consolidated improvements across all surface packages.
|
|
18
|
+
|
|
19
|
+
**core**: Add `TrailResult<T>` utility type, `topo.ids()` and `topo.count` accessors, `dispatch()` for headless trail execution, and extract shared `executeTrail` pipeline used by CLI/MCP/HTTP.
|
|
20
|
+
|
|
21
|
+
**http**: Detect route path collisions and return `Result` from `buildHttpRoutes()`, wire request `AbortSignal` through to trail context, and make write → POST mapping explicit in intent-to-method lookup.
|
|
22
|
+
|
|
23
|
+
**mcp**: Return `Result` from `buildMcpTools()` on collision instead of throwing.
|
|
24
|
+
|
|
25
|
+
**cli**: Verify exception catching via centralized `executeTrail`.
|
|
26
|
+
|
|
27
|
+
**testing**: Follow context awareness improvements.
|
|
28
|
+
|
|
29
|
+
**warden**: Refactor rules as composable trails with examples.
|
|
30
|
+
|
|
31
|
+
**schema**: Error code and empty body fixes.
|
|
32
|
+
|
|
33
|
+
### Patch Changes
|
|
34
|
+
|
|
35
|
+
- Updated dependencies
|
|
36
|
+
- @ontrails/core@1.0.0-beta.9
|
|
37
|
+
- @ontrails/cli@1.0.0-beta.9
|
|
38
|
+
- @ontrails/mcp@1.0.0-beta.9
|
|
39
|
+
- @ontrails/logging@1.0.0-beta.9
|
|
40
|
+
|
|
41
|
+
## 1.0.0-beta.8
|
|
42
|
+
|
|
43
|
+
### Patch Changes
|
|
44
|
+
|
|
45
|
+
- @ontrails/cli@1.0.0-beta.8
|
|
46
|
+
- @ontrails/core@1.0.0-beta.8
|
|
47
|
+
- @ontrails/logging@1.0.0-beta.8
|
|
48
|
+
- @ontrails/mcp@1.0.0-beta.8
|
|
49
|
+
|
|
50
|
+
## 1.0.0-beta.7
|
|
51
|
+
|
|
52
|
+
### Patch Changes
|
|
53
|
+
|
|
54
|
+
- @ontrails/cli@1.0.0-beta.7
|
|
55
|
+
- @ontrails/core@1.0.0-beta.7
|
|
56
|
+
- @ontrails/logging@1.0.0-beta.7
|
|
57
|
+
- @ontrails/mcp@1.0.0-beta.7
|
|
58
|
+
|
|
59
|
+
## 1.0.0-beta.6
|
|
60
|
+
|
|
61
|
+
### Patch Changes
|
|
62
|
+
|
|
63
|
+
- Updated dependencies
|
|
64
|
+
- @ontrails/core@1.0.0-beta.6
|
|
65
|
+
- @ontrails/cli@1.0.0-beta.6
|
|
66
|
+
- @ontrails/logging@1.0.0-beta.6
|
|
67
|
+
- @ontrails/mcp@1.0.0-beta.6
|
|
68
|
+
|
|
69
|
+
## 1.0.0-beta.5
|
|
70
|
+
|
|
71
|
+
### Patch Changes
|
|
72
|
+
|
|
73
|
+
- Updated dependencies
|
|
74
|
+
- @ontrails/core@1.0.0-beta.5
|
|
75
|
+
- @ontrails/logging@1.0.0-beta.5
|
|
76
|
+
- @ontrails/cli@1.0.0-beta.5
|
|
77
|
+
- @ontrails/mcp@1.0.0-beta.5
|
|
78
|
+
|
|
79
|
+
## 1.0.0-beta.4
|
|
80
|
+
|
|
81
|
+
### Major Changes
|
|
82
|
+
|
|
83
|
+
- API simplification: unified trail model, intent enum, run, metadata.
|
|
84
|
+
|
|
85
|
+
**BREAKING CHANGES:**
|
|
86
|
+
|
|
87
|
+
- `hike()` removed — use `trail()` with optional `follow: [...]` field
|
|
88
|
+
- `follows` renamed to `follow` (singular, matching `ctx.follow()`)
|
|
89
|
+
- `topo.hikes` removed — single `topo.trails` map
|
|
90
|
+
- `kind: 'hike'` removed — everything is `kind: 'trail'`
|
|
91
|
+
- `readOnly`/`destructive` booleans replaced by `intent: 'read' | 'write' | 'destroy'`
|
|
92
|
+
- `implementation` field renamed to `run`
|
|
93
|
+
- `markers` field renamed to `metadata`
|
|
94
|
+
- `testHike` renamed to `testFollows`, `HikeScenario` to `FollowScenario`
|
|
95
|
+
- `blaze()` now returns the surface handle (`Command` for CLI, `Server` for MCP)
|
|
96
|
+
|
|
97
|
+
### Patch Changes
|
|
98
|
+
|
|
99
|
+
- Updated dependencies
|
|
100
|
+
- @ontrails/core@1.0.0-beta.4
|
|
101
|
+
- @ontrails/cli@1.0.0-beta.4
|
|
102
|
+
- @ontrails/mcp@1.0.0-beta.4
|
|
103
|
+
- @ontrails/logging@1.0.0-beta.4
|
|
104
|
+
|
|
105
|
+
## 1.0.0-beta.3
|
|
106
|
+
|
|
107
|
+
### Minor Changes
|
|
108
|
+
|
|
109
|
+
- Bug fixes across all surface packages found via parallel Codex review.
|
|
110
|
+
|
|
111
|
+
**core**: Fix Result.toJson false circular detection on DAGs, deserializeError subclass round-trip, topo cross-kind ID collisions, validateTopo multi-node cycle detection, error example input validation bypass, and deriveFields array type collapse.
|
|
112
|
+
|
|
113
|
+
**cli**: Switch blaze to parseAsync for proper async error handling, add boolean flag negation (--no-flag), and strict number parsing that rejects partial input.
|
|
114
|
+
|
|
115
|
+
**mcp**: Align BlobRef with core (including ReadableStream support) and detect tool-name collisions after normalization.
|
|
116
|
+
|
|
117
|
+
**testing**: Include hikes in testContracts validation, with follow-context awareness.
|
|
118
|
+
|
|
119
|
+
**warden**: Collect hike detour targets, validate detour refs in hike specs, and stop implementation-returns-result from walking into nested function bodies.
|
|
120
|
+
|
|
121
|
+
### Patch Changes
|
|
122
|
+
|
|
123
|
+
- Updated dependencies
|
|
124
|
+
- @ontrails/core@1.0.0-beta.3
|
|
125
|
+
- @ontrails/cli@1.0.0-beta.3
|
|
126
|
+
- @ontrails/mcp@1.0.0-beta.3
|
|
127
|
+
- @ontrails/logging@1.0.0-beta.3
|
|
128
|
+
|
|
129
|
+
## 1.0.0-beta.2
|
|
130
|
+
|
|
131
|
+
### Patch Changes
|
|
132
|
+
|
|
133
|
+
- Fix workspace dependency resolution in published packages. Now using bun publish
|
|
134
|
+
which correctly replaces workspace:^ with actual version numbers.
|
|
135
|
+
- Updated dependencies
|
|
136
|
+
- @ontrails/core@1.0.0-beta.2
|
|
137
|
+
- @ontrails/cli@1.0.0-beta.2
|
|
138
|
+
- @ontrails/mcp@1.0.0-beta.2
|
|
139
|
+
- @ontrails/logging@1.0.0-beta.2
|
|
140
|
+
|
|
3
141
|
## 1.0.0-beta.1
|
|
4
142
|
|
|
5
143
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -29,10 +29,10 @@ testDetours(app); // Verify detour targets exist
|
|
|
29
29
|
| --- | --- |
|
|
30
30
|
| `testAll(topo, ctx?)` | Single-line governance suite: validation + examples + contracts + detours |
|
|
31
31
|
| `testExamples(topo, ctx?)` | Run trail examples as `describe`/`test` blocks |
|
|
32
|
-
| `testTrail(trail, scenarios)` | Custom scenarios for edge cases
|
|
33
|
-
| `
|
|
34
|
-
| `testContracts(topo, ctx?)` | Validate implementation output against declared schemas |
|
|
32
|
+
| `testTrail(trail, scenarios)` | Custom scenarios for edge cases, error paths, and follow chains |
|
|
33
|
+
| `testContracts(topo, ctx?)` | Validate output against declared schemas |
|
|
35
34
|
| `testDetours(topo)` | Verify every detour target exists in the topo |
|
|
35
|
+
| `createFollowContext(options?)` | Mock `FollowFn` for testing composite trails; returns preconfigured `Result` values keyed by trail ID |
|
|
36
36
|
| `createTestContext(options?)` | `TrailContext` with sensible test defaults |
|
|
37
37
|
| `createTestLogger()` | Logger that captures entries in memory for assertions |
|
|
38
38
|
| `createCliHarness(options)` | Execute CLI commands in-process, capture stdout/stderr |
|
|
@@ -55,19 +55,37 @@ testTrail(showTrail, [
|
|
|
55
55
|
]);
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
##
|
|
58
|
+
## Testing composition (trails with follow)
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
`testTrail` works the same for trails with `follow` -- it exercises the follow graph:
|
|
61
61
|
|
|
62
62
|
```typescript
|
|
63
|
-
import {
|
|
63
|
+
import { testTrail } from '@ontrails/testing';
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
testTrail(onboardTrail, [
|
|
66
66
|
{ description: 'happy path', input: { name: 'Delta', type: 'tool' }, expectOk: true },
|
|
67
67
|
{ description: 'add fails', input: { name: 'Alpha' }, expectErr: AlreadyExistsError },
|
|
68
68
|
]);
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
+
When you need to isolate a composite trail and stub out its dependencies, use `createFollowContext`:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { createFollowContext, createTestContext } from '@ontrails/testing';
|
|
75
|
+
import { Result } from '@ontrails/core';
|
|
76
|
+
|
|
77
|
+
const follow = createFollowContext({
|
|
78
|
+
responses: {
|
|
79
|
+
'entity.add': Result.ok({ id: '1', name: 'Delta', type: 'tool' }),
|
|
80
|
+
'search': Result.ok({ results: [] }),
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
const ctx = { ...createTestContext(), follow };
|
|
84
|
+
const result = await onboardTrail.run({ name: 'Delta', type: 'tool' }, ctx);
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Calls to unregistered trail IDs return `Result.err` with a descriptive message, so missing stubs fail loudly.
|
|
88
|
+
|
|
71
89
|
## Surface harnesses
|
|
72
90
|
|
|
73
91
|
```typescript
|
package/dist/context.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Test context factory for creating TrailContext instances suitable for testing.
|
|
3
3
|
*/
|
|
4
|
-
import type { TrailContext } from '@ontrails/core';
|
|
4
|
+
import type { FollowFn, TrailContext } from '@ontrails/core';
|
|
5
|
+
import { Result } from '@ontrails/core';
|
|
5
6
|
import type { TestTrailContextOptions } from './types.js';
|
|
6
7
|
/**
|
|
7
8
|
* Create a TrailContext with deterministic, test-friendly defaults.
|
|
@@ -11,6 +12,24 @@ import type { TestTrailContextOptions } from './types.js';
|
|
|
11
12
|
* - `signal`: a non-aborted AbortController signal
|
|
12
13
|
*/
|
|
13
14
|
export declare const createTestContext: (overrides?: TestTrailContextOptions) => TrailContext;
|
|
15
|
+
export interface CreateFollowContextOptions {
|
|
16
|
+
readonly responses?: Record<string, Result<unknown, Error>> | undefined;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create a mock `FollowFn` for testing composite trails.
|
|
20
|
+
*
|
|
21
|
+
* Returns preconfigured `Result` values keyed by trail ID. Calls to
|
|
22
|
+
* unregistered IDs return `Result.err` with a descriptive message.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* const follow = createFollowContext({
|
|
27
|
+
* responses: { 'entity.add': Result.ok({ id: '1', name: 'Alpha' }) },
|
|
28
|
+
* });
|
|
29
|
+
* const ctx = { ...createTestContext(), follow };
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare const createFollowContext: (options?: CreateFollowContextOptions) => FollowFn;
|
|
14
33
|
/**
|
|
15
34
|
* Merge a Partial<TrailContext> into a test context.
|
|
16
35
|
* Used internally when the public API accepts Partial<TrailContext>.
|
package/dist/context.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAGxC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAM1D;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAC5B,YAAY,uBAAuB,KAClC,YAMD,CAAC;AAMH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,GAAG,SAAS,CAAC;CACzE;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,mBAAmB,GAC9B,UAAU,0BAA0B,KACnC,QAcF,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAAI,MAAM,OAAO,CAAC,YAAY,CAAC,KAAG,YAO9D,CAAC"}
|
package/dist/context.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Test context factory for creating TrailContext instances suitable for testing.
|
|
3
3
|
*/
|
|
4
|
+
import { Result } from '@ontrails/core';
|
|
4
5
|
import { createTestLogger } from './logger.js';
|
|
5
6
|
// ---------------------------------------------------------------------------
|
|
6
7
|
// createTestContext
|
|
@@ -19,6 +20,30 @@ export const createTestContext = (overrides) => ({
|
|
|
19
20
|
signal: overrides?.signal ?? new AbortController().signal,
|
|
20
21
|
workspaceRoot: overrides?.cwd ?? process.cwd(),
|
|
21
22
|
});
|
|
23
|
+
/**
|
|
24
|
+
* Create a mock `FollowFn` for testing composite trails.
|
|
25
|
+
*
|
|
26
|
+
* Returns preconfigured `Result` values keyed by trail ID. Calls to
|
|
27
|
+
* unregistered IDs return `Result.err` with a descriptive message.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* const follow = createFollowContext({
|
|
32
|
+
* responses: { 'entity.add': Result.ok({ id: '1', name: 'Alpha' }) },
|
|
33
|
+
* });
|
|
34
|
+
* const ctx = { ...createTestContext(), follow };
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export const createFollowContext = (options) => {
|
|
38
|
+
const responses = options?.responses ?? {};
|
|
39
|
+
return (id, _input) => {
|
|
40
|
+
const response = responses[id];
|
|
41
|
+
if (response === undefined) {
|
|
42
|
+
return Promise.resolve(Result.err(new Error(`No mock response for follow("${id}")`)));
|
|
43
|
+
}
|
|
44
|
+
return Promise.resolve(response);
|
|
45
|
+
};
|
|
46
|
+
};
|
|
22
47
|
/**
|
|
23
48
|
* Merge a Partial<TrailContext> into a test context.
|
|
24
49
|
* Used internally when the public API accepts Partial<TrailContext>.
|
package/dist/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAExC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,SAAmC,EACrB,EAAE,CAAC,CAAC;IAClB,GAAG,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE;IAC7C,MAAM,EAAE,SAAS,EAAE,MAAM,IAAI,gBAAgB,EAAE;IAC/C,SAAS,EAAE,SAAS,EAAE,SAAS,IAAI,kBAAkB;IACrD,MAAM,EAAE,SAAS,EAAE,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC,MAAM;IACzD,aAAa,EAAE,SAAS,EAAE,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE;CAC/C,CAAC,CAAC;AAUH;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,OAAoC,EAC1B,EAAE;IACZ,MAAM,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,EAAE,CAAC;IAC3C,OAAO,CAAI,EAAU,EAAE,MAAe,EAA6B,EAAE;QACnE,MAAM,QAAQ,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;QAC/B,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,OAAO,OAAO,CAAC,OAAO,CACpB,MAAM,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,gCAAgC,EAAE,IAAI,CAAC,CAG3D,CACF,CAAC;QACJ,CAAC;QACD,OAAO,OAAO,CAAC,OAAO,CAAC,QAA4B,CAAC,CAAC;IACvD,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,GAA2B,EAAgB,EAAE;IAC5E,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,OAAO,iBAAiB,EAAE,CAAC;IAC7B,CAAC;IAED,MAAM,IAAI,GAAG,iBAAiB,EAAE,CAAC;IACjC,OAAO,EAAE,GAAG,IAAI,EAAE,GAAG,GAAG,EAAE,CAAC;AAC7B,CAAC,CAAC"}
|
package/dist/contracts.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { Topo, TrailContext } from '@ontrails/core';
|
|
9
9
|
/**
|
|
10
|
-
* Verify that every trail
|
|
10
|
+
* Verify that every trail implementation output matches its declared
|
|
11
11
|
* output schema. Catches implementation-schema drift.
|
|
12
12
|
*
|
|
13
13
|
* Trails without output schemas or examples are skipped.
|
package/dist/contracts.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,IAAI,EAAuB,YAAY,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"contracts.d.ts","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,IAAI,EAAuB,YAAY,EAAE,MAAM,gBAAgB,CAAC;AA0C9E;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GACxB,KAAK,IAAI,EACT,eAAe,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC,KACnE,IAoCF,CAAC"}
|
package/dist/contracts.js
CHANGED
|
@@ -12,6 +12,14 @@ import { mergeTestContext } from './context.js';
|
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
13
|
// Helpers
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
15
|
+
/** Check if a trail requires follow() but the context doesn't provide it. */
|
|
16
|
+
const needsFollowContext = (t, resolveCtx) => {
|
|
17
|
+
const spec = t;
|
|
18
|
+
if (!spec.follow || spec.follow.length === 0) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
return !resolveCtx()?.follow;
|
|
22
|
+
};
|
|
15
23
|
const validateOutputSchema = (outputSchema, value, trailId, exampleName) => {
|
|
16
24
|
const parsed = outputSchema.safeParse(value);
|
|
17
25
|
if (!parsed.success) {
|
|
@@ -23,30 +31,32 @@ const validateOutputSchema = (outputSchema, value, trailId, exampleName) => {
|
|
|
23
31
|
// testContracts
|
|
24
32
|
// ---------------------------------------------------------------------------
|
|
25
33
|
/**
|
|
26
|
-
* Verify that every trail
|
|
34
|
+
* Verify that every trail implementation output matches its declared
|
|
27
35
|
* output schema. Catches implementation-schema drift.
|
|
28
36
|
*
|
|
29
37
|
* Trails without output schemas or examples are skipped.
|
|
30
38
|
*/
|
|
31
39
|
export const testContracts = (app, ctxOrFactory) => {
|
|
32
40
|
const resolveCtx = typeof ctxOrFactory === 'function' ? ctxOrFactory : () => ctxOrFactory;
|
|
33
|
-
const
|
|
41
|
+
const allEntries = app.list();
|
|
34
42
|
describe('contracts', () => {
|
|
35
|
-
describe.each(
|
|
36
|
-
const t = trailDef;
|
|
43
|
+
describe.each(allEntries)('$id', (t) => {
|
|
37
44
|
if (t.output === undefined) {
|
|
38
45
|
return;
|
|
39
46
|
}
|
|
40
47
|
if (t.examples === undefined || t.examples.length === 0) {
|
|
41
48
|
return;
|
|
42
49
|
}
|
|
50
|
+
if (needsFollowContext(t, resolveCtx)) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
43
53
|
const { examples, output: outputSchema } = t;
|
|
44
54
|
const successExamples = examples.filter((e) => e.error === undefined);
|
|
45
55
|
test.each(successExamples)('contract: $name', async (example) => {
|
|
46
56
|
const testCtx = mergeTestContext(resolveCtx());
|
|
47
57
|
const validated = validateInput(t.input, example.input);
|
|
48
58
|
const validatedInput = expectOk(validated);
|
|
49
|
-
const result = await t.
|
|
59
|
+
const result = await t.run(validatedInput, testCtx);
|
|
50
60
|
const resultValue = expectOk(result);
|
|
51
61
|
validateOutputSchema(outputSchema, resultValue, t.id, example.name);
|
|
52
62
|
});
|
package/dist/contracts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contracts.js","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAG1C,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGhE,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,MAAM,oBAAoB,GAAG,CAC3B,YAAuB,EACvB,KAAc,EACd,OAAe,EACf,WAAmB,EACb,EAAE;IACR,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC7C,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACpD,MAAM,IAAI,KAAK,CACb,sCAAsC,OAAO,eAAe,WAAW,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,sBAAsB,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAC7K,CAAC;IACJ,CAAC;AACH,CAAC,CAAC;AAEF,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,GAAS,EACT,YAAoE,EAC9D,EAAE;IACR,MAAM,UAAU,GACd,OAAO,YAAY,KAAK,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC;IACzE,MAAM,
|
|
1
|
+
{"version":3,"file":"contracts.js","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"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"}
|
package/dist/examples.d.ts
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
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
|
|
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 type { Topo, TrailContext } from '@ontrails/core';
|
|
10
10
|
/**
|
|
11
11
|
* Generate describe/test blocks for every trail example in the app.
|
|
12
12
|
*
|
|
13
|
-
* For
|
|
13
|
+
* For trails with `follow` declarations and examples, also verifies that
|
|
14
14
|
* every declared follow ID was called at least once across all examples.
|
|
15
15
|
*
|
|
16
16
|
* One line in your test file:
|
package/dist/examples.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"examples.d.ts","sourceRoot":"","sources":["../src/examples.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"examples.d.ts","sourceRoot":"","sources":["../src/examples.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAEV,IAAI,EAGJ,YAAY,EACb,MAAM,gBAAgB,CAAC;AAiMxB;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,GACvB,KAAK,IAAI,EACT,eAAe,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC,KACnE,IAqDF,CAAC"}
|
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
|
|
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.
|
|
78
|
+
const result = await t.run(validatedInput, testCtx);
|
|
79
79
|
assertProgressiveMatch(result, example, output);
|
|
80
80
|
};
|
|
81
81
|
// ---------------------------------------------------------------------------
|
|
82
|
-
//
|
|
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.
|
|
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
|
|
110
|
+
* Run a single example against a composition trail, recording follow calls.
|
|
111
111
|
*/
|
|
112
|
-
const
|
|
113
|
-
const validated = validateInput(
|
|
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
|
|
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
|
|
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
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
-
|
|
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
|
package/dist/examples.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"examples.js","sourceRoot":"","sources":["../src/examples.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;
|
|
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"}
|