@znight/testing 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +441 -2
- package/dist/index.d.mts +697 -0
- package/dist/index.mjs +1561 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +49 -4
- package/src/config.ts +214 -0
- package/src/define-metadata.ts +255 -0
- package/src/extensions.ts +109 -0
- package/src/index.ts +58 -0
- package/src/metadata-index.ts +161 -0
- package/src/mock-fn.ts +83 -0
- package/src/mock-registry.ts +118 -0
- package/src/mock.ts +270 -0
- package/src/overrides.ts +54 -0
- package/src/spy.ts +246 -0
- package/src/test-app.ts +551 -0
- package/src/testbed-builder.ts +366 -0
- package/src/testbed.ts +97 -0
- package/src/types.ts +107 -0
- package/src/utils.ts +37 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,697 @@
|
|
|
1
|
+
import { Application, ClassKey, Container, CoreLogger, DependencyRef, ExternalDefinition, MethodInterception, Plugin, ProviderClass, ProviderDefinition, ProviderFactory, ProviderKey, ProviderValues, Scope, ShutdownOptions, SourceLocation, Token, TypedToken, ZnightExtensionsMetadata, ZnightMetadata } from "@znight/core";
|
|
2
|
+
/** Property values of one configuration class (`{ port: 8080 }`). */
|
|
3
|
+
type ConfigProperties = Readonly<Record<string, unknown>>;
|
|
4
|
+
/**
|
|
5
|
+
* Configuration values by configuration class, for `TestBed.create(..., { config })`: a record keyed
|
|
6
|
+
* by token, display name or `@Config` prefix, or `[ConfigClass, values]` pairs.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* config: { DatabaseConfig: { host: 'db.test' } }
|
|
10
|
+
* config: { database: { host: 'db.test' } } // @Config('database')
|
|
11
|
+
* config: [[DatabaseConfig, { host: 'db.test' }]]
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
type ConfigValues = Iterable<readonly [ProviderKey, ConfigProperties]> | Readonly<Record<string, ConfigProperties>>;
|
|
15
|
+
/**
|
|
16
|
+
* Public types of the mocks created by `@znight/testing`. They describe the Jest-compatible API
|
|
17
|
+
* shared by the built-in spy, `vi.fn()` (Vitest), `jest.fn()` (Jest) and `mock()` (`bun:test`).
|
|
18
|
+
*/
|
|
19
|
+
/** Any function. Every function type is assignable to it (parameters are contravariant). */
|
|
20
|
+
type AnyFunction = (...args: never[]) => unknown;
|
|
21
|
+
/**
|
|
22
|
+
* Signature of an untyped mock function: accepts any arguments and returns anything.
|
|
23
|
+
*/
|
|
24
|
+
type UntypedFunction = (...args: any[]) => any;
|
|
25
|
+
/** Outcome of one call of a mock function (`mock.results`). */
|
|
26
|
+
type MockResult<R> = {
|
|
27
|
+
readonly type: "return";
|
|
28
|
+
readonly value: R;
|
|
29
|
+
} | {
|
|
30
|
+
readonly type: "throw";
|
|
31
|
+
readonly value: unknown;
|
|
32
|
+
} | {
|
|
33
|
+
readonly type: "incomplete";
|
|
34
|
+
readonly value: undefined;
|
|
35
|
+
};
|
|
36
|
+
/** Recorded calls of a mock function (`fn.mock`). */
|
|
37
|
+
interface MockState<F extends AnyFunction = UntypedFunction> {
|
|
38
|
+
/** Arguments of every call, in call order. */
|
|
39
|
+
readonly calls: Parameters<F>[];
|
|
40
|
+
/** Outcome of every call, in call order. */
|
|
41
|
+
readonly results: MockResult<ReturnType<F>>[];
|
|
42
|
+
/** `this` of every call (the new instance for `new` calls). */
|
|
43
|
+
readonly instances: unknown[];
|
|
44
|
+
/** `this` of every call. */
|
|
45
|
+
readonly contexts: unknown[];
|
|
46
|
+
/** Global, monotonic order of every call (comparable across mocks). */
|
|
47
|
+
readonly invocationCallOrder: number[];
|
|
48
|
+
/** Arguments of the last call. */
|
|
49
|
+
readonly lastCall: Parameters<F> | undefined;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* A mock function (spy): callable like `F`, records its calls and can be programmed. The API is the
|
|
53
|
+
* common subset of `jest.fn()`, `vi.fn()` and `bun:test`'s `mock()`.
|
|
54
|
+
*/
|
|
55
|
+
interface MockFunction<F extends AnyFunction = UntypedFunction> {
|
|
56
|
+
(...args: Parameters<F>): ReturnType<F>;
|
|
57
|
+
readonly mock: MockState<F>;
|
|
58
|
+
/** Every call returns `value` (until reset). */
|
|
59
|
+
mockReturnValue(value: ReturnType<F>): this;
|
|
60
|
+
/** The next call returns `value`. Queued values are used before the default implementation. */
|
|
61
|
+
mockReturnValueOnce(value: ReturnType<F>): this;
|
|
62
|
+
/** Every call returns a promise resolved with `value`. */
|
|
63
|
+
mockResolvedValue(value: Awaited<ReturnType<F>>): this;
|
|
64
|
+
mockResolvedValueOnce(value: Awaited<ReturnType<F>>): this;
|
|
65
|
+
/** Every call returns a promise rejected with `error`. */
|
|
66
|
+
mockRejectedValue(error: unknown): this;
|
|
67
|
+
mockRejectedValueOnce(error: unknown): this;
|
|
68
|
+
mockImplementation(implementation: (...args: Parameters<F>) => ReturnType<F>): this;
|
|
69
|
+
mockImplementationOnce(implementation: (...args: Parameters<F>) => ReturnType<F>): this;
|
|
70
|
+
/** Every call returns its `this`. */
|
|
71
|
+
mockReturnThis(): this;
|
|
72
|
+
/** Name displayed by assertion messages. */
|
|
73
|
+
mockName(name: string): this;
|
|
74
|
+
getMockName(): string;
|
|
75
|
+
getMockImplementation(): ((...args: Parameters<F>) => ReturnType<F>) | undefined;
|
|
76
|
+
/** Forgets the recorded calls (implementations are kept). */
|
|
77
|
+
mockClear(): this;
|
|
78
|
+
/** Forgets the recorded calls and the programmed implementations. */
|
|
79
|
+
mockReset(): this;
|
|
80
|
+
mockRestore(): void;
|
|
81
|
+
}
|
|
82
|
+
/** A member of a {@link Mocked} object: methods become {@link MockFunction}s, objects are mocked deeply. */
|
|
83
|
+
type MockedMember<V> = V extends AnyFunction ? MockFunction<V> : V extends object ? Mocked<V> : V;
|
|
84
|
+
/**
|
|
85
|
+
* A mock of `T`: assignable to `T`, every method is a {@link MockFunction} and every object member
|
|
86
|
+
* is itself mocked.
|
|
87
|
+
*
|
|
88
|
+
* ```ts
|
|
89
|
+
* const repository: Mocked<UserRepository> = createMock<UserRepository>()
|
|
90
|
+
* repository.findById.mockResolvedValue(user)
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
type Mocked<T> = T & { [K in keyof T]: MockedMember<T[K]>; };
|
|
94
|
+
/**
|
|
95
|
+
* An untyped deep mock: every property is a callable {@link MockFunction} which is itself a deep
|
|
96
|
+
* mock (`mock.repository.findById.mockResolvedValue(user)`).
|
|
97
|
+
*/
|
|
98
|
+
interface DeepMock {
|
|
99
|
+
readonly [key: string]: DeepMockFunction;
|
|
100
|
+
}
|
|
101
|
+
/** A callable member of a {@link DeepMock}. */
|
|
102
|
+
type DeepMockFunction = MockFunction & DeepMock;
|
|
103
|
+
/**
|
|
104
|
+
* Creates a mock function from an optional implementation: `vi.fn`, `jest.fn`, `bun:test`'s `mock`
|
|
105
|
+
* or {@link createSpy}.
|
|
106
|
+
*/
|
|
107
|
+
type MockFnFactory = (implementation?: AnyFunction) => unknown;
|
|
108
|
+
/**
|
|
109
|
+
* Which spy implementation mocks use:
|
|
110
|
+
* - `'auto'` (default): Vitest (`globalThis.vi.fn`), Jest (`globalThis.jest.fn`), `bun:test`
|
|
111
|
+
* (`mock`, when running on Bun), otherwise the built-in spy;
|
|
112
|
+
* - `'builtin'`: the built-in Jest-compatible spy ({@link createSpy});
|
|
113
|
+
* - a factory such as `vi.fn`, `jest.fn` or `mock` from `bun:test`.
|
|
114
|
+
*/
|
|
115
|
+
type MockFnOption = MockFnFactory | "auto" | "builtin";
|
|
116
|
+
/**
|
|
117
|
+
* The auto-mocks of a `TestBed`, looked up by class, token, alias or display name.
|
|
118
|
+
*
|
|
119
|
+
* ```ts
|
|
120
|
+
* const { instance, mocks } = await TestBed.create(UserService, { metadata })
|
|
121
|
+
* mocks.get(UserRepository).findById.mockResolvedValue(user) // typed
|
|
122
|
+
* mocks.get('Logger').info // untyped deep mock
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
interface MockRegistry {
|
|
126
|
+
/**
|
|
127
|
+
* The auto-mock injected for `key`: a class (typed result), a token, an alias (interface, base
|
|
128
|
+
* class) or a unique display name (`'UserRepository'`).
|
|
129
|
+
*
|
|
130
|
+
* @throws ZnightError ZNIGHT001 when no auto-mock matches (the message says why: provided value,
|
|
131
|
+
* configuration class, optional dependency...), ZNIGHT008 when a display name is ambiguous.
|
|
132
|
+
*/
|
|
133
|
+
get<T>(key: ClassKey<T>): Mocked<T>;
|
|
134
|
+
get<T = never>(key: TypedToken<T>): [T] extends [never] ? DeepMock : Mocked<T>;
|
|
135
|
+
/** Whether an auto-mock matches `key`. */
|
|
136
|
+
has(key: ClassKey | Token): boolean;
|
|
137
|
+
/** Tokens of the auto-mocked dependencies, in injection order. */
|
|
138
|
+
tokens(): Token[];
|
|
139
|
+
/** `mockClear()` on every spy of every auto-mock (recorded calls are forgotten). */
|
|
140
|
+
clearAll(): void;
|
|
141
|
+
/** Resets every auto-mock to its initial state (calls and programmed behaviours are forgotten). */
|
|
142
|
+
resetAll(): void;
|
|
143
|
+
}
|
|
144
|
+
/** Options of {@link createMetadata}. */
|
|
145
|
+
interface CreateMetadataOptions {
|
|
146
|
+
readonly aliases?: Readonly<Record<Token, Token>>;
|
|
147
|
+
/** Externals, as tokens or full definitions (`{ token, scope, providedBy }`). */
|
|
148
|
+
readonly externals?: readonly (Token | ExternalDefinition)[];
|
|
149
|
+
readonly extensions?: ZnightExtensionsMetadata;
|
|
150
|
+
/** Default: a deterministic topological order (dependencies first, declaration order otherwise). */
|
|
151
|
+
readonly resolutionOrder?: readonly Token[];
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Hand-written metadata with the exact shape the compiler generates (version, resolution order...),
|
|
155
|
+
* for tests that do not run the compiler (plugins, libraries, edge cases).
|
|
156
|
+
*
|
|
157
|
+
* ```ts
|
|
158
|
+
* const metadata = createMetadata({
|
|
159
|
+
* 'src/clock.ts#Clock': { scope: 'singleton', class: Clock, deps: [], factory: () => new Clock() },
|
|
160
|
+
* })
|
|
161
|
+
* ```
|
|
162
|
+
*
|
|
163
|
+
* @throws ZnightError ZNIGHT005 for a malformed provider definition.
|
|
164
|
+
*/
|
|
165
|
+
export declare function createMetadata(providers: Readonly<Record<Token, ProviderDefinition>>, options?: CreateMetadataOptions): ZnightMetadata;
|
|
166
|
+
/** A provider class or a token, in {@link defineTestMetadata}. */
|
|
167
|
+
type TestKey = Token | ProviderClass | ClassKey;
|
|
168
|
+
/** A dependency in {@link defineTestMetadata}: like `DependencyRef`, with classes allowed in place of tokens. */
|
|
169
|
+
type TestDependency = TestKey | {
|
|
170
|
+
readonly token: TestKey;
|
|
171
|
+
readonly optional: true;
|
|
172
|
+
} | {
|
|
173
|
+
readonly multi: readonly TestKey[];
|
|
174
|
+
} | {
|
|
175
|
+
readonly lazy: TestKey;
|
|
176
|
+
};
|
|
177
|
+
/** A provider in {@link defineTestMetadata}. */
|
|
178
|
+
interface TestProvider<T = unknown> {
|
|
179
|
+
/** Default: `test#<ClassName>` (see `tokenPrefix`). Required without `class`. */
|
|
180
|
+
readonly token?: Token;
|
|
181
|
+
readonly class?: ProviderClass<T>;
|
|
182
|
+
/** Default: `'singleton'`. */
|
|
183
|
+
readonly scope?: Scope;
|
|
184
|
+
/** Constructor (or factory) dependencies, in parameter order. */
|
|
185
|
+
readonly deps?: readonly TestDependency[];
|
|
186
|
+
/** Default: `deps => new Class(...deps)`. Required without `class`. */
|
|
187
|
+
readonly factory?: ProviderFactory<T>;
|
|
188
|
+
readonly async?: boolean;
|
|
189
|
+
readonly interceptors?: Readonly<Record<string, MethodInterception>>;
|
|
190
|
+
readonly dispose?: string;
|
|
191
|
+
/** `@Named` qualifier. */
|
|
192
|
+
readonly name?: string;
|
|
193
|
+
readonly primary?: boolean;
|
|
194
|
+
readonly source?: SourceLocation;
|
|
195
|
+
}
|
|
196
|
+
/** Input of {@link defineTestMetadata}. */
|
|
197
|
+
interface TestMetadataSpec {
|
|
198
|
+
/** Providers: classes (no dependency) or {@link TestProvider}s. */
|
|
199
|
+
readonly providers?: readonly (TestProvider | ProviderClass)[];
|
|
200
|
+
/** Alias → provider pairs (`[UserRepository, PgUserRepository]`), or a record of tokens. */
|
|
201
|
+
readonly aliases?: Iterable<readonly [TestKey, TestKey]> | Readonly<Record<Token, TestKey>>;
|
|
202
|
+
readonly externals?: readonly (Token | ExternalDefinition)[];
|
|
203
|
+
/** Feature metadata (`http`, `messaging`, `config`), tokens written with {@link testToken}. */
|
|
204
|
+
readonly extensions?: ZnightExtensionsMetadata;
|
|
205
|
+
readonly resolutionOrder?: readonly Token[];
|
|
206
|
+
/** Prefix of the tokens derived from class names. Default: `'test'` (`test#UserService`). */
|
|
207
|
+
readonly tokenPrefix?: string;
|
|
208
|
+
}
|
|
209
|
+
/** The token {@link defineTestMetadata} derives from a class: `<prefix>#<ClassName>`. */
|
|
210
|
+
export declare function testToken(cls: ProviderClass | ClassKey, prefix?: string): Token;
|
|
211
|
+
/**
|
|
212
|
+
* Class-first hand-written metadata: tokens are derived from class names (`test#UserService`),
|
|
213
|
+
* dependencies may be classes, factories default to `new Class(...deps)` and the resolution order
|
|
214
|
+
* is computed.
|
|
215
|
+
*
|
|
216
|
+
* ```ts
|
|
217
|
+
* const metadata = defineTestMetadata({
|
|
218
|
+
* providers: [
|
|
219
|
+
* PgUserRepository,
|
|
220
|
+
* { class: UserService, deps: [PgUserRepository, '@znight/observability#Logger'] },
|
|
221
|
+
* ],
|
|
222
|
+
* aliases: [[UserRepository, PgUserRepository]],
|
|
223
|
+
* externals: ['@znight/observability#Logger'],
|
|
224
|
+
* })
|
|
225
|
+
* ```
|
|
226
|
+
*
|
|
227
|
+
* @throws ZnightError ZNIGHT004 for duplicate tokens; TypeError for a provider without class nor
|
|
228
|
+
* token/factory.
|
|
229
|
+
*/
|
|
230
|
+
export declare function defineTestMetadata(spec?: TestMetadataSpec): ZnightMetadata;
|
|
231
|
+
/** Options of {@link createMock}. */
|
|
232
|
+
interface CreateMockOptions {
|
|
233
|
+
/**
|
|
234
|
+
* Name of the mock, used to name its spies in assertion messages (`UserRepository.findById`).
|
|
235
|
+
* Default: the class name, or `mock`.
|
|
236
|
+
*/
|
|
237
|
+
readonly name?: string;
|
|
238
|
+
/**
|
|
239
|
+
* When `true`, calling an unconfigured method returns a deep mock (the same one for every call)
|
|
240
|
+
* instead of `undefined`, so fluent APIs work: `db.select().from('users')`. Default: `false`.
|
|
241
|
+
*/
|
|
242
|
+
readonly deep?: boolean;
|
|
243
|
+
/** Spy implementation. Default: auto-detected (see `MockFnOption`). */
|
|
244
|
+
readonly mockFn?: MockFnOption;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Creates a deep auto-mock.
|
|
248
|
+
*
|
|
249
|
+
* - Every property read returns a spy (`MockFunction`), created on first access and then stable.
|
|
250
|
+
* Spies are deep too: `mock.pool.query.mockResolvedValue(rows)`.
|
|
251
|
+
* - Unconfigured spies return `undefined` (or a deep mock with `{ deep: true }`).
|
|
252
|
+
* - The mock is **not thenable** and inert for serialisers: `then`, `toJSON`, `asymmetricMatch`,
|
|
253
|
+
* `$$typeof`, `Symbol.toPrimitive`... read as `undefined`, so `await mock`, `JSON.stringify(mock)`
|
|
254
|
+
* and `expect(...).toEqual(mock)` behave.
|
|
255
|
+
* - Assigned properties win: `mock.enabled = false`.
|
|
256
|
+
* - With a class, the mock inherits its prototype (`instanceof` works) and getters read as
|
|
257
|
+
* `undefined` instead of a (truthy) spy.
|
|
258
|
+
* - Functions of `partial` become spies with that implementation; other values are set as is.
|
|
259
|
+
*
|
|
260
|
+
* ```ts
|
|
261
|
+
* const repository = createMock(UserRepository, { findById: async id => ({ id }) })
|
|
262
|
+
* const logger = createMock<Logger>()
|
|
263
|
+
* logger.info('hello')
|
|
264
|
+
* expect(logger.info).toHaveBeenCalledWith('hello')
|
|
265
|
+
* ```
|
|
266
|
+
*/
|
|
267
|
+
export declare function createMock<T>(cls: ClassKey<T>, partial?: Partial<T>, options?: CreateMockOptions): Mocked<T>;
|
|
268
|
+
export declare function createMock<T = never>(partial?: Partial<T>, options?: CreateMockOptions): [T] extends [never] ? DeepMock : Mocked<T>;
|
|
269
|
+
/** Whether `value` is a mock (or one of its spies) created by {@link createMock}. */
|
|
270
|
+
export declare function isMock(value: unknown): boolean;
|
|
271
|
+
/** Forgets the calls recorded by every spy of `mock` (`mockClear()`); implementations are kept. */
|
|
272
|
+
export declare function clearMock(mock: object): void;
|
|
273
|
+
/**
|
|
274
|
+
* Resets every spy of `mock` to its initial state: recorded calls and programmed implementations
|
|
275
|
+
* are forgotten, implementations given to {@link createMock} (and deep returns) are restored.
|
|
276
|
+
*/
|
|
277
|
+
export declare function resetMock(mock: object): void;
|
|
278
|
+
/** Where the spy factory used by mocks comes from. */
|
|
279
|
+
type MockFnSource = "custom" | "vitest" | "jest" | "bun" | "builtin";
|
|
280
|
+
/** A spy factory and its origin (see {@link resolveMockFn}). */
|
|
281
|
+
interface ResolvedMockFn {
|
|
282
|
+
readonly source: MockFnSource;
|
|
283
|
+
readonly create: MockFnFactory;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Sets the spy factory used when `mockFn` is not passed explicitly (e.g. in a Vitest setup file:
|
|
287
|
+
* `setDefaultMockFn(vi.fn)`). Without argument, restores auto-detection.
|
|
288
|
+
*/
|
|
289
|
+
export declare function setDefaultMockFn(option?: MockFnOption): void;
|
|
290
|
+
/**
|
|
291
|
+
* Resolves a {@link MockFnOption} (default: the option set with {@link setDefaultMockFn}, `'auto'`
|
|
292
|
+
* initially) to a spy factory.
|
|
293
|
+
*/
|
|
294
|
+
export declare function resolveMockFn(option?: MockFnOption): ResolvedMockFn;
|
|
295
|
+
/**
|
|
296
|
+
* Auto-detects the spy factory of the running test framework: Vitest (`globalThis.vi.fn`, with
|
|
297
|
+
* `globals: true`), Jest (`globalThis.jest.fn`), `bun:test` (`mock`, loaded only when running on
|
|
298
|
+
* Bun), otherwise the built-in spy ({@link createSpy}).
|
|
299
|
+
*/
|
|
300
|
+
export declare function detectMockFn(): ResolvedMockFn;
|
|
301
|
+
/** A typed `[key, value]` entry for `overrides` / `providers` / `provide`. */
|
|
302
|
+
type OverrideEntry<T = unknown> = readonly [ProviderKey<T>, T];
|
|
303
|
+
/** A `[key, definition]` entry replacing a provider with a factory. */
|
|
304
|
+
type OverrideDefinitionEntry<T = unknown> = readonly [ProviderKey<T>, ProviderDefinition<T>];
|
|
305
|
+
/**
|
|
306
|
+
* A type-checked override: the value must match the type designated by the class or typed token.
|
|
307
|
+
*
|
|
308
|
+
* ```ts
|
|
309
|
+
* await TestApp.create({ metadata, overrides: [override(UserRepository, new InMemoryUserRepository())] })
|
|
310
|
+
* ```
|
|
311
|
+
*/
|
|
312
|
+
export declare function override<T>(key: ProviderKey<T>, value: NoInfer<T>): OverrideEntry<T>;
|
|
313
|
+
/** Options of {@link overrideFactory}. */
|
|
314
|
+
interface OverrideFactoryOptions {
|
|
315
|
+
/** Tokens resolved and passed to the factory, in order. Default: none. */
|
|
316
|
+
readonly deps?: readonly DependencyRef[];
|
|
317
|
+
/** Default: `'singleton'`. */
|
|
318
|
+
readonly scope?: Scope;
|
|
319
|
+
/** Set when the factory returns a promise (singletons only). */
|
|
320
|
+
readonly async?: boolean;
|
|
321
|
+
/** Method called when the instance is disposed. */
|
|
322
|
+
readonly dispose?: string;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Replaces a provider with a factory whose dependencies are resolved by the container (or, in
|
|
326
|
+
* `TestBed`, like the target's dependencies).
|
|
327
|
+
*
|
|
328
|
+
* ```ts
|
|
329
|
+
* overrideFactory(UserRepository, ([db]) => new InMemoryUserRepository(db), { deps: ['src/db.ts#Database'] })
|
|
330
|
+
* ```
|
|
331
|
+
*/
|
|
332
|
+
export declare function overrideFactory<T>(key: ProviderKey<T>, factory: ProviderFactory<NoInfer<T>>, options?: OverrideFactoryOptions): OverrideDefinitionEntry<T>;
|
|
333
|
+
/**
|
|
334
|
+
* Creates the built-in, dependency-free, Jest-compatible spy. It records `mock.calls`,
|
|
335
|
+
* `mock.results`, `mock.instances`, `mock.contexts`, `mock.invocationCallOrder` and `mock.lastCall`,
|
|
336
|
+
* supports `mockReturnValue(Once)`, `mockResolvedValue(Once)`, `mockRejectedValue(Once)`,
|
|
337
|
+
* `mockImplementation(Once)`, `mockReturnThis`, `mockName`, `mockClear`, `mockReset` and
|
|
338
|
+
* `mockRestore`, and is recognised by Jest's and Vitest's `expect` (`_isMockFunction`).
|
|
339
|
+
*
|
|
340
|
+
* `mockReset()` restores the implementation given to `createSpy()` (Vitest semantics).
|
|
341
|
+
*
|
|
342
|
+
* ```ts
|
|
343
|
+
* const find = createSpy((id: string) => ({ id }))
|
|
344
|
+
* find.mockReturnValueOnce({ id: 'x' })
|
|
345
|
+
* find('1')
|
|
346
|
+
* find.mock.calls // [['1']]
|
|
347
|
+
* ```
|
|
348
|
+
*/
|
|
349
|
+
export declare function createSpy<F extends AnyFunction = UntypedFunction>(implementation?: F): MockFunction<F>;
|
|
350
|
+
/** Whether `value` is a spy created by {@link createSpy}. */
|
|
351
|
+
export declare function isBuiltinSpy(value: unknown): boolean;
|
|
352
|
+
/** Name of the HTTP plugin `TestApp.inject()` delegates to (`HttpPlugin.configure()` from `@znight/http`). */
|
|
353
|
+
export declare const HTTP_PLUGIN_NAME = "http";
|
|
354
|
+
/** An in-memory HTTP request for {@link TestApp.inject}. */
|
|
355
|
+
interface InjectRequest {
|
|
356
|
+
/** HTTP method. Default: `GET`. */
|
|
357
|
+
readonly method?: string;
|
|
358
|
+
/** Path, with an optional query string (`/users?page=2`). */
|
|
359
|
+
readonly url: string;
|
|
360
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
361
|
+
/**
|
|
362
|
+
* Request body, encoded by the HTTP plugin: a string or bytes are sent as is (`text/plain` /
|
|
363
|
+
* `application/octet-stream` without `content-type` header), a `FormData` as
|
|
364
|
+
* `multipart/form-data` (files included: uploads), a `Blob` / `File` with its type, anything else
|
|
365
|
+
* as JSON (`application/json`).
|
|
366
|
+
*/
|
|
367
|
+
readonly body?: unknown;
|
|
368
|
+
/** Query parameters added to those of `url`. */
|
|
369
|
+
readonly query?: Readonly<Record<string, string | readonly string[]>>;
|
|
370
|
+
/**
|
|
371
|
+
* Request cookies (name → value), sent by the HTTP plugin in a `cookie` header, after any `cookie`
|
|
372
|
+
* header of `headers`. Values are encoded like the cookies the plugin sets, so a value read from
|
|
373
|
+
* `response.cookies` can be sent back as is (signed values included).
|
|
374
|
+
*/
|
|
375
|
+
readonly cookies?: Readonly<Record<string, string>>;
|
|
376
|
+
/**
|
|
377
|
+
* Cookies the HTTP plugin signs with its current secret (`cookies.secrets[0]`) and merges into
|
|
378
|
+
* `cookies` before dispatch: the way to send a valid `@SignedCookie`.
|
|
379
|
+
*/
|
|
380
|
+
readonly signedCookies?: Readonly<Record<string, string>>;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* A parsed `Set-Cookie` header of an {@link InjectResponse}: the shape of `SetCookieInfo` from
|
|
384
|
+
* `@znight/http`.
|
|
385
|
+
*/
|
|
386
|
+
interface SetCookieInfo {
|
|
387
|
+
readonly name: string;
|
|
388
|
+
/** Decoded value (a signed cookie: `<value>.<signature>`). */
|
|
389
|
+
readonly value: string;
|
|
390
|
+
/** The `Set-Cookie` header line. */
|
|
391
|
+
readonly raw: string;
|
|
392
|
+
readonly expires?: Date;
|
|
393
|
+
readonly maxAge?: number;
|
|
394
|
+
readonly domain?: string;
|
|
395
|
+
readonly path?: string;
|
|
396
|
+
readonly secure: boolean;
|
|
397
|
+
readonly httpOnly: boolean;
|
|
398
|
+
readonly sameSite?: "strict" | "lax" | "none";
|
|
399
|
+
readonly partitioned: boolean;
|
|
400
|
+
readonly priority?: "low" | "medium" | "high";
|
|
401
|
+
}
|
|
402
|
+
/** The response of {@link TestApp.inject}. */
|
|
403
|
+
interface InjectResponse {
|
|
404
|
+
readonly status: number;
|
|
405
|
+
/** Response headers (lower-cased names). */
|
|
406
|
+
readonly headers: Readonly<Record<string, string | readonly string[] | undefined>>;
|
|
407
|
+
/** The body decoded as UTF-8. */
|
|
408
|
+
readonly body: string;
|
|
409
|
+
/** The raw body bytes (downloads, binary responses). */
|
|
410
|
+
readonly bytes: Uint8Array;
|
|
411
|
+
/** The `set-cookie` headers parsed, by cookie name (the last one wins); `{}` without any. */
|
|
412
|
+
readonly cookies: Readonly<Record<string, SetCookieInfo>>;
|
|
413
|
+
/** The body parsed as JSON. */
|
|
414
|
+
json<T = unknown>(): T;
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* What the `inject()` of the HTTP plugin resolves with: an {@link InjectResponse} whose `bytes` and
|
|
418
|
+
* `cookies` may be absent (`TestApp.inject()` then encodes `body` as UTF-8 and returns no cookies).
|
|
419
|
+
*/
|
|
420
|
+
type HttpInjectResult = Omit<InjectResponse, "bytes" | "cookies"> & {
|
|
421
|
+
readonly bytes?: Uint8Array;
|
|
422
|
+
readonly cookies?: Readonly<Record<string, SetCookieInfo>>;
|
|
423
|
+
};
|
|
424
|
+
/**
|
|
425
|
+
* What `TestApp.inject()` expects from the plugin named `'http'`: an in-memory dispatch (no socket).
|
|
426
|
+
* `HttpPlugin` from `@znight/http` implements it.
|
|
427
|
+
*/
|
|
428
|
+
interface HttpInjector {
|
|
429
|
+
inject(request: InjectRequest & {
|
|
430
|
+
readonly method: string;
|
|
431
|
+
}): Promise<HttpInjectResult>;
|
|
432
|
+
}
|
|
433
|
+
/** A request for {@link TestApp.injectStream} / {@link TestApp.injectSse}: an {@link InjectRequest} that can be aborted. */
|
|
434
|
+
interface InjectStreamRequest extends InjectRequest {
|
|
435
|
+
/** Aborting it disconnects the client (like cancelling the response body). */
|
|
436
|
+
readonly signal?: AbortSignal;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* The response of {@link TestApp.injectStream}: available at the headers, the body read as it is
|
|
440
|
+
* produced. Cancelling `body` disconnects the client. The shape of `InjectStreamResponse` from
|
|
441
|
+
* `@znight/http`.
|
|
442
|
+
*/
|
|
443
|
+
interface InjectStreamResponse {
|
|
444
|
+
readonly status: number;
|
|
445
|
+
readonly headers: Readonly<Record<string, string | readonly string[] | undefined>>;
|
|
446
|
+
readonly cookies: Readonly<Record<string, SetCookieInfo>>;
|
|
447
|
+
readonly body: ReadableStream<Uint8Array>;
|
|
448
|
+
}
|
|
449
|
+
/** An event of an event stream (`SseMessage` of `@znight/http`). */
|
|
450
|
+
interface SseMessage {
|
|
451
|
+
/** Event type: `message` by default. */
|
|
452
|
+
readonly event: string;
|
|
453
|
+
readonly data: string;
|
|
454
|
+
/** The last event id at dispatch time. */
|
|
455
|
+
readonly id: string;
|
|
456
|
+
json<T = unknown>(): T;
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* The response of {@link TestApp.injectSse}: an event stream read in memory like `EventSource`
|
|
460
|
+
* would (`InjectSseResponse` of `@znight/http`).
|
|
461
|
+
*/
|
|
462
|
+
interface InjectSseResponse extends AsyncIterable<SseMessage>, AsyncDisposable {
|
|
463
|
+
readonly status: number;
|
|
464
|
+
readonly headers: Readonly<Record<string, string | readonly string[] | undefined>>;
|
|
465
|
+
readonly cookies: Readonly<Record<string, SetCookieInfo>>;
|
|
466
|
+
/** `''` for an event stream; otherwise the whole body (an error, a 204...). */
|
|
467
|
+
readonly body: string;
|
|
468
|
+
json<T = unknown>(): T;
|
|
469
|
+
/** The next event (comments skipped). Rejects on timeout (default 2 000 ms) or when the stream ended. */
|
|
470
|
+
next(options?: {
|
|
471
|
+
readonly timeoutMs?: number;
|
|
472
|
+
}): Promise<SseMessage>;
|
|
473
|
+
take(count: number, options?: {
|
|
474
|
+
readonly timeoutMs?: number;
|
|
475
|
+
}): Promise<SseMessage[]>;
|
|
476
|
+
/** Comments received so far (heartbeats are `''`). */
|
|
477
|
+
readonly comments: readonly string[];
|
|
478
|
+
/** What a browser would send as `Last-Event-ID`. */
|
|
479
|
+
readonly lastEventId: string;
|
|
480
|
+
/** The last `retry` received. */
|
|
481
|
+
readonly retry: number | undefined;
|
|
482
|
+
/** Resolves when the server ends the stream. */
|
|
483
|
+
readonly done: Promise<void>;
|
|
484
|
+
/** Disconnects (the server sees a client disconnect). Idempotent. */
|
|
485
|
+
close(): Promise<void>;
|
|
486
|
+
/** Reconnects like `EventSource`: the same request plus `last-event-id`. */
|
|
487
|
+
reconnect(): Promise<InjectSseResponse>;
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* What `TestApp.injectStream()` / `injectSse()` expect from the plugin named `'http'`
|
|
491
|
+
* (`HttpPlugin` of `@znight/http` ≥ 0.1.0, the release that ships streaming).
|
|
492
|
+
*/
|
|
493
|
+
interface HttpStreamInjector {
|
|
494
|
+
injectStream(request: InjectStreamRequest & {
|
|
495
|
+
readonly method: string;
|
|
496
|
+
}): Promise<InjectStreamResponse>;
|
|
497
|
+
injectSse(request: InjectStreamRequest & {
|
|
498
|
+
readonly method: string;
|
|
499
|
+
}): Promise<InjectSseResponse>;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* A plugin implementing the optional `initRoots(context)` member of `Plugin` (`@znight/core`), read
|
|
503
|
+
* by `TestApp.create()`: the providers the plugin needs at boot although the metadata does not make
|
|
504
|
+
* them entry points, i.e. classes or tokens given in its options (`HttpPlugin.configure({ guards,
|
|
505
|
+
* interceptors, exceptionMappers })`) or derived from its metadata section (`context.metadata`).
|
|
506
|
+
* `TestApp` adds them to the providers instantiated at boot (see {@link TestAppOptions.only}), so
|
|
507
|
+
* that their async dependencies exist when the plugin resolves them: an async factory cannot run on
|
|
508
|
+
* demand.
|
|
509
|
+
*
|
|
510
|
+
* Called once per `TestApp.create()`, before the application is created. Keys that are not
|
|
511
|
+
* providers of the metadata are ignored (the plugin reports them itself).
|
|
512
|
+
*/
|
|
513
|
+
type PluginInitRoots = Required<Pick<Plugin, "initRoots">>;
|
|
514
|
+
/** Options of {@link TestApp.create}. */
|
|
515
|
+
interface TestAppOptions {
|
|
516
|
+
/** The generated metadata (`__ZNIGHT_METADATA__`). */
|
|
517
|
+
readonly metadata: ZnightMetadata;
|
|
518
|
+
readonly plugins?: readonly Plugin[];
|
|
519
|
+
/** Values supplied by the application (externals, configuration...), as in `Application.create`. */
|
|
520
|
+
readonly providers?: ProviderValues;
|
|
521
|
+
/**
|
|
522
|
+
* Replacements applied last, with the highest precedence: values or provider definitions
|
|
523
|
+
* (`{ scope, deps, factory }`), keyed by class or token. Overridden providers are instantiated.
|
|
524
|
+
*/
|
|
525
|
+
readonly overrides?: ProviderValues;
|
|
526
|
+
/**
|
|
527
|
+
* Which providers are instantiated at boot (with their dependency closure, plus the overrides and
|
|
528
|
+
* the providers the plugins resolve at bootstrap, see {@link PluginInitRoots}: global guards,
|
|
529
|
+
* interceptors and exception mappers of `HttpPlugin`):
|
|
530
|
+
* - default: the entry points of the metadata, i.e. the HTTP controllers (with their guards and
|
|
531
|
+
* interceptors), the message consumers and the hosts of scheduled jobs, or every provider when
|
|
532
|
+
* there is none;
|
|
533
|
+
* - `'all'`: every provider;
|
|
534
|
+
* - a list of classes or tokens.
|
|
535
|
+
*
|
|
536
|
+
* Other providers are created on first use (synchronous factories only: list a provider here
|
|
537
|
+
* when it, or one of its dependencies, has an async factory).
|
|
538
|
+
*/
|
|
539
|
+
readonly only?: readonly ProviderKey[] | "all";
|
|
540
|
+
/** Application logger. Default: a console logger writing warnings and errors. */
|
|
541
|
+
readonly logger?: CoreLogger;
|
|
542
|
+
/** Run `app.start()` (plugins `onStart`: listen, subscribe...). Default: `true`. */
|
|
543
|
+
readonly start?: boolean;
|
|
544
|
+
/** Shutdown timeouts. Signal handlers are always disabled. */
|
|
545
|
+
readonly shutdown?: Omit<ShutdownOptions, "signals" | "process">;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* End-to-end harness: a started {@link Application} without signal handlers, overrides applied last
|
|
549
|
+
* and only what the tested entry points need instantiated.
|
|
550
|
+
*
|
|
551
|
+
* ```ts
|
|
552
|
+
* await using app = await TestApp.create({
|
|
553
|
+
* metadata: __ZNIGHT_METADATA__,
|
|
554
|
+
* plugins: [HttpPlugin.configure({ adapter: fastify() })],
|
|
555
|
+
* overrides: [[UserRepository, fakeRepository]],
|
|
556
|
+
* })
|
|
557
|
+
* const response = await app.inject({ method: 'GET', url: '/users/1' })
|
|
558
|
+
* expect(response.status).toBe(200)
|
|
559
|
+
* expect(response.json()).toEqual({ id: '1' })
|
|
560
|
+
* ```
|
|
561
|
+
*/
|
|
562
|
+
export declare class TestApp implements AsyncDisposable {
|
|
563
|
+
#private;
|
|
564
|
+
/** The application under test. */
|
|
565
|
+
readonly app: Application;
|
|
566
|
+
private constructor();
|
|
567
|
+
/**
|
|
568
|
+
* Creates and (by default) starts the application.
|
|
569
|
+
*
|
|
570
|
+
* Plugins are used as configured: give the servers they start a free port or none in tests
|
|
571
|
+
* (`HttpPlugin.configure({ port: 0 })`, `ObservabilityPlugin.configure({ metrics: { server: false } })`);
|
|
572
|
+
* a start failing on a port already in use (`EADDRINUSE`) gets a hint saying so.
|
|
573
|
+
*
|
|
574
|
+
* @throws the error of `Application.create()` / `app.start()` (everything is rolled back).
|
|
575
|
+
*/
|
|
576
|
+
static create(options: TestAppOptions): Promise<TestApp>;
|
|
577
|
+
/** The application container. */
|
|
578
|
+
get container(): Container;
|
|
579
|
+
/** Shortcut for `app.container.get(key)`. */
|
|
580
|
+
get<T>(key: ProviderClass<T>): T;
|
|
581
|
+
get<T>(key: ClassKey<T>): T;
|
|
582
|
+
get<T = unknown>(key: TypedToken<T>): T;
|
|
583
|
+
/**
|
|
584
|
+
* Dispatches a request in memory through the HTTP plugin (`HttpPlugin`): routing, guards,
|
|
585
|
+
* interceptors, validation, serialisation, without opening a socket. Send uploads as a
|
|
586
|
+
* `FormData` body; read downloads from `response.bytes`. Send cookies with `cookies` (and
|
|
587
|
+
* `signedCookies`), read those the response sets from `response.cookies`.
|
|
588
|
+
*
|
|
589
|
+
* @throws ZnightError ZNIGHT001 when the application has no HTTP plugin, ZNIGHT021 once closed.
|
|
590
|
+
*/
|
|
591
|
+
inject(request: InjectRequest): Promise<InjectResponse>;
|
|
592
|
+
/**
|
|
593
|
+
* Dispatches a request in memory and resolves at the response headers; the body is read as it is
|
|
594
|
+
* produced (`response.body`). Cancelling the body (or aborting `signal`) disconnects the client.
|
|
595
|
+
*
|
|
596
|
+
* @throws ZnightError ZNIGHT001 when the HTTP plugin does not support streaming, ZNIGHT021 once closed.
|
|
597
|
+
*/
|
|
598
|
+
injectStream(request: InjectStreamRequest): Promise<InjectStreamResponse>;
|
|
599
|
+
/**
|
|
600
|
+
* Opens an event stream (Server-Sent Events) in memory and reads it like `EventSource`:
|
|
601
|
+
*
|
|
602
|
+
* ```ts
|
|
603
|
+
* await using stream = await app.injectSse({ url: '/orders/o-1/events' })
|
|
604
|
+
* const event = await stream.next() // rejects after 2 000 ms
|
|
605
|
+
* expect(event.json()).toMatchObject({ status: 'paid' })
|
|
606
|
+
* const resumed = await stream.reconnect() // last-event-id, like EventSource
|
|
607
|
+
* ```
|
|
608
|
+
*
|
|
609
|
+
* Leaving the `await using` block (or `close()`) disconnects: the server sees `ctx.signal` abort.
|
|
610
|
+
*
|
|
611
|
+
* @throws ZnightError ZNIGHT001 when the HTTP plugin does not support event streams, ZNIGHT021 once closed.
|
|
612
|
+
*/
|
|
613
|
+
injectSse(request: InjectStreamRequest): Promise<InjectSseResponse>;
|
|
614
|
+
/** Stops the application (idempotent): plugins `onStop`, providers `onStop` and disposal, plugins `onDispose`. */
|
|
615
|
+
close(): Promise<void>;
|
|
616
|
+
/** {@link close}, for `await using app = await TestApp.create(...)`. */
|
|
617
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* How `@Intercept` interceptors of the target are handled:
|
|
621
|
+
* - `'none'` (default): interceptors are neither instantiated nor applied, the target's methods are
|
|
622
|
+
* the plain ones;
|
|
623
|
+
* - `'real'`: interceptors are built (their own dependencies auto-mocked) or taken from
|
|
624
|
+
* `provide`/`overrides`, and applied like the container does.
|
|
625
|
+
*/
|
|
626
|
+
type AopMode = "none" | "real";
|
|
627
|
+
/** Options of {@link TestBed.create}. */
|
|
628
|
+
interface TestBedOptions {
|
|
629
|
+
/** The generated metadata (`__ZNIGHT_METADATA__`). */
|
|
630
|
+
readonly metadata: ZnightMetadata;
|
|
631
|
+
/**
|
|
632
|
+
* Values injected instead of auto-mocks, keyed by class, token, alias or display name. Required
|
|
633
|
+
* for qualified values (`@Inject('dbUrl')`, `@Provides({ name })` without a class) such as
|
|
634
|
+
* primitives; also used for optional dependencies and members of multi dependencies.
|
|
635
|
+
*/
|
|
636
|
+
readonly provide?: ProviderValues;
|
|
637
|
+
/**
|
|
638
|
+
* Like `provide`, but a value shaped like a provider definition (`{ scope, deps, factory }`) is
|
|
639
|
+
* built with its factory, its own dependencies being resolved like the target's (auto-mocked...).
|
|
640
|
+
* A definition keyed by the target replaces the target's factory. Wins over `provide`.
|
|
641
|
+
*/
|
|
642
|
+
readonly overrides?: ProviderValues;
|
|
643
|
+
/** Values of configuration classes (real instances are injected for `@Config` classes). */
|
|
644
|
+
readonly config?: ConfigValues;
|
|
645
|
+
/** Spy implementation of the auto-mocks. Default: auto-detected. */
|
|
646
|
+
readonly mockFn?: MockFnOption;
|
|
647
|
+
/** Auto-mocks return deep mocks from unconfigured methods instead of `undefined`. Default: `false`. */
|
|
648
|
+
readonly deep?: boolean;
|
|
649
|
+
/** Interceptors handling, see {@link AopMode}. Default: `'none'`. */
|
|
650
|
+
readonly aop?: AopMode;
|
|
651
|
+
}
|
|
652
|
+
/** What {@link TestBed.create} returns. */
|
|
653
|
+
interface TestBedResult<T> {
|
|
654
|
+
/** The target, built with its real (generated) factory. */
|
|
655
|
+
readonly instance: T;
|
|
656
|
+
/** The auto-mocks injected into the target. */
|
|
657
|
+
readonly mocks: MockRegistry;
|
|
658
|
+
/**
|
|
659
|
+
* A container holding the target and everything injected into it (auto-mocks, provided values,
|
|
660
|
+
* configuration instances), for code that resolves dependencies itself.
|
|
661
|
+
*/
|
|
662
|
+
readonly container: Container;
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* Unit-test harness: builds one provider with its real factory and auto-mocks its **direct**
|
|
666
|
+
* dependencies, by kind:
|
|
667
|
+
*
|
|
668
|
+
* | Dependency | Injected |
|
|
669
|
+
* | -------------------------------------------- | --------------------------------------------------- |
|
|
670
|
+
* | class / interface / `@Provides` / external | deep auto-mock |
|
|
671
|
+
* | configuration class (`@Config`) | real instance: defaults + `config` values |
|
|
672
|
+
* | qualified value (`@Inject('x')`, primitives) | the `provide` value (an error otherwise) |
|
|
673
|
+
* | optional (`@Optional()`, `T \| undefined`) | `undefined` (or the `provide` value) |
|
|
674
|
+
* | multi (`T[]`) | `[]` (or the provided members) |
|
|
675
|
+
* | `Lazy<T>` | `{ get: () => mock }` |
|
|
676
|
+
* | interceptor (`@Intercept`) | nothing, not applied (unless `aop: 'real'`) |
|
|
677
|
+
*
|
|
678
|
+
* ```ts
|
|
679
|
+
* const { instance, mocks } = await TestBed.create(UserService, { metadata: __ZNIGHT_METADATA__ })
|
|
680
|
+
* mocks.get(UserRepository).findById.mockResolvedValue({ id: '1' })
|
|
681
|
+
* await instance.findById('1')
|
|
682
|
+
* expect(mocks.get(UserRepository).findById).toHaveBeenCalledWith('1')
|
|
683
|
+
* ```
|
|
684
|
+
*/
|
|
685
|
+
export declare class TestBed {
|
|
686
|
+
private constructor();
|
|
687
|
+
/**
|
|
688
|
+
* Builds `target` (a class, token, alias or display name of a provider of `options.metadata`).
|
|
689
|
+
*
|
|
690
|
+
* @throws ZnightError ZNIGHT001 (unknown target, qualified dependency without value), ZNIGHT012
|
|
691
|
+
* (invalid `config`), ZNIGHT015 (the factory failed).
|
|
692
|
+
*/
|
|
693
|
+
static create<T>(target: ProviderClass<T> | ClassKey<T>, options: TestBedOptions): Promise<TestBedResult<T>>;
|
|
694
|
+
static create<T = unknown>(target: TypedToken<T>, options: TestBedOptions): Promise<TestBedResult<T>>;
|
|
695
|
+
}
|
|
696
|
+
export type { AnyFunction, AopMode, ConfigProperties, ConfigValues, CreateMetadataOptions, CreateMockOptions, DeepMock, DeepMockFunction, HttpInjectResult, HttpInjector, HttpStreamInjector, InjectRequest, InjectResponse, InjectSseResponse, InjectStreamRequest, InjectStreamResponse, MockFnFactory, MockFnOption, MockFnSource, MockFunction, MockRegistry, MockResult, MockState, Mocked, MockedMember, OverrideDefinitionEntry, OverrideEntry, OverrideFactoryOptions, PluginInitRoots, ResolvedMockFn, SetCookieInfo, SseMessage, TestAppOptions, TestBedOptions, TestBedResult, TestDependency, TestKey, TestMetadataSpec, TestProvider, UntypedFunction };
|
|
697
|
+
//# sourceMappingURL=index.d.mts.map
|