@btravstack/testing 0.18.0 → 0.20.0
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/README.md +3 -0
- package/dist/index.cjs +14 -2
- package/dist/index.d.cts +14 -2
- package/dist/index.d.mts +14 -2
- package/dist/index.mjs +15 -3
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -100,6 +100,9 @@ answers the very instances the running graph holds once it is built — after
|
|
|
100
100
|
tree stopped providing is a `WiringDefect` ("nothing to override"), which is
|
|
101
101
|
what keeps a test root from drifting silently away from the real one — the
|
|
102
102
|
drift that four hand-maintained parallel roots had already produced here.
|
|
103
|
+
`overridden(module, [providers], { unit: { user: [providers] } })` reaches
|
|
104
|
+
inside a unit module the root binds, by kind, with the same drift gate at
|
|
105
|
+
boot.
|
|
103
106
|
- **`createFakeClock(start?)`** — a `Clock` for `StartOptions.clock` whose
|
|
104
107
|
time moves only on `advance(ms)`.
|
|
105
108
|
|
package/dist/index.cjs
CHANGED
|
@@ -114,6 +114,14 @@ const createFakeClock = (start = 0) => {
|
|
|
114
114
|
* tree no longer provides is a `WiringDefect` ("nothing to override"), which is
|
|
115
115
|
* what turns fixture drift into a loud failure.
|
|
116
116
|
*
|
|
117
|
+
* `options.unit` reaches inside the unit modules the root binds, keyed by the
|
|
118
|
+
* kind the root binds them under (`{ user: [...] }`, `{ message: [...] }`):
|
|
119
|
+
* a unit module is forked per unit, after the root is built, so a root-level
|
|
120
|
+
* override cannot see its providers. The kernel applies these at boot, and a
|
|
121
|
+
* kind the runtime binds no module for, a port that kind's module does not
|
|
122
|
+
* provide, or two overrides for one port in one kind is a defect there — the
|
|
123
|
+
* same drift gate, at the same moment.
|
|
124
|
+
*
|
|
117
125
|
* It replaces ONE provider, never a subsystem: the replaced provider's siblings
|
|
118
126
|
* still construct, so swapping a whole adapter stack remains a different module
|
|
119
127
|
* composed in its place.
|
|
@@ -123,9 +131,12 @@ const createFakeClock = (start = 0) => {
|
|
|
123
131
|
* root to re-export internals to be overridable. They are checked at build
|
|
124
132
|
* instead, by `plan`'s missing-provider defect.
|
|
125
133
|
*/
|
|
126
|
-
const overridden = (module, overrides) => (0, _btravstack_di.Module)("Overridden")({
|
|
134
|
+
const overridden = (module, overrides, options = {}) => (0, _btravstack_di.Module)("Overridden")({
|
|
127
135
|
imports: [module],
|
|
128
|
-
provides: overrides.map((override) => (0, _btravstack_di.overrideProvider)(override)),
|
|
136
|
+
provides: [...overrides.map((override) => (0, _btravstack_di.overrideProvider)(override)), _btravstack_di.Provider.member(_btravstack_core.UnitOverrides)({
|
|
137
|
+
inject: {},
|
|
138
|
+
value: Object.fromEntries(Object.entries(options.unit ?? {}).map(([kind, providers]) => [kind, providers.map((provider) => (0, _btravstack_di.overrideProvider)(provider))]))
|
|
139
|
+
})],
|
|
129
140
|
exports: [module]
|
|
130
141
|
});
|
|
131
142
|
//#endregion
|
|
@@ -176,6 +187,7 @@ const testRuntime = (name = "test", options = {}) => {
|
|
|
176
187
|
exports: [TestRuntimePort]
|
|
177
188
|
}),
|
|
178
189
|
resolves: [],
|
|
190
|
+
units: { test: options.unit },
|
|
179
191
|
start: (h) => {
|
|
180
192
|
host = h;
|
|
181
193
|
accepting = true;
|
package/dist/index.d.cts
CHANGED
|
@@ -68,9 +68,11 @@ export declare const createFakeClock: (start?: number) => FakeClock;
|
|
|
68
68
|
//#endregion
|
|
69
69
|
//#region src/overridden.d.ts
|
|
70
70
|
/** One override's error channel, unioned across the tuple by `overridden`. */
|
|
71
|
-
type ErrorsOf<O extends readonly AnyProviderFor[]> = O[number] extends Provider<never, infer E, unknown> ? E : never;
|
|
71
|
+
type ErrorsOf<O extends readonly AnyProviderFor[]> = O[number] extends (infer P) ? P extends Provider<never, infer E, unknown> ? E : never : never;
|
|
72
72
|
/** The widest provider `overridden` accepts — variance makes every real one assignable. */
|
|
73
73
|
type AnyProviderFor = Provider<never, unknown, unknown>;
|
|
74
|
+
/** A unit module's provider: a fork's error channel is `never`, so its overrides' must be too. */
|
|
75
|
+
type UnitProviderFor = Provider<never, never, unknown>;
|
|
74
76
|
/**
|
|
75
77
|
* The real composition root, with named providers substituted — the testing half
|
|
76
78
|
* of "swapping an adapter is composing a different module", for the seam
|
|
@@ -83,6 +85,14 @@ type AnyProviderFor = Provider<never, unknown, unknown>;
|
|
|
83
85
|
* tree no longer provides is a `WiringDefect` ("nothing to override"), which is
|
|
84
86
|
* what turns fixture drift into a loud failure.
|
|
85
87
|
*
|
|
88
|
+
* `options.unit` reaches inside the unit modules the root binds, keyed by the
|
|
89
|
+
* kind the root binds them under (`{ user: [...] }`, `{ message: [...] }`):
|
|
90
|
+
* a unit module is forked per unit, after the root is built, so a root-level
|
|
91
|
+
* override cannot see its providers. The kernel applies these at boot, and a
|
|
92
|
+
* kind the runtime binds no module for, a port that kind's module does not
|
|
93
|
+
* provide, or two overrides for one port in one kind is a defect there — the
|
|
94
|
+
* same drift gate, at the same moment.
|
|
95
|
+
*
|
|
86
96
|
* It replaces ONE provider, never a subsystem: the replaced provider's siblings
|
|
87
97
|
* still construct, so swapping a whole adapter stack remains a different module
|
|
88
98
|
* composed in its place.
|
|
@@ -92,7 +102,9 @@ type AnyProviderFor = Provider<never, unknown, unknown>;
|
|
|
92
102
|
* root to re-export internals to be overridable. They are checked at build
|
|
93
103
|
* instead, by `plan`'s missing-provider defect.
|
|
94
104
|
*/
|
|
95
|
-
export declare const overridden: <X, E, N, const O extends readonly AnyProviderFor[]>(module: Module<X, E, N>, overrides: O
|
|
105
|
+
export declare const overridden: <X, E, N, const O extends readonly AnyProviderFor[]>(module: Module<X, E, N>, overrides: O, options?: {
|
|
106
|
+
readonly unit?: Readonly<Record<string, readonly UnitProviderFor[]>>;
|
|
107
|
+
}) => Module<X, E | ErrorsOf<O>, N>;
|
|
96
108
|
//#endregion
|
|
97
109
|
//#region src/tapped.d.ts
|
|
98
110
|
/** The services behind `ports`, in order — what `tapped(...).services()` answers once the graph is built. */
|
package/dist/index.d.mts
CHANGED
|
@@ -68,9 +68,11 @@ export declare const createFakeClock: (start?: number) => FakeClock;
|
|
|
68
68
|
//#endregion
|
|
69
69
|
//#region src/overridden.d.ts
|
|
70
70
|
/** One override's error channel, unioned across the tuple by `overridden`. */
|
|
71
|
-
type ErrorsOf<O extends readonly AnyProviderFor[]> = O[number] extends Provider<never, infer E, unknown> ? E : never;
|
|
71
|
+
type ErrorsOf<O extends readonly AnyProviderFor[]> = O[number] extends (infer P) ? P extends Provider<never, infer E, unknown> ? E : never : never;
|
|
72
72
|
/** The widest provider `overridden` accepts — variance makes every real one assignable. */
|
|
73
73
|
type AnyProviderFor = Provider<never, unknown, unknown>;
|
|
74
|
+
/** A unit module's provider: a fork's error channel is `never`, so its overrides' must be too. */
|
|
75
|
+
type UnitProviderFor = Provider<never, never, unknown>;
|
|
74
76
|
/**
|
|
75
77
|
* The real composition root, with named providers substituted — the testing half
|
|
76
78
|
* of "swapping an adapter is composing a different module", for the seam
|
|
@@ -83,6 +85,14 @@ type AnyProviderFor = Provider<never, unknown, unknown>;
|
|
|
83
85
|
* tree no longer provides is a `WiringDefect` ("nothing to override"), which is
|
|
84
86
|
* what turns fixture drift into a loud failure.
|
|
85
87
|
*
|
|
88
|
+
* `options.unit` reaches inside the unit modules the root binds, keyed by the
|
|
89
|
+
* kind the root binds them under (`{ user: [...] }`, `{ message: [...] }`):
|
|
90
|
+
* a unit module is forked per unit, after the root is built, so a root-level
|
|
91
|
+
* override cannot see its providers. The kernel applies these at boot, and a
|
|
92
|
+
* kind the runtime binds no module for, a port that kind's module does not
|
|
93
|
+
* provide, or two overrides for one port in one kind is a defect there — the
|
|
94
|
+
* same drift gate, at the same moment.
|
|
95
|
+
*
|
|
86
96
|
* It replaces ONE provider, never a subsystem: the replaced provider's siblings
|
|
87
97
|
* still construct, so swapping a whole adapter stack remains a different module
|
|
88
98
|
* composed in its place.
|
|
@@ -92,7 +102,9 @@ type AnyProviderFor = Provider<never, unknown, unknown>;
|
|
|
92
102
|
* root to re-export internals to be overridable. They are checked at build
|
|
93
103
|
* instead, by `plan`'s missing-provider defect.
|
|
94
104
|
*/
|
|
95
|
-
export declare const overridden: <X, E, N, const O extends readonly AnyProviderFor[]>(module: Module<X, E, N>, overrides: O
|
|
105
|
+
export declare const overridden: <X, E, N, const O extends readonly AnyProviderFor[]>(module: Module<X, E, N>, overrides: O, options?: {
|
|
106
|
+
readonly unit?: Readonly<Record<string, readonly UnitProviderFor[]>>;
|
|
107
|
+
}) => Module<X, E | ErrorsOf<O>, N>;
|
|
96
108
|
//#endregion
|
|
97
109
|
//#region src/tapped.d.ts
|
|
98
110
|
/** The services behind `ports`, in order — what `tapped(...).services()` answers once the graph is built. */
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RuntimePort, start } from "@btravstack/core";
|
|
1
|
+
import { RuntimePort, UnitOverrides, start } from "@btravstack/core";
|
|
2
2
|
import { setTimeout } from "node:timers/promises";
|
|
3
3
|
import { OkAsync, fromSafePromise } from "unthrown";
|
|
4
4
|
import { Module, Port, Provider, overrideProvider } from "@btravstack/di";
|
|
@@ -113,6 +113,14 @@ const createFakeClock = (start = 0) => {
|
|
|
113
113
|
* tree no longer provides is a `WiringDefect` ("nothing to override"), which is
|
|
114
114
|
* what turns fixture drift into a loud failure.
|
|
115
115
|
*
|
|
116
|
+
* `options.unit` reaches inside the unit modules the root binds, keyed by the
|
|
117
|
+
* kind the root binds them under (`{ user: [...] }`, `{ message: [...] }`):
|
|
118
|
+
* a unit module is forked per unit, after the root is built, so a root-level
|
|
119
|
+
* override cannot see its providers. The kernel applies these at boot, and a
|
|
120
|
+
* kind the runtime binds no module for, a port that kind's module does not
|
|
121
|
+
* provide, or two overrides for one port in one kind is a defect there — the
|
|
122
|
+
* same drift gate, at the same moment.
|
|
123
|
+
*
|
|
116
124
|
* It replaces ONE provider, never a subsystem: the replaced provider's siblings
|
|
117
125
|
* still construct, so swapping a whole adapter stack remains a different module
|
|
118
126
|
* composed in its place.
|
|
@@ -122,9 +130,12 @@ const createFakeClock = (start = 0) => {
|
|
|
122
130
|
* root to re-export internals to be overridable. They are checked at build
|
|
123
131
|
* instead, by `plan`'s missing-provider defect.
|
|
124
132
|
*/
|
|
125
|
-
const overridden = (module, overrides) => Module("Overridden")({
|
|
133
|
+
const overridden = (module, overrides, options = {}) => Module("Overridden")({
|
|
126
134
|
imports: [module],
|
|
127
|
-
provides: overrides.map((override) => overrideProvider(override)),
|
|
135
|
+
provides: [...overrides.map((override) => overrideProvider(override)), Provider.member(UnitOverrides)({
|
|
136
|
+
inject: {},
|
|
137
|
+
value: Object.fromEntries(Object.entries(options.unit ?? {}).map(([kind, providers]) => [kind, providers.map((provider) => overrideProvider(provider))]))
|
|
138
|
+
})],
|
|
128
139
|
exports: [module]
|
|
129
140
|
});
|
|
130
141
|
//#endregion
|
|
@@ -175,6 +186,7 @@ const testRuntime = (name = "test", options = {}) => {
|
|
|
175
186
|
exports: [TestRuntimePort]
|
|
176
187
|
}),
|
|
177
188
|
resolves: [],
|
|
189
|
+
units: { test: options.unit },
|
|
178
190
|
start: (h) => {
|
|
179
191
|
host = h;
|
|
180
192
|
accepting = true;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@btravstack/testing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"description": "Test the applications @btravstack/core boots: an in-memory runtime, a fake clock, a boot fixture that stops what it started, and a tap into a running graph",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dependency-injection",
|
|
@@ -54,9 +54,9 @@
|
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@btravstack/config": "0.
|
|
58
|
-
"@btravstack/core": "0.
|
|
59
|
-
"@btravstack/di": "0.
|
|
57
|
+
"@btravstack/config": "0.20.0",
|
|
58
|
+
"@btravstack/core": "0.20.0",
|
|
59
|
+
"@btravstack/di": "0.20.0",
|
|
60
60
|
"@btravstack/tsconfig": "0.4.0",
|
|
61
61
|
"@types/node": "26.6.4",
|
|
62
62
|
"@unthrown/vitest": "5.12.0",
|
|
@@ -68,9 +68,9 @@
|
|
|
68
68
|
"vitest": "5.0.3"
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
|
-
"@btravstack/config": "^0.
|
|
72
|
-
"@btravstack/core": "^0.
|
|
73
|
-
"@btravstack/di": "^0.
|
|
71
|
+
"@btravstack/config": "^0.20.0",
|
|
72
|
+
"@btravstack/core": "^0.20.0",
|
|
73
|
+
"@btravstack/di": "^0.20.0",
|
|
74
74
|
"jose": "^6",
|
|
75
75
|
"unthrown": "^5.0.0"
|
|
76
76
|
},
|