@noego/testing 0.1.0 → 0.4.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 +94 -0
- package/dist/index.cjs +687 -637
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +278 -222
- package/dist/index.d.ts +278 -222
- package/dist/index.js +676 -618
- package/dist/index.js.map +1 -1
- package/package.json +7 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,262 +1,318 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IContainer, ApplicationModule } from '@noego/ioc';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Lowercase `test.*` descriptors — immutable frozen values.
|
|
5
|
+
*
|
|
6
|
+
* Descriptors carry NO mutable state (no cursors, no counters, no histories);
|
|
7
|
+
* all mutable invocation state lives in the built environment, so one
|
|
8
|
+
* descriptor value is safe to share across builders and repeated builds.
|
|
6
9
|
*/
|
|
7
|
-
declare
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
declare const DESCRIPTOR: unique symbol;
|
|
11
|
+
/** A raw custom method wrapper: (original) => replacement. NOT auto-watched. */
|
|
12
|
+
type RawMethodWrapper = (original: (...args: any[]) => any) => (...args: any[]) => any;
|
|
13
|
+
interface ReturnsDescriptor {
|
|
14
|
+
readonly [DESCRIPTOR]: true;
|
|
15
|
+
readonly kind: 'returns';
|
|
16
|
+
readonly value: unknown;
|
|
14
17
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
readonly
|
|
18
|
-
readonly
|
|
19
|
-
readonly deadline: Instant;
|
|
18
|
+
interface ThrowsDescriptor {
|
|
19
|
+
readonly [DESCRIPTOR]: true;
|
|
20
|
+
readonly kind: 'throws';
|
|
21
|
+
readonly error: unknown;
|
|
20
22
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
* Locked semantics:
|
|
25
|
-
* - deadlines are (scheduledAt + delay);
|
|
26
|
-
* - equal deadlines run in insertion order;
|
|
27
|
-
* - cancelled tasks never execute;
|
|
28
|
-
* - callbacks scheduled by callbacks are ordered deterministically (insertion
|
|
29
|
-
* sequence is global and monotonic);
|
|
30
|
-
* - async callbacks settle before advancing continues;
|
|
31
|
-
* - runUntilIdle fails with a bounded diagnostic on infinite reschedule loops;
|
|
32
|
-
* - assertNoPendingTasks fails teardown when tasks remain, unless allowed;
|
|
33
|
-
* - CHOSEN MODEL: advancing time RUNS every task whose deadline falls inside
|
|
34
|
-
* the advanced window, in deadline order. advanceBy(Duration.zero) runs
|
|
35
|
-
* tasks already due.
|
|
36
|
-
*/
|
|
37
|
-
declare class ManualScheduler extends Scheduler {
|
|
38
|
-
private readonly clock;
|
|
39
|
-
private readonly tasks;
|
|
40
|
-
private nextSequence;
|
|
41
|
-
private nextId;
|
|
42
|
-
constructor(clock: ManualClock);
|
|
43
|
-
schedule(input: ScheduleInput): ScheduledTaskHandle;
|
|
44
|
-
pending(): PendingTask[];
|
|
45
|
-
/** Advance the clock, running every task due inside the window in order. */
|
|
46
|
-
advanceBy(duration: Duration): Promise<void>;
|
|
47
|
-
/** Advance to the earliest pending deadline and run exactly that task. */
|
|
48
|
-
runNext(): Promise<void>;
|
|
49
|
-
/** Run tasks (advancing time as needed) until none remain. */
|
|
50
|
-
runUntilIdle(options?: {
|
|
51
|
-
maxTasks?: number;
|
|
52
|
-
}): Promise<void>;
|
|
53
|
-
/** Teardown assertion: fails when pending tasks remain, unless allowed. */
|
|
54
|
-
assertNoPendingTasks(options?: {
|
|
55
|
-
allow?: boolean;
|
|
56
|
-
}): void;
|
|
57
|
-
private live;
|
|
58
|
-
private nextDue;
|
|
59
|
-
private execute;
|
|
60
|
-
private remove;
|
|
23
|
+
interface OriginalDescriptor {
|
|
24
|
+
readonly [DESCRIPTOR]: true;
|
|
25
|
+
readonly kind: 'original';
|
|
61
26
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
*/
|
|
67
|
-
declare class SequenceIdGenerator extends IdGenerator {
|
|
68
|
-
private readonly counters;
|
|
69
|
-
next<TBrand extends string>(brand: TBrand): BrandedId<TBrand>;
|
|
27
|
+
interface CallsDescriptor {
|
|
28
|
+
readonly [DESCRIPTOR]: true;
|
|
29
|
+
readonly kind: 'calls';
|
|
30
|
+
readonly script: readonly BehaviorDescriptor[];
|
|
70
31
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
declare class SeededRandomSource extends RandomSource {
|
|
77
|
-
private state;
|
|
78
|
-
constructor(seed?: number);
|
|
79
|
-
private nextUint32;
|
|
80
|
-
bytes(length: number): Uint8Array;
|
|
81
|
-
integer(minInclusive: number, maxExclusive: number): number;
|
|
32
|
+
type BehaviorDescriptor = ReturnsDescriptor | ThrowsDescriptor | OriginalDescriptor | CallsDescriptor;
|
|
33
|
+
interface WatchDescriptor {
|
|
34
|
+
readonly [DESCRIPTOR]: true;
|
|
35
|
+
readonly kind: 'watch';
|
|
36
|
+
readonly wrapper?: RawMethodWrapper;
|
|
82
37
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
38
|
+
interface ExpectationDescriptor {
|
|
39
|
+
readonly [DESCRIPTOR]: true;
|
|
40
|
+
readonly kind: 'expect';
|
|
41
|
+
/** Exact required call count; 0 for never(). */
|
|
42
|
+
readonly expected: number;
|
|
43
|
+
/** Behavior used for allowed calls; undefined = original effective behavior. */
|
|
44
|
+
readonly behavior?: BehaviorDescriptor;
|
|
45
|
+
}
|
|
46
|
+
/** Everything installable through .methods({...}). */
|
|
47
|
+
type MethodDescriptor = BehaviorDescriptor | WatchDescriptor | ExpectationDescriptor | RawMethodWrapper;
|
|
48
|
+
declare const test: {
|
|
49
|
+
/** Return the supplied value when the method is called. Auto-watches. */
|
|
50
|
+
returns(value: unknown): ReturnsDescriptor;
|
|
51
|
+
/** Throw/reject with the supplied error. Auto-watches. */
|
|
52
|
+
throws(error: unknown): ThrowsDescriptor;
|
|
53
|
+
/** Invoke the original effective method. Auto-watches. */
|
|
54
|
+
original(): OriginalDescriptor;
|
|
55
|
+
/**
|
|
56
|
+
* Per-invocation behavior script: call 1 uses entry 1, and so on. A call
|
|
57
|
+
* after exhaustion fails immediately. Unused entries do not fail verification.
|
|
58
|
+
*/
|
|
59
|
+
calls(script: readonly BehaviorDescriptor[]): CallsDescriptor;
|
|
60
|
+
/**
|
|
61
|
+
* Keep original behavior and record calls. With a raw wrapper argument, the
|
|
62
|
+
* wrapper's behavior runs and is recorded.
|
|
63
|
+
*/
|
|
64
|
+
watch(wrapper?: RawMethodWrapper): WatchDescriptor;
|
|
65
|
+
/** Require exactly one call; with no behavior, the original runs. */
|
|
66
|
+
once(behavior?: BehaviorDescriptor): ExpectationDescriptor;
|
|
67
|
+
/** Require exactly `count` calls; with no behavior, the original runs. */
|
|
68
|
+
times(count: number, behavior?: BehaviorDescriptor): ExpectationDescriptor;
|
|
69
|
+
/** Require zero calls; the first invocation fails and skips the original. */
|
|
70
|
+
never(): ExpectationDescriptor;
|
|
71
|
+
/** Read the recorded history for a watched method in one environment. */
|
|
72
|
+
inspect(environment: unknown, token: unknown, method: string): MethodInspection;
|
|
73
|
+
};
|
|
74
|
+
/** Symbol under which a built environment exposes its watch registry. */
|
|
75
|
+
declare const ENV_REGISTRY: unique symbol;
|
|
76
|
+
interface RecordedCall {
|
|
77
|
+
/** 1-based invocation index in this environment. */
|
|
78
|
+
readonly index: number;
|
|
79
|
+
readonly args: readonly unknown[];
|
|
80
|
+
/** Present once the call returned (resolved value for async methods). */
|
|
81
|
+
readonly result?: unknown;
|
|
82
|
+
/** Present once the call threw/rejected. */
|
|
83
|
+
readonly error?: unknown;
|
|
84
|
+
/** True while an async outcome is still pending. */
|
|
85
|
+
readonly pending: boolean;
|
|
86
|
+
readonly timestamp: number;
|
|
87
|
+
}
|
|
88
|
+
interface MethodInspection {
|
|
89
|
+
readonly count: number;
|
|
90
|
+
readonly calls: readonly RecordedCall[];
|
|
91
91
|
}
|
|
92
|
+
|
|
92
93
|
/**
|
|
93
|
-
*
|
|
94
|
-
*
|
|
94
|
+
* Environment-owned method behavior/observation runtime.
|
|
95
|
+
*
|
|
96
|
+
* All mutable state (histories, expectation counters, calls-script cursors)
|
|
97
|
+
* lives here, created fresh at every build(). Descriptors stay immutable.
|
|
95
98
|
*/
|
|
96
|
-
declare class ScriptedFetchClient extends FetchClient {
|
|
97
|
-
private readonly script;
|
|
98
|
-
private cursor;
|
|
99
|
-
readonly executed: FetchRequest[];
|
|
100
|
-
constructor(script: readonly FetchScriptEntry[]);
|
|
101
|
-
execute(request: FetchRequest): Promise<FetchResponse>;
|
|
102
|
-
/** Teardown assertion: every scripted call must have been consumed. */
|
|
103
|
-
assertScriptConsumed(): void;
|
|
104
|
-
}
|
|
105
99
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
100
|
+
interface MutableCall {
|
|
101
|
+
index: number;
|
|
102
|
+
args: readonly unknown[];
|
|
103
|
+
result?: unknown;
|
|
104
|
+
error?: unknown;
|
|
105
|
+
pending: boolean;
|
|
106
|
+
timestamp: number;
|
|
110
107
|
}
|
|
111
|
-
|
|
112
|
-
readonly
|
|
113
|
-
readonly
|
|
114
|
-
|
|
115
|
-
readonly
|
|
108
|
+
declare class MethodState {
|
|
109
|
+
readonly tokenName: string;
|
|
110
|
+
readonly method: string;
|
|
111
|
+
readonly descriptor: Exclude<MethodDescriptor, RawMethodWrapper>;
|
|
112
|
+
readonly calls: MutableCall[];
|
|
113
|
+
/** Actual invocation count (includes the call currently executing). */
|
|
114
|
+
actual: number;
|
|
115
|
+
/** Cursor into a test.calls() script. */
|
|
116
|
+
scriptCursor: number;
|
|
117
|
+
constructor(tokenName: string, method: string, descriptor: Exclude<MethodDescriptor, RawMethodWrapper>);
|
|
118
|
+
get expectation(): ExpectationDescriptor | undefined;
|
|
119
|
+
inspection(): MethodInspection;
|
|
116
120
|
}
|
|
117
|
-
/**
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
private
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
121
|
+
/** One method-config entry: how it was keyed, and its per-method descriptors. */
|
|
122
|
+
interface MethodConfigEntry {
|
|
123
|
+
/** Exact token (class/symbol/string) or a name string matched lazily. */
|
|
124
|
+
readonly key: unknown;
|
|
125
|
+
readonly byName: boolean;
|
|
126
|
+
readonly methods: ReadonlyMap<string, MethodDescriptor>;
|
|
127
|
+
}
|
|
128
|
+
declare class WatchRegistry {
|
|
129
|
+
/** entry-identity → method → state. Entries share states across instances. */
|
|
130
|
+
private readonly states;
|
|
131
|
+
private readonly nameIndex;
|
|
132
|
+
private readonly entries;
|
|
133
|
+
/** Class-token entries that identity-matched at least one construction. */
|
|
134
|
+
private readonly matchedEntryKeys;
|
|
135
|
+
/** Constructed class tokens that matched NO entry, by display name. */
|
|
136
|
+
private readonly unmatchedConstructedByName;
|
|
137
|
+
addEntry(entry: MethodConfigEntry): void;
|
|
138
|
+
private entryLabel;
|
|
139
|
+
/** Entries applying to a resolving token (exact identity or name match). */
|
|
140
|
+
matchEntries(token: unknown): MethodConfigEntry[];
|
|
141
|
+
state(entryKey: unknown, method: string): MethodState | undefined;
|
|
142
|
+
inspect(token: unknown, method: string): MethodInspection;
|
|
143
|
+
/**
|
|
144
|
+
* Class-token entries that never identity-matched a construction while a
|
|
145
|
+
* DIFFERENT class with the same display name did construct. This is the
|
|
146
|
+
* split-module-registry signature (a test-file class object vs the graph's
|
|
147
|
+
* own load of the same file) — or two genuinely distinct same-named tokens
|
|
148
|
+
* where the configured one never resolved. Either way the configured
|
|
149
|
+
* behavior silently did not apply, which must be loud.
|
|
150
|
+
*/
|
|
151
|
+
private identitySplits;
|
|
152
|
+
/** Repeatable snapshot check of all exact expectations. */
|
|
153
|
+
verify(): void;
|
|
132
154
|
}
|
|
133
155
|
|
|
134
156
|
/**
|
|
135
|
-
*
|
|
136
|
-
*
|
|
157
|
+
* `testIoc` — the canonical shared real-IoC test composition builder.
|
|
158
|
+
*
|
|
159
|
+
* Persistent immutable: every fluent call returns a new derived builder
|
|
160
|
+
* sharing the ordered write log structurally. Non-conflicting writes are
|
|
161
|
+
* order-insensitive; the last write to the same effective identity wins on
|
|
162
|
+
* that derived branch. `.build()` is non-consuming and creates fresh runtime,
|
|
163
|
+
* watch, and expectation state (spec 15, PBR-01..15).
|
|
137
164
|
*/
|
|
138
|
-
declare class MemoryKeyValueStore extends KeyValueStore {
|
|
139
|
-
private readonly clock;
|
|
140
|
-
private readonly entries;
|
|
141
|
-
constructor(clock: Clock);
|
|
142
|
-
get<T>(key: Key, codec: Codec<T>): Promise<T | null>;
|
|
143
|
-
put<T>(key: Key, value: T, codec: Codec<T>, options?: PutOptions): Promise<void>;
|
|
144
|
-
delete(key: Key): Promise<void>;
|
|
145
|
-
}
|
|
146
165
|
|
|
166
|
+
type Token = unknown;
|
|
167
|
+
type ClassLike = new (...args: any[]) => any;
|
|
168
|
+
/** Config maps accept plain objects (string keys) or Maps (exact tokens). */
|
|
147
169
|
/**
|
|
148
|
-
*
|
|
149
|
-
*
|
|
170
|
+
* Composition input (spec 04 §2). The CANONICAL entry form is an array of
|
|
171
|
+
* tuples — token-first, exact identity:
|
|
172
|
+
*
|
|
173
|
+
* .classes([[ProjectRepository, MemoryProjectRepository]])
|
|
174
|
+
*
|
|
175
|
+
* A `ReadonlyMap<Token, V>` is equivalent (token-keyed). A name-keyed
|
|
176
|
+
* `Record<string, V>` remains accepted as COMPATIBILITY input: string keys
|
|
177
|
+
* resolve against known token display names, fail on unknown names, and
|
|
178
|
+
* fail on ambiguous names (two tokens sharing one display name never
|
|
179
|
+
* collapse into one entry — tokens are identities, names are labels).
|
|
150
180
|
*/
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
181
|
+
type ConfigMap<V> = ReadonlyArray<readonly [Token, V]> | ReadonlyMap<Token, V> | Record<string, V>;
|
|
182
|
+
type MethodsConfig = ConfigMap<Record<string, MethodDescriptor> | ReadonlyMap<string, MethodDescriptor>>;
|
|
183
|
+
type UseInput = ApplicationModule | TestIocBuilder;
|
|
184
|
+
type Write = {
|
|
185
|
+
op: 'use';
|
|
186
|
+
module: ApplicationModule;
|
|
187
|
+
} | {
|
|
188
|
+
op: 'classes';
|
|
189
|
+
key: Token;
|
|
190
|
+
byName: boolean;
|
|
191
|
+
implementation: ClassLike;
|
|
192
|
+
} | {
|
|
193
|
+
op: 'functions';
|
|
194
|
+
key: Token;
|
|
195
|
+
byName: boolean;
|
|
196
|
+
factory: (...args: any[]) => any;
|
|
197
|
+
} | {
|
|
198
|
+
op: 'values';
|
|
199
|
+
key: Token;
|
|
200
|
+
byName: boolean;
|
|
201
|
+
value: unknown;
|
|
202
|
+
} | {
|
|
203
|
+
op: 'methods';
|
|
204
|
+
key: Token;
|
|
205
|
+
byName: boolean;
|
|
206
|
+
methods: ReadonlyMap<string, MethodDescriptor>;
|
|
207
|
+
};
|
|
208
|
+
interface TestEnvironment {
|
|
209
|
+
readonly root: IContainer;
|
|
210
|
+
get<T>(token: unknown, params?: any[]): Promise<T> | T;
|
|
211
|
+
instance<T>(cls: new (...args: any[]) => T, params?: any[]): Promise<T> | T;
|
|
212
|
+
extend(): IContainer;
|
|
213
|
+
verify(): Promise<void>;
|
|
214
|
+
dispose(): Promise<void>;
|
|
215
|
+
readonly [ENV_REGISTRY]: WatchRegistry;
|
|
157
216
|
}
|
|
217
|
+
declare class TestIocBuilder {
|
|
218
|
+
private readonly log;
|
|
219
|
+
private constructor();
|
|
220
|
+
/** @internal */
|
|
221
|
+
static create(inputs: readonly UseInput[]): TestIocBuilder;
|
|
222
|
+
/** @internal — read by .use(builderPreset) */
|
|
223
|
+
get writes(): readonly Write[];
|
|
224
|
+
private derive;
|
|
225
|
+
private useAll;
|
|
226
|
+
/** Apply a reusable composition preset: an ApplicationModule or a builder. */
|
|
227
|
+
use(preset: UseInput): TestIocBuilder;
|
|
228
|
+
/** Replace the implementation for IoC class tokens in the built environment. */
|
|
229
|
+
classes(config: ConfigMap<ClassLike>): TestIocBuilder;
|
|
230
|
+
/** Replace IoC factory/provider registrations. */
|
|
231
|
+
functions(config: ConfigMap<(...args: any[]) => any>): TestIocBuilder;
|
|
232
|
+
/** Provide/replace IoC value registrations. */
|
|
233
|
+
values(config: ConfigMap<unknown>): TestIocBuilder;
|
|
234
|
+
/** Install method behavior/observation descriptors on IoC-managed instances. */
|
|
235
|
+
methods(config: MethodsConfig): TestIocBuilder;
|
|
236
|
+
/** Materialize a fresh, isolated real-IoC environment. Non-consuming. */
|
|
237
|
+
build(): Promise<TestEnvironment>;
|
|
238
|
+
/**
|
|
239
|
+
* Register a class binding. When token === implementation this is a plain
|
|
240
|
+
* class registration. Otherwise an alias factory resolves the implementation
|
|
241
|
+
* through real IoC, mirroring the implementation's effective lifetime so
|
|
242
|
+
* lifetime validation (captive-lifetime checks) stays honest.
|
|
243
|
+
*/
|
|
244
|
+
private registerClassBinding;
|
|
245
|
+
}
|
|
246
|
+
/** Create a persistent immutable real-IoC test composition builder. */
|
|
247
|
+
declare function testIoc(...inputs: UseInput[]): TestIocBuilder;
|
|
158
248
|
|
|
159
|
-
type DeliveryMode = "immediate" | "queued";
|
|
160
249
|
/**
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
* - queued: events buffer until deliverQueued() is called.
|
|
164
|
-
* Active subscriptions at teardown fail assertNoActiveSubscriptions().
|
|
250
|
+
* Diagnostics are first-class: every error names the real token/method and
|
|
251
|
+
* what was expected vs what happened, never only internal wrapper machinery.
|
|
165
252
|
*/
|
|
166
|
-
declare class
|
|
167
|
-
|
|
168
|
-
readonly published: TEvent[];
|
|
169
|
-
private readonly handlers;
|
|
170
|
-
private readonly queue;
|
|
171
|
-
constructor(mode?: DeliveryMode);
|
|
172
|
-
publish(event: TEvent): Promise<void>;
|
|
173
|
-
subscribe(handler: EventHandler<TEvent>): Subscription;
|
|
174
|
-
/** Deliver buffered events (queued mode) in publication order. */
|
|
175
|
-
deliverQueued(): Promise<void>;
|
|
176
|
-
get activeSubscriptionCount(): number;
|
|
177
|
-
assertNoActiveSubscriptions(): void;
|
|
178
|
-
private deliver;
|
|
253
|
+
declare class TestingError extends Error {
|
|
254
|
+
constructor(message: string);
|
|
179
255
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
readonly envelopes: LogEnvelope[];
|
|
184
|
-
emit(envelope: LogEnvelope): void;
|
|
256
|
+
/** Thrown at build() when the installed @noego/ioc lacks the decoration seam. */
|
|
257
|
+
declare class MissingIocSeamError extends TestingError {
|
|
258
|
+
constructor();
|
|
185
259
|
}
|
|
186
|
-
/**
|
|
187
|
-
declare class
|
|
188
|
-
|
|
189
|
-
emit(envelope: TraceEnvelope): void;
|
|
260
|
+
/** test.inspect() on a method that is not watched in this environment. */
|
|
261
|
+
declare class UnwatchedInspectionError extends TestingError {
|
|
262
|
+
constructor(token: string, method: string);
|
|
190
263
|
}
|
|
191
|
-
/**
|
|
192
|
-
declare class
|
|
193
|
-
|
|
194
|
-
emit(envelope: TelemetryEnvelope): void;
|
|
264
|
+
/** A call arrived after a test.calls([...]) script was fully consumed. */
|
|
265
|
+
declare class CallScriptExhaustedError extends TestingError {
|
|
266
|
+
constructor(token: string, method: string, scriptLength: number, callIndex: number);
|
|
195
267
|
}
|
|
196
|
-
/**
|
|
197
|
-
declare class
|
|
198
|
-
|
|
268
|
+
/** An exact expectation (once/times/never) was exceeded at call time. */
|
|
269
|
+
declare class ExpectationOverflowError extends TestingError {
|
|
270
|
+
constructor(token: string, method: string, expected: number, attempted: number);
|
|
199
271
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
})
|
|
208
|
-
|
|
209
|
-
interface KeyValueStoreContractContext {
|
|
210
|
-
store: KeyValueStore;
|
|
211
|
-
/** Move the store's time source forward (real adapters may wait/mock). */
|
|
212
|
-
advanceBy: (duration: Duration) => Promise<void>;
|
|
213
|
-
/** Whether the implementation supports TTL expiry. */
|
|
214
|
-
supportsTtl: boolean;
|
|
272
|
+
/** Aggregated under-count failures reported by env.verify(). */
|
|
273
|
+
declare class VerificationError extends TestingError {
|
|
274
|
+
constructor(failures: readonly {
|
|
275
|
+
token: string;
|
|
276
|
+
method: string;
|
|
277
|
+
expected: number;
|
|
278
|
+
actual: number;
|
|
279
|
+
}[]);
|
|
215
280
|
}
|
|
216
|
-
/**
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
* Behavioral contract every ObjectStore implementation must satisfy —
|
|
224
|
-
* memory, R2, S3, and filesystem adapters alike.
|
|
225
|
-
*/
|
|
226
|
-
declare function runObjectStoreContract(name: string, setup: () => {
|
|
227
|
-
store: ObjectStore;
|
|
228
|
-
}): void;
|
|
229
|
-
|
|
230
|
-
interface TestEvent extends DomainEvent {
|
|
231
|
-
readonly type: "test-event";
|
|
232
|
-
readonly value: number;
|
|
281
|
+
/** .methods configured for a token whose resolved value has no such callable method. */
|
|
282
|
+
declare class MethodNotCallableError extends TestingError {
|
|
283
|
+
constructor(token: string, method: string);
|
|
284
|
+
}
|
|
285
|
+
/** .methods configured for a token that resolved to a non-object value. */
|
|
286
|
+
declare class NonObjectMethodTargetError extends TestingError {
|
|
287
|
+
constructor(token: string);
|
|
233
288
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
289
|
+
/** A string configuration key could not be resolved to a known IoC token. */
|
|
290
|
+
declare class UnknownTokenKeyError extends TestingError {
|
|
291
|
+
constructor(key: string, space: string, known: readonly string[]);
|
|
292
|
+
}
|
|
293
|
+
/** Invalid descriptor construction (e.g. test.times(-1)). */
|
|
294
|
+
declare class InvalidDescriptorError extends TestingError {
|
|
239
295
|
}
|
|
240
296
|
/**
|
|
241
|
-
*
|
|
297
|
+
* A name-keyed compatibility entry referred to a display name claimed by
|
|
298
|
+
* two or more distinct tokens. Tokens are identities; names are labels —
|
|
299
|
+
* pass the exact token in canonical tuple form instead (spec 04 §5).
|
|
242
300
|
*/
|
|
243
|
-
declare
|
|
244
|
-
|
|
245
|
-
interface LeakCheck {
|
|
246
|
-
/** Which resource family this check guards (timers, subscriptions, …). */
|
|
247
|
-
readonly name: string;
|
|
248
|
-
/** Returns a description per leaked resource; empty means clean. */
|
|
249
|
-
readonly check: () => readonly string[];
|
|
301
|
+
declare class AmbiguousNameKeyError extends TestingError {
|
|
302
|
+
constructor(name: string, space: string);
|
|
250
303
|
}
|
|
251
304
|
/**
|
|
252
|
-
*
|
|
253
|
-
*
|
|
305
|
+
* A .methods() class token never matched any constructed instance while a
|
|
306
|
+
* DIFFERENT class with the same display name did construct — the configured
|
|
307
|
+
* behavior silently did not apply. Usual cause: two module registries loaded
|
|
308
|
+
* the same source file (e.g. a vitest test file's import vs a framework
|
|
309
|
+
* harness's native import of the production graph); fix by routing the
|
|
310
|
+
* harness's imports through the caller's registry (testApp:
|
|
311
|
+
* `.importer((p) => import(p))`) or by passing the token the graph actually
|
|
312
|
+
* uses.
|
|
254
313
|
*/
|
|
255
|
-
declare class
|
|
256
|
-
|
|
257
|
-
register(check: LeakCheck): void;
|
|
258
|
-
findLeaks(): string[];
|
|
259
|
-
assertNoLeaks(): void;
|
|
314
|
+
declare class TokenIdentitySplitError extends TestingError {
|
|
315
|
+
constructor(names: readonly string[]);
|
|
260
316
|
}
|
|
261
317
|
|
|
262
|
-
export { type
|
|
318
|
+
export { AmbiguousNameKeyError, type BehaviorDescriptor, CallScriptExhaustedError, type CallsDescriptor, type ConfigMap, ENV_REGISTRY, type ExpectationDescriptor, ExpectationOverflowError, InvalidDescriptorError, type MethodDescriptor, type MethodInspection, MethodNotCallableError, type MethodsConfig, MissingIocSeamError, NonObjectMethodTargetError, type OriginalDescriptor, type RawMethodWrapper, type RecordedCall, type ReturnsDescriptor, type TestEnvironment, TestIocBuilder, TestingError, type ThrowsDescriptor, TokenIdentitySplitError, UnknownTokenKeyError, UnwatchedInspectionError, type UseInput, VerificationError, type WatchDescriptor, test, testIoc };
|