@btravstack/testing 0.13.0 → 0.15.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 +8 -0
- package/dist/index.cjs +4 -2
- package/dist/index.d.cts +10 -9
- package/dist/index.d.mts +10 -9
- package/dist/index.mjs +4 -2
- package/dist/jwt.d.cts +5 -6
- package/dist/jwt.d.mts +5 -6
- package/package.json +14 -15
package/README.md
CHANGED
|
@@ -92,6 +92,14 @@ answers the very instances the running graph holds once it is built — after
|
|
|
92
92
|
provides it where a starter would; `unit` is a module every submitted unit
|
|
93
93
|
forks, with no seed, before its work runs — and what that module needs joins
|
|
94
94
|
`module`'s own, so `start` names it instead of the first `submit()` failing.
|
|
95
|
+
- **`overridden(module, [providers])`** — substitute named providers into your
|
|
96
|
+
**real** composition root, rather than maintaining a parallel test root
|
|
97
|
+
beside it. It replaces one **provider**, never a subsystem: the replaced
|
|
98
|
+
provider's siblings still construct, so swapping a whole adapter stack is
|
|
99
|
+
still a different module composed in its place. An override for a port the
|
|
100
|
+
tree stopped providing is a `WiringDefect` ("nothing to override"), which is
|
|
101
|
+
what keeps a test root from drifting silently away from the real one — the
|
|
102
|
+
drift that four hand-maintained parallel roots had already produced here.
|
|
95
103
|
- **`createFakeClock(start?)`** — a `Clock` for `StartOptions.clock` whose
|
|
96
104
|
time moves only on `advance(ms)`.
|
|
97
105
|
|
package/dist/index.cjs
CHANGED
|
@@ -21,8 +21,9 @@ let _btravstack_di = require("@btravstack/di");
|
|
|
21
21
|
* ```
|
|
22
22
|
*
|
|
23
23
|
* The defaults are a test's: `signals: false` always (process-wide handlers
|
|
24
|
-
* would fight across a file), `probes: false`, `preDrainDelayMs: 0
|
|
25
|
-
* `
|
|
24
|
+
* would fight across a file), `probes: false`, `preDrainDelayMs: 0`, a
|
|
25
|
+
* `stopTimeoutMs` far out of reach and a silent `onEvent` — each overridable by
|
|
26
|
+
* `defaults` and again per call.
|
|
26
27
|
*
|
|
27
28
|
* Teardown is `stop()`, then `exited` is examined: a **`Defect`** fails the test
|
|
28
29
|
* even when the test never looked at `exited`, while a modeled `Err` passes
|
|
@@ -33,6 +34,7 @@ const bootFixture = (defaults = {}) => async ({}, use) => {
|
|
|
33
34
|
const boot = ((module, options = {}) => {
|
|
34
35
|
const app = (0, _btravstack_core.start)(module, {
|
|
35
36
|
preDrainDelayMs: 0,
|
|
37
|
+
stopTimeoutMs: 6e5,
|
|
36
38
|
onEvent: () => {},
|
|
37
39
|
probes: false,
|
|
38
40
|
...defaults,
|
package/dist/index.d.cts
CHANGED
|
@@ -27,14 +27,15 @@ type BootDefaults = Omit<StartOptions, "signals">;
|
|
|
27
27
|
* ```
|
|
28
28
|
*
|
|
29
29
|
* The defaults are a test's: `signals: false` always (process-wide handlers
|
|
30
|
-
* would fight across a file), `probes: false`, `preDrainDelayMs: 0
|
|
31
|
-
* `
|
|
30
|
+
* would fight across a file), `probes: false`, `preDrainDelayMs: 0`, a
|
|
31
|
+
* `stopTimeoutMs` far out of reach and a silent `onEvent` — each overridable by
|
|
32
|
+
* `defaults` and again per call.
|
|
32
33
|
*
|
|
33
34
|
* Teardown is `stop()`, then `exited` is examined: a **`Defect`** fails the test
|
|
34
35
|
* even when the test never looked at `exited`, while a modeled `Err` passes
|
|
35
36
|
* through, since a startup failure is an outcome a test may be asserting.
|
|
36
37
|
*/
|
|
37
|
-
declare const bootFixture: (defaults?: BootDefaults) => ({}: object, use: (boot: Boot) => Promise<void>) => Promise<void>;
|
|
38
|
+
export declare const bootFixture: (defaults?: BootDefaults) => ({}: object, use: (boot: Boot) => Promise<void>) => Promise<void>;
|
|
38
39
|
//#endregion
|
|
39
40
|
//#region src/fake-clock.d.ts
|
|
40
41
|
type FakeClock = Clock & {
|
|
@@ -63,7 +64,7 @@ type FakeClock = Clock & {
|
|
|
63
64
|
* await clock.advance(20_000); // the drain deadline
|
|
64
65
|
* ```
|
|
65
66
|
*/
|
|
66
|
-
declare const createFakeClock: (start?: number) => FakeClock;
|
|
67
|
+
export declare const createFakeClock: (start?: number) => FakeClock;
|
|
67
68
|
//#endregion
|
|
68
69
|
//#region src/overridden.d.ts
|
|
69
70
|
/** One override's error channel, unioned across the tuple by `overridden`. */
|
|
@@ -91,7 +92,7 @@ type AnyProviderFor = Provider<never, unknown, unknown>;
|
|
|
91
92
|
* root to re-export internals to be overridable. They are checked at build
|
|
92
93
|
* instead, by `plan`'s missing-provider defect.
|
|
93
94
|
*/
|
|
94
|
-
declare const overridden: <X, E, N, const O extends readonly AnyProviderFor[]>(module: Module<X, E, N>, overrides: O) => Module<X, E | ErrorsOf<O>, N>;
|
|
95
|
+
export declare const overridden: <X, E, N, const O extends readonly AnyProviderFor[]>(module: Module<X, E, N>, overrides: O) => Module<X, E | ErrorsOf<O>, N>;
|
|
95
96
|
//#endregion
|
|
96
97
|
//#region src/tapped.d.ts
|
|
97
98
|
/** The services behind `ports`, in order — what `tapped(...).services()` answers once the graph is built. */
|
|
@@ -122,7 +123,7 @@ type ServicesOf<P extends readonly AnyPort[]> = { readonly [K in keyof P]: Servi
|
|
|
122
123
|
type TapGate<P extends readonly AnyPort[], X> = [Exclude<InstanceType<P[number]>, X>] extends [never] ? unknown : {
|
|
123
124
|
readonly "NOT EXPORTED — tap only what the module exports": Exclude<InstanceType<P[number]>, X>;
|
|
124
125
|
};
|
|
125
|
-
declare const tapped: <X, E, N, const P extends readonly AnyPort[]>(module: Module<X, E, N>, ports: P & TapGate<P, X>) => {
|
|
126
|
+
export declare const tapped: <X, E, N, const P extends readonly AnyPort[]>(module: Module<X, E, N>, ports: P & TapGate<P, X>) => {
|
|
126
127
|
readonly module: Module<X, E, N>;
|
|
127
128
|
readonly services: () => ServicesOf<P>;
|
|
128
129
|
};
|
|
@@ -141,7 +142,7 @@ type TestRuntimeInfo = {
|
|
|
141
142
|
readonly name: string;
|
|
142
143
|
};
|
|
143
144
|
/** The in-memory runtime's port: what `TestRuntime.module` provides, and what a test composition exports. */
|
|
144
|
-
declare class TestRuntimePort extends RuntimePort<Runtime<never, TestRuntimeInfo>> {}
|
|
145
|
+
export declare class TestRuntimePort extends RuntimePort<Runtime<never, TestRuntimeInfo>> {}
|
|
145
146
|
/**
|
|
146
147
|
* A module `options.unit` may bind, as the upper bound `testRuntime`
|
|
147
148
|
* constrains its own `Unit` type parameter to. `Module`'s `_exports` channel is
|
|
@@ -191,6 +192,6 @@ type TestRuntime<Unit extends AnyUnitModule | undefined = undefined> = Runtime<n
|
|
|
191
192
|
/** The `RuntimeHost` the kernel last called `start` with. **Throws** if the runtime was never started — the same misuse guard as `serving()`. */
|
|
192
193
|
readonly host: () => RuntimeHost<never>;
|
|
193
194
|
};
|
|
194
|
-
declare const testRuntime: <Unit extends AnyUnitModule | undefined = undefined>(name?: string, options?: TestRuntimeOptions<Unit>) => TestRuntime<Unit>;
|
|
195
|
+
export declare const testRuntime: <Unit extends AnyUnitModule | undefined = undefined>(name?: string, options?: TestRuntimeOptions<Unit>) => TestRuntime<Unit>;
|
|
195
196
|
//#endregion
|
|
196
|
-
export {
|
|
197
|
+
export type { Boot, BootDefaults, FakeClock, ServicesOf, SubmittedUnit, TestRuntime, TestRuntimeInfo, TestRuntimeOptions };
|
package/dist/index.d.mts
CHANGED
|
@@ -27,14 +27,15 @@ type BootDefaults = Omit<StartOptions, "signals">;
|
|
|
27
27
|
* ```
|
|
28
28
|
*
|
|
29
29
|
* The defaults are a test's: `signals: false` always (process-wide handlers
|
|
30
|
-
* would fight across a file), `probes: false`, `preDrainDelayMs: 0
|
|
31
|
-
* `
|
|
30
|
+
* would fight across a file), `probes: false`, `preDrainDelayMs: 0`, a
|
|
31
|
+
* `stopTimeoutMs` far out of reach and a silent `onEvent` — each overridable by
|
|
32
|
+
* `defaults` and again per call.
|
|
32
33
|
*
|
|
33
34
|
* Teardown is `stop()`, then `exited` is examined: a **`Defect`** fails the test
|
|
34
35
|
* even when the test never looked at `exited`, while a modeled `Err` passes
|
|
35
36
|
* through, since a startup failure is an outcome a test may be asserting.
|
|
36
37
|
*/
|
|
37
|
-
declare const bootFixture: (defaults?: BootDefaults) => ({}: object, use: (boot: Boot) => Promise<void>) => Promise<void>;
|
|
38
|
+
export declare const bootFixture: (defaults?: BootDefaults) => ({}: object, use: (boot: Boot) => Promise<void>) => Promise<void>;
|
|
38
39
|
//#endregion
|
|
39
40
|
//#region src/fake-clock.d.ts
|
|
40
41
|
type FakeClock = Clock & {
|
|
@@ -63,7 +64,7 @@ type FakeClock = Clock & {
|
|
|
63
64
|
* await clock.advance(20_000); // the drain deadline
|
|
64
65
|
* ```
|
|
65
66
|
*/
|
|
66
|
-
declare const createFakeClock: (start?: number) => FakeClock;
|
|
67
|
+
export declare const createFakeClock: (start?: number) => FakeClock;
|
|
67
68
|
//#endregion
|
|
68
69
|
//#region src/overridden.d.ts
|
|
69
70
|
/** One override's error channel, unioned across the tuple by `overridden`. */
|
|
@@ -91,7 +92,7 @@ type AnyProviderFor = Provider<never, unknown, unknown>;
|
|
|
91
92
|
* root to re-export internals to be overridable. They are checked at build
|
|
92
93
|
* instead, by `plan`'s missing-provider defect.
|
|
93
94
|
*/
|
|
94
|
-
declare const overridden: <X, E, N, const O extends readonly AnyProviderFor[]>(module: Module<X, E, N>, overrides: O) => Module<X, E | ErrorsOf<O>, N>;
|
|
95
|
+
export declare const overridden: <X, E, N, const O extends readonly AnyProviderFor[]>(module: Module<X, E, N>, overrides: O) => Module<X, E | ErrorsOf<O>, N>;
|
|
95
96
|
//#endregion
|
|
96
97
|
//#region src/tapped.d.ts
|
|
97
98
|
/** The services behind `ports`, in order — what `tapped(...).services()` answers once the graph is built. */
|
|
@@ -122,7 +123,7 @@ type ServicesOf<P extends readonly AnyPort[]> = { readonly [K in keyof P]: Servi
|
|
|
122
123
|
type TapGate<P extends readonly AnyPort[], X> = [Exclude<InstanceType<P[number]>, X>] extends [never] ? unknown : {
|
|
123
124
|
readonly "NOT EXPORTED — tap only what the module exports": Exclude<InstanceType<P[number]>, X>;
|
|
124
125
|
};
|
|
125
|
-
declare const tapped: <X, E, N, const P extends readonly AnyPort[]>(module: Module<X, E, N>, ports: P & TapGate<P, X>) => {
|
|
126
|
+
export declare const tapped: <X, E, N, const P extends readonly AnyPort[]>(module: Module<X, E, N>, ports: P & TapGate<P, X>) => {
|
|
126
127
|
readonly module: Module<X, E, N>;
|
|
127
128
|
readonly services: () => ServicesOf<P>;
|
|
128
129
|
};
|
|
@@ -141,7 +142,7 @@ type TestRuntimeInfo = {
|
|
|
141
142
|
readonly name: string;
|
|
142
143
|
};
|
|
143
144
|
/** The in-memory runtime's port: what `TestRuntime.module` provides, and what a test composition exports. */
|
|
144
|
-
declare class TestRuntimePort extends RuntimePort<Runtime<never, TestRuntimeInfo>> {}
|
|
145
|
+
export declare class TestRuntimePort extends RuntimePort<Runtime<never, TestRuntimeInfo>> {}
|
|
145
146
|
/**
|
|
146
147
|
* A module `options.unit` may bind, as the upper bound `testRuntime`
|
|
147
148
|
* constrains its own `Unit` type parameter to. `Module`'s `_exports` channel is
|
|
@@ -191,6 +192,6 @@ type TestRuntime<Unit extends AnyUnitModule | undefined = undefined> = Runtime<n
|
|
|
191
192
|
/** The `RuntimeHost` the kernel last called `start` with. **Throws** if the runtime was never started — the same misuse guard as `serving()`. */
|
|
192
193
|
readonly host: () => RuntimeHost<never>;
|
|
193
194
|
};
|
|
194
|
-
declare const testRuntime: <Unit extends AnyUnitModule | undefined = undefined>(name?: string, options?: TestRuntimeOptions<Unit>) => TestRuntime<Unit>;
|
|
195
|
+
export declare const testRuntime: <Unit extends AnyUnitModule | undefined = undefined>(name?: string, options?: TestRuntimeOptions<Unit>) => TestRuntime<Unit>;
|
|
195
196
|
//#endregion
|
|
196
|
-
export {
|
|
197
|
+
export type { Boot, BootDefaults, FakeClock, ServicesOf, SubmittedUnit, TestRuntime, TestRuntimeInfo, TestRuntimeOptions };
|
package/dist/index.mjs
CHANGED
|
@@ -20,8 +20,9 @@ import { Module, Port, Provider, overrideProvider } from "@btravstack/di";
|
|
|
20
20
|
* ```
|
|
21
21
|
*
|
|
22
22
|
* The defaults are a test's: `signals: false` always (process-wide handlers
|
|
23
|
-
* would fight across a file), `probes: false`, `preDrainDelayMs: 0
|
|
24
|
-
* `
|
|
23
|
+
* would fight across a file), `probes: false`, `preDrainDelayMs: 0`, a
|
|
24
|
+
* `stopTimeoutMs` far out of reach and a silent `onEvent` — each overridable by
|
|
25
|
+
* `defaults` and again per call.
|
|
25
26
|
*
|
|
26
27
|
* Teardown is `stop()`, then `exited` is examined: a **`Defect`** fails the test
|
|
27
28
|
* even when the test never looked at `exited`, while a modeled `Err` passes
|
|
@@ -32,6 +33,7 @@ const bootFixture = (defaults = {}) => async ({}, use) => {
|
|
|
32
33
|
const boot = ((module, options = {}) => {
|
|
33
34
|
const app = start(module, {
|
|
34
35
|
preDrainDelayMs: 0,
|
|
36
|
+
stopTimeoutMs: 6e5,
|
|
35
37
|
onEvent: () => {},
|
|
36
38
|
probes: false,
|
|
37
39
|
...defaults,
|
package/dist/jwt.d.cts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { AsyncResult } from "unthrown";
|
|
2
2
|
import { JWK, JWTPayload } from "jose";
|
|
3
3
|
//#region src/jwt.d.ts
|
|
4
|
-
type LocalIssuerOptions = {
|
|
4
|
+
export type LocalIssuerOptions = {
|
|
5
5
|
readonly issuer: string;
|
|
6
6
|
readonly audience: string;
|
|
7
7
|
/** Asymmetric only, the same list `jwtAuthenticator` accepts; default `"RS256"`. */
|
|
8
8
|
readonly algorithm?: "RS256" | "RS384" | "RS512" | "ES256" | "ES384";
|
|
9
9
|
};
|
|
10
|
-
type SignOptions = {
|
|
10
|
+
export type SignOptions = {
|
|
11
11
|
readonly issuer?: string;
|
|
12
12
|
readonly audience?: string;
|
|
13
13
|
/** `"5m"` by default; `false` mints a token with no `exp` at all. */
|
|
14
14
|
readonly expiresIn?: string | false;
|
|
15
15
|
};
|
|
16
|
-
type LocalIssuer = {
|
|
16
|
+
export type LocalIssuer = {
|
|
17
17
|
/** `http://127.0.0.1:<port>/jwks.json` — served on ANY path, so a caller need not match it exactly. */
|
|
18
18
|
readonly jwks: string;
|
|
19
19
|
/** The public key as served, with `kid`/`alg`/`use` already set. */
|
|
@@ -31,6 +31,5 @@ type LocalIssuer = {
|
|
|
31
31
|
* listener answering the JWKS on any path, and `sign` closing over the
|
|
32
32
|
* private key. `close()` stops the listener; nothing else needs tearing down.
|
|
33
33
|
*/
|
|
34
|
-
declare const localIssuer: (options: LocalIssuerOptions) => AsyncResult<LocalIssuer, never>;
|
|
35
|
-
//#endregion
|
|
36
|
-
export { LocalIssuer, LocalIssuerOptions, SignOptions, localIssuer };
|
|
34
|
+
export declare const localIssuer: (options: LocalIssuerOptions) => AsyncResult<LocalIssuer, never>;
|
|
35
|
+
//#endregion
|
package/dist/jwt.d.mts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { AsyncResult } from "unthrown";
|
|
2
2
|
import { JWK, JWTPayload } from "jose";
|
|
3
3
|
//#region src/jwt.d.ts
|
|
4
|
-
type LocalIssuerOptions = {
|
|
4
|
+
export type LocalIssuerOptions = {
|
|
5
5
|
readonly issuer: string;
|
|
6
6
|
readonly audience: string;
|
|
7
7
|
/** Asymmetric only, the same list `jwtAuthenticator` accepts; default `"RS256"`. */
|
|
8
8
|
readonly algorithm?: "RS256" | "RS384" | "RS512" | "ES256" | "ES384";
|
|
9
9
|
};
|
|
10
|
-
type SignOptions = {
|
|
10
|
+
export type SignOptions = {
|
|
11
11
|
readonly issuer?: string;
|
|
12
12
|
readonly audience?: string;
|
|
13
13
|
/** `"5m"` by default; `false` mints a token with no `exp` at all. */
|
|
14
14
|
readonly expiresIn?: string | false;
|
|
15
15
|
};
|
|
16
|
-
type LocalIssuer = {
|
|
16
|
+
export type LocalIssuer = {
|
|
17
17
|
/** `http://127.0.0.1:<port>/jwks.json` — served on ANY path, so a caller need not match it exactly. */
|
|
18
18
|
readonly jwks: string;
|
|
19
19
|
/** The public key as served, with `kid`/`alg`/`use` already set. */
|
|
@@ -31,6 +31,5 @@ type LocalIssuer = {
|
|
|
31
31
|
* listener answering the JWKS on any path, and `sign` closing over the
|
|
32
32
|
* private key. `close()` stops the listener; nothing else needs tearing down.
|
|
33
33
|
*/
|
|
34
|
-
declare const localIssuer: (options: LocalIssuerOptions) => AsyncResult<LocalIssuer, never>;
|
|
35
|
-
//#endregion
|
|
36
|
-
export { LocalIssuer, LocalIssuerOptions, SignOptions, localIssuer };
|
|
34
|
+
export declare const localIssuer: (options: LocalIssuerOptions) => AsyncResult<LocalIssuer, never>;
|
|
35
|
+
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@btravstack/testing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.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,25 +54,25 @@
|
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
+
"@btravstack/config": "0.15.0",
|
|
58
|
+
"@btravstack/core": "0.15.0",
|
|
59
|
+
"@btravstack/di": "0.15.0",
|
|
57
60
|
"@btravstack/tsconfig": "0.4.0",
|
|
58
|
-
"@types/node": "26.4.
|
|
59
|
-
"@unthrown/vitest": "5.
|
|
61
|
+
"@types/node": "26.4.1",
|
|
62
|
+
"@unthrown/vitest": "5.8.0",
|
|
60
63
|
"@vitest/coverage-v8": "4.1.11",
|
|
61
|
-
"jose": "6.2.
|
|
62
|
-
"tsdown": "0.
|
|
64
|
+
"jose": "6.2.12",
|
|
65
|
+
"tsdown": "0.23.0",
|
|
63
66
|
"typescript": "7.0.2",
|
|
64
|
-
"unthrown": "5.
|
|
65
|
-
"vitest": "4.1.11"
|
|
66
|
-
"@btravstack/config": "0.13.0",
|
|
67
|
-
"@btravstack/core": "0.13.0",
|
|
68
|
-
"@btravstack/di": "0.13.0"
|
|
67
|
+
"unthrown": "5.8.0",
|
|
68
|
+
"vitest": "4.1.11"
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
|
+
"@btravstack/config": "^0.15.0",
|
|
72
|
+
"@btravstack/core": "^0.15.0",
|
|
73
|
+
"@btravstack/di": "^0.15.0",
|
|
71
74
|
"jose": "^6",
|
|
72
|
-
"unthrown": "^5.0.0"
|
|
73
|
-
"@btravstack/config": "^0.13.0",
|
|
74
|
-
"@btravstack/core": "^0.13.0",
|
|
75
|
-
"@btravstack/di": "^0.13.0"
|
|
75
|
+
"unthrown": "^5.0.0"
|
|
76
76
|
},
|
|
77
77
|
"peerDependenciesMeta": {
|
|
78
78
|
"jose": {
|
|
@@ -86,7 +86,6 @@
|
|
|
86
86
|
"build": "tsdown src/index.ts src/jwt.ts --format cjs,esm --dts --clean",
|
|
87
87
|
"dev": "tsdown src/index.ts src/jwt.ts --format cjs,esm --dts --watch",
|
|
88
88
|
"test": "vitest run --coverage",
|
|
89
|
-
"test:types": "tsc --noEmit -p tsconfig.test-d.json",
|
|
90
89
|
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.test-d.json"
|
|
91
90
|
}
|
|
92
91
|
}
|