@ontrails/testing 1.0.0-beta.10 → 1.0.0-beta.12
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 +47 -0
- package/dist/all.d.ts +2 -1
- package/dist/all.d.ts.map +1 -1
- package/dist/all.js.map +1 -1
- package/dist/context.d.ts +39 -2
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +60 -13
- package/dist/context.js.map +1 -1
- package/dist/contracts.d.ts +2 -1
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +13 -8
- package/dist/contracts.js.map +1 -1
- package/dist/examples.d.ts +2 -1
- package/dist/examples.d.ts.map +1 -1
- package/dist/examples.js +49 -22
- package/dist/examples.js.map +1 -1
- package/dist/follows.d.ts +7 -1
- package/dist/follows.d.ts.map +1 -1
- package/dist/follows.js +60 -17
- package/dist/follows.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
- package/src/__tests__/all.test.ts +64 -0
- package/src/__tests__/context.test.ts +58 -3
- package/src/__tests__/contracts.test.ts +92 -1
- package/src/__tests__/examples.test.ts +359 -1
- package/src/__tests__/follows.test.ts +427 -1
- package/src/all.ts +5 -1
- package/src/context.ts +126 -15
- package/src/contracts.ts +28 -10
- package/src/examples.ts +94 -22
- package/src/follows.ts +112 -17
- package/src/index.ts +10 -1
package/dist/follows.js
CHANGED
|
@@ -5,9 +5,48 @@
|
|
|
5
5
|
* and supports failure injection from followed trail examples.
|
|
6
6
|
*/
|
|
7
7
|
import { describe, expect, test } from 'bun:test';
|
|
8
|
-
import { InternalError, Result, ValidationError, validateInput, } from '@ontrails/core';
|
|
9
|
-
import { assertErrorMatch, assertFullMatch, assertSchemaMatch,
|
|
10
|
-
import { mergeTestContext } from './context.js';
|
|
8
|
+
import { executeTrail, InternalError, Result, ValidationError, validateInput, } from '@ontrails/core';
|
|
9
|
+
import { assertErrorMatch, assertFullMatch, assertSchemaMatch, } from './assertions.js';
|
|
10
|
+
import { mergeServiceOverrides, mergeTestContext } from './context.js';
|
|
11
|
+
const collectDeclaredServices = (trailDef, trailsMap) => {
|
|
12
|
+
const seenServiceIds = new Set();
|
|
13
|
+
const seenTrailIds = new Set();
|
|
14
|
+
const services = [];
|
|
15
|
+
const collect = (candidate) => {
|
|
16
|
+
for (const declaredService of candidate.services) {
|
|
17
|
+
if (seenServiceIds.has(declaredService.id)) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
seenServiceIds.add(declaredService.id);
|
|
21
|
+
services.push(declaredService);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const visit = (candidate) => {
|
|
25
|
+
if (seenTrailIds.has(candidate.id)) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
seenTrailIds.add(candidate.id);
|
|
29
|
+
collect(candidate);
|
|
30
|
+
for (const followedId of candidate.follow) {
|
|
31
|
+
const followedTrail = trailsMap?.get(followedId);
|
|
32
|
+
if (followedTrail) {
|
|
33
|
+
visit(followedTrail);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
visit(trailDef);
|
|
38
|
+
return services;
|
|
39
|
+
};
|
|
40
|
+
const resolveMockServices = async (trailDef, trailsMap) => {
|
|
41
|
+
const services = {};
|
|
42
|
+
for (const declaredService of collectDeclaredServices(trailDef, trailsMap)) {
|
|
43
|
+
if (!declaredService.mock) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
services[declaredService.id] = await declaredService.mock();
|
|
47
|
+
}
|
|
48
|
+
return services;
|
|
49
|
+
};
|
|
11
50
|
// ---------------------------------------------------------------------------
|
|
12
51
|
// Injection helpers
|
|
13
52
|
// ---------------------------------------------------------------------------
|
|
@@ -41,16 +80,16 @@ const tryInjectError = (id, scenario, trailsMap) => {
|
|
|
41
80
|
/**
|
|
42
81
|
* Execute a trail from the map, validating input first.
|
|
43
82
|
*/
|
|
44
|
-
const executeFromMap = (id, input, trailsMap, ctx) => {
|
|
83
|
+
const executeFromMap = (id, input, trailsMap, ctx, services, follow) => {
|
|
45
84
|
const trailDef = trailsMap?.get(id);
|
|
46
85
|
if (trailDef === undefined) {
|
|
47
86
|
return undefined;
|
|
48
87
|
}
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
88
|
+
const nestedCtx = follow ? { ...ctx, follow } : ctx;
|
|
89
|
+
return executeTrail(trailDef, input, {
|
|
90
|
+
ctx: nestedCtx,
|
|
91
|
+
services,
|
|
92
|
+
});
|
|
54
93
|
};
|
|
55
94
|
// ---------------------------------------------------------------------------
|
|
56
95
|
// Follow factory
|
|
@@ -58,7 +97,7 @@ const executeFromMap = (id, input, trailsMap, ctx) => {
|
|
|
58
97
|
/**
|
|
59
98
|
* Build a recording follow function that optionally injects errors.
|
|
60
99
|
*/
|
|
61
|
-
const createRecordingFollow = (trace, scenario, trailsMap, baseFollow, ctx) => {
|
|
100
|
+
const createRecordingFollow = (trace, scenario, trailsMap, baseFollow, ctx, services) => {
|
|
62
101
|
// The generic O on FollowFn is erased at runtime; the cast is safe
|
|
63
102
|
// because callers narrow via isOk/isErr before accessing the value.
|
|
64
103
|
const follow = (id, input) => {
|
|
@@ -70,7 +109,7 @@ const createRecordingFollow = (trace, scenario, trailsMap, baseFollow, ctx) => {
|
|
|
70
109
|
if (baseFollow !== undefined) {
|
|
71
110
|
return baseFollow(id, input);
|
|
72
111
|
}
|
|
73
|
-
const executed = executeFromMap(id, input, trailsMap, ctx);
|
|
112
|
+
const executed = executeFromMap(id, input, trailsMap, ctx, services, follow);
|
|
74
113
|
if (executed !== undefined) {
|
|
75
114
|
return Promise.resolve(executed);
|
|
76
115
|
}
|
|
@@ -128,19 +167,22 @@ const handleValidationError = (validated, scenario) => {
|
|
|
128
167
|
// ---------------------------------------------------------------------------
|
|
129
168
|
// Scenario runner
|
|
130
169
|
// ---------------------------------------------------------------------------
|
|
131
|
-
const buildTestContext = (scenario, ctx, trailsMap) => {
|
|
170
|
+
const buildTestContext = (scenario, ctx, trailsMap, services) => {
|
|
132
171
|
const trace = [];
|
|
133
172
|
const baseCtx = mergeTestContext(ctx);
|
|
134
|
-
const follow = createRecordingFollow(trace, scenario, trailsMap, baseCtx.follow, baseCtx);
|
|
173
|
+
const follow = createRecordingFollow(trace, scenario, trailsMap, baseCtx.follow, baseCtx, services);
|
|
135
174
|
return { testCtx: { ...baseCtx, follow }, trace };
|
|
136
175
|
};
|
|
137
|
-
const runScenario = async (trailDef, scenario, ctx, trailsMap) => {
|
|
176
|
+
const runScenario = async (trailDef, scenario, ctx, trailsMap, services) => {
|
|
138
177
|
const validated = validateInput(trailDef.input, scenario.input);
|
|
139
178
|
if (handleValidationError(validated, scenario)) {
|
|
140
179
|
return;
|
|
141
180
|
}
|
|
142
|
-
const { trace, testCtx } = buildTestContext(scenario, ctx, trailsMap);
|
|
143
|
-
const result = await trailDef.
|
|
181
|
+
const { trace, testCtx } = buildTestContext(scenario, ctx, trailsMap, services);
|
|
182
|
+
const result = await executeTrail(trailDef, scenario.input, {
|
|
183
|
+
ctx: testCtx,
|
|
184
|
+
services,
|
|
185
|
+
});
|
|
144
186
|
assertFollowTrace(trace, scenario);
|
|
145
187
|
assertScenarioResult(result, scenario, trailDef);
|
|
146
188
|
};
|
|
@@ -162,7 +204,8 @@ const runScenario = async (trailDef, scenario, ctx, trailsMap) => {
|
|
|
162
204
|
export const testFollows = (trailDef, scenarios, options) => {
|
|
163
205
|
describe(trailDef.id, () => {
|
|
164
206
|
test.each([...scenarios])('$description', async (scenario) => {
|
|
165
|
-
await
|
|
207
|
+
const services = mergeServiceOverrides(await resolveMockServices(trailDef, options?.trails), options?.ctx, options?.services);
|
|
208
|
+
await runScenario(trailDef, scenario, options?.ctx, options?.trails, services);
|
|
166
209
|
});
|
|
167
210
|
});
|
|
168
211
|
};
|
package/dist/follows.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"follows.js","sourceRoot":"","sources":["../src/follows.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"follows.js","sourceRoot":"","sources":["../src/follows.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,11 +5,12 @@ 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 { createFollowContext, createTestContext } from './context.js';
|
|
8
|
+
export { createFollowContext, createTestContext, defaultMintPermit, } 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
12
|
export type { CreateFollowContextOptions } from './context.js';
|
|
13
|
+
export type { MintableTrail, MintedPermit, 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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAG3C,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,SAAS,EACT,QAAQ,GACT,MAAM,iBAAiB,CAAC;AAGzB,OAAO,
|
|
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,EACL,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAG/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGpD,YAAY,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAC/D,YAAY,EACV,aAAa,EACb,YAAY,EACZ,oBAAoB,GACrB,MAAM,cAAc,CAAC;AACtB,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
|
@@ -8,7 +8,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 { createFollowContext, createTestContext } from './context.js';
|
|
11
|
+
export { createFollowContext, createTestContext, defaultMintPermit, } 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,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,
|
|
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,EACL,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,cAAc,CAAC;AACtB,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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ontrails/testing",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.12",
|
|
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": "^1.0.0-beta.
|
|
18
|
-
"@ontrails/core": "^1.0.0-beta.
|
|
19
|
-
"@ontrails/logging": "^1.0.0-beta.
|
|
20
|
-
"@ontrails/mcp": "^1.0.0-beta.
|
|
17
|
+
"@ontrails/cli": "^1.0.0-beta.12",
|
|
18
|
+
"@ontrails/core": "^1.0.0-beta.12",
|
|
19
|
+
"@ontrails/logging": "^1.0.0-beta.12",
|
|
20
|
+
"@ontrails/mcp": "^1.0.0-beta.12",
|
|
21
21
|
"zod": "^4.3.5"
|
|
22
22
|
}
|
|
23
23
|
}
|
|
@@ -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 {
|
|
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).
|
|
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
|
+
});
|