@stratal/testing 0.0.13 → 0.0.15
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/dist/index.d.mts +1130 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +1788 -0
- package/dist/index.mjs.map +1 -0
- package/dist/mocks/index.d.mts +2 -0
- package/dist/mocks/index.mjs +2 -0
- package/dist/mocks/nodemailer.d.mts +12 -0
- package/dist/mocks/nodemailer.d.mts.map +1 -0
- package/dist/mocks/nodemailer.mjs +7 -0
- package/dist/mocks/nodemailer.mjs.map +1 -0
- package/dist/mocks/zenstack-language.d.mts +48 -0
- package/dist/mocks/zenstack-language.d.mts.map +1 -0
- package/dist/mocks/zenstack-language.mjs +48 -0
- package/dist/mocks/zenstack-language.mjs.map +1 -0
- package/dist/vitest-plugin/index.d.mts +50 -0
- package/dist/vitest-plugin/index.d.mts.map +1 -0
- package/dist/vitest-plugin/index.mjs +86 -0
- package/dist/vitest-plugin/index.mjs.map +1 -0
- package/package.json +21 -19
- package/dist/auth/acting-as.d.ts +0 -21
- package/dist/auth/acting-as.d.ts.map +0 -1
- package/dist/auth/acting-as.js +0 -68
- package/dist/auth/acting-as.js.map +0 -1
- package/dist/auth/index.d.ts +0 -2
- package/dist/auth/index.d.ts.map +0 -1
- package/dist/auth/index.js +0 -2
- package/dist/auth/index.js.map +0 -1
- package/dist/core/env/index.d.ts +0 -2
- package/dist/core/env/index.d.ts.map +0 -1
- package/dist/core/env/index.js +0 -2
- package/dist/core/env/index.js.map +0 -1
- package/dist/core/env/test-env.d.ts +0 -9
- package/dist/core/env/test-env.d.ts.map +0 -1
- package/dist/core/env/test-env.js +0 -14
- package/dist/core/env/test-env.js.map +0 -1
- package/dist/core/http/fetch-mock.types.d.ts +0 -48
- package/dist/core/http/fetch-mock.types.d.ts.map +0 -1
- package/dist/core/http/fetch-mock.types.js +0 -2
- package/dist/core/http/fetch-mock.types.js.map +0 -1
- package/dist/core/http/index.d.ts +0 -6
- package/dist/core/http/index.d.ts.map +0 -1
- package/dist/core/http/index.js +0 -5
- package/dist/core/http/index.js.map +0 -1
- package/dist/core/http/mock-fetch.d.ts +0 -88
- package/dist/core/http/mock-fetch.d.ts.map +0 -1
- package/dist/core/http/mock-fetch.js +0 -111
- package/dist/core/http/mock-fetch.js.map +0 -1
- package/dist/core/http/test-http-client.d.ts +0 -54
- package/dist/core/http/test-http-client.d.ts.map +0 -1
- package/dist/core/http/test-http-client.js +0 -75
- package/dist/core/http/test-http-client.js.map +0 -1
- package/dist/core/http/test-http-request.d.ts +0 -60
- package/dist/core/http/test-http-request.d.ts.map +0 -1
- package/dist/core/http/test-http-request.js +0 -106
- package/dist/core/http/test-http-request.js.map +0 -1
- package/dist/core/http/test-response.d.ts +0 -161
- package/dist/core/http/test-response.d.ts.map +0 -1
- package/dist/core/http/test-response.js +0 -309
- package/dist/core/http/test-response.js.map +0 -1
- package/dist/core/index.d.ts +0 -7
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js +0 -7
- package/dist/core/index.js.map +0 -1
- package/dist/core/override/index.d.ts +0 -2
- package/dist/core/override/index.d.ts.map +0 -1
- package/dist/core/override/index.js +0 -2
- package/dist/core/override/index.js.map +0 -1
- package/dist/core/override/provider-override-builder.d.ts +0 -78
- package/dist/core/override/provider-override-builder.d.ts.map +0 -1
- package/dist/core/override/provider-override-builder.js +0 -94
- package/dist/core/override/provider-override-builder.js.map +0 -1
- package/dist/core/sse/index.d.ts +0 -3
- package/dist/core/sse/index.d.ts.map +0 -1
- package/dist/core/sse/index.js +0 -3
- package/dist/core/sse/index.js.map +0 -1
- package/dist/core/sse/test-sse-connection.d.ts +0 -61
- package/dist/core/sse/test-sse-connection.d.ts.map +0 -1
- package/dist/core/sse/test-sse-connection.js +0 -233
- package/dist/core/sse/test-sse-connection.js.map +0 -1
- package/dist/core/sse/test-sse-request.d.ts +0 -42
- package/dist/core/sse/test-sse-request.d.ts.map +0 -1
- package/dist/core/sse/test-sse-request.js +0 -76
- package/dist/core/sse/test-sse-request.js.map +0 -1
- package/dist/core/test.d.ts +0 -48
- package/dist/core/test.d.ts.map +0 -1
- package/dist/core/test.js +0 -53
- package/dist/core/test.js.map +0 -1
- package/dist/core/testing-module-builder.d.ts +0 -57
- package/dist/core/testing-module-builder.d.ts.map +0 -1
- package/dist/core/testing-module-builder.js +0 -109
- package/dist/core/testing-module-builder.js.map +0 -1
- package/dist/core/testing-module.d.ts +0 -113
- package/dist/core/testing-module.d.ts.map +0 -1
- package/dist/core/testing-module.js +0 -177
- package/dist/core/testing-module.js.map +0 -1
- package/dist/core/ws/index.d.ts +0 -3
- package/dist/core/ws/index.d.ts.map +0 -1
- package/dist/core/ws/index.js +0 -3
- package/dist/core/ws/index.js.map +0 -1
- package/dist/core/ws/test-ws-connection.d.ts +0 -54
- package/dist/core/ws/test-ws-connection.d.ts.map +0 -1
- package/dist/core/ws/test-ws-connection.js +0 -119
- package/dist/core/ws/test-ws-connection.js.map +0 -1
- package/dist/core/ws/test-ws-request.d.ts +0 -43
- package/dist/core/ws/test-ws-request.d.ts.map +0 -1
- package/dist/core/ws/test-ws-request.js +0 -83
- package/dist/core/ws/test-ws-request.js.map +0 -1
- package/dist/errors/index.d.ts +0 -3
- package/dist/errors/index.d.ts.map +0 -1
- package/dist/errors/index.js +0 -3
- package/dist/errors/index.js.map +0 -1
- package/dist/errors/setup-error.d.ts +0 -9
- package/dist/errors/setup-error.d.ts.map +0 -1
- package/dist/errors/setup-error.js +0 -11
- package/dist/errors/setup-error.js.map +0 -1
- package/dist/errors/test-error.d.ts +0 -9
- package/dist/errors/test-error.d.ts.map +0 -1
- package/dist/errors/test-error.js +0 -15
- package/dist/errors/test-error.js.map +0 -1
- package/dist/index.d.ts +0 -21
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -29
- package/dist/index.js.map +0 -1
- package/dist/mocks/index.d.ts +0 -3
- package/dist/mocks/index.d.ts.map +0 -1
- package/dist/mocks/index.js +0 -3
- package/dist/mocks/index.js.map +0 -1
- package/dist/mocks/nodemailer.d.ts +0 -10
- package/dist/mocks/nodemailer.d.ts.map +0 -1
- package/dist/mocks/nodemailer.js +0 -9
- package/dist/mocks/nodemailer.js.map +0 -1
- package/dist/mocks/zenstack-language.d.ts +0 -46
- package/dist/mocks/zenstack-language.d.ts.map +0 -1
- package/dist/mocks/zenstack-language.js +0 -47
- package/dist/mocks/zenstack-language.js.map +0 -1
- package/dist/storage/fake-storage.service.d.ts +0 -114
- package/dist/storage/fake-storage.service.d.ts.map +0 -1
- package/dist/storage/fake-storage.service.js +0 -233
- package/dist/storage/fake-storage.service.js.map +0 -1
- package/dist/storage/index.d.ts +0 -2
- package/dist/storage/index.d.ts.map +0 -1
- package/dist/storage/index.js +0 -2
- package/dist/storage/index.js.map +0 -1
- package/dist/types.d.ts +0 -5
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -3
- package/dist/types.js.map +0 -1
- package/dist/vitest-plugin/index.d.ts +0 -2
- package/dist/vitest-plugin/index.d.ts.map +0 -1
- package/dist/vitest-plugin/index.js +0 -2
- package/dist/vitest-plugin/index.js.map +0 -1
- package/dist/vitest-plugin/stratal-test.d.ts +0 -28
- package/dist/vitest-plugin/stratal-test.d.ts.map +0 -1
- package/dist/vitest-plugin/stratal-test.js +0 -47
- package/dist/vitest-plugin/stratal-test.js.map +0 -1
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,1130 @@
|
|
|
1
|
+
import { Application, ApplicationConfig, Constructor, StratalEnv } from "stratal";
|
|
2
|
+
import { DynamicModule, InjectionToken, ModuleClass, ModuleOptions } from "stratal/module";
|
|
3
|
+
import { DownloadResult, PresignedUrlResult, StorageConfig, StorageManagerService, StorageService, StreamingBlobPayloadInputTypes, UploadOptions, UploadResult } from "stratal/storage";
|
|
4
|
+
import { Container } from "stratal/di";
|
|
5
|
+
import { ConnectionName, DatabaseService } from "@stratal/framework/database";
|
|
6
|
+
import { Seeder } from "stratal/seeder";
|
|
7
|
+
import { AuthService } from "@stratal/framework/auth";
|
|
8
|
+
import { HttpResponse, RequestHandler, http } from "msw";
|
|
9
|
+
import { CommandInput, CommandResult } from "stratal/quarry";
|
|
10
|
+
|
|
11
|
+
//#region src/storage/fake-storage.service.d.ts
|
|
12
|
+
/**
|
|
13
|
+
* Stored file representation in memory
|
|
14
|
+
*/
|
|
15
|
+
interface StoredFile {
|
|
16
|
+
content: Uint8Array;
|
|
17
|
+
mimeType: string;
|
|
18
|
+
size: number;
|
|
19
|
+
metadata?: Record<string, string>;
|
|
20
|
+
uploadedAt: Date;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* FakeStorageService
|
|
24
|
+
*
|
|
25
|
+
* In-memory storage implementation for testing.
|
|
26
|
+
* Registered by default in TestingModuleBuilder.
|
|
27
|
+
*
|
|
28
|
+
* Similar to Laravel's Storage::fake() - stores files in memory
|
|
29
|
+
* and provides assertion helpers for testing.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* // Access via TestingModule
|
|
34
|
+
* module.storage.assertExists('path/to/file.pdf')
|
|
35
|
+
* module.storage.assertMissing('deleted/file.pdf')
|
|
36
|
+
* module.storage.clear() // Reset between tests
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
declare class FakeStorageService extends StorageService {
|
|
40
|
+
protected readonly storageManager: StorageManagerService;
|
|
41
|
+
protected readonly options: StorageConfig;
|
|
42
|
+
private files;
|
|
43
|
+
constructor(storageManager: StorageManagerService, options: StorageConfig);
|
|
44
|
+
/**
|
|
45
|
+
* Upload content to fake storage
|
|
46
|
+
*/
|
|
47
|
+
upload(body: StreamingBlobPayloadInputTypes, relativePath: string, options: UploadOptions, disk?: string): Promise<UploadResult>;
|
|
48
|
+
/**
|
|
49
|
+
* Download a file from fake storage
|
|
50
|
+
*/
|
|
51
|
+
download(path: string): Promise<DownloadResult>;
|
|
52
|
+
/**
|
|
53
|
+
* Delete a file from fake storage
|
|
54
|
+
*/
|
|
55
|
+
delete(path: string): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Check if a file exists in fake storage
|
|
58
|
+
*/
|
|
59
|
+
exists(path: string): Promise<boolean>;
|
|
60
|
+
/**
|
|
61
|
+
* Generate a fake presigned download URL
|
|
62
|
+
*/
|
|
63
|
+
getPresignedDownloadUrl(path: string, expiresIn?: number): Promise<PresignedUrlResult>;
|
|
64
|
+
/**
|
|
65
|
+
* Generate a fake presigned upload URL
|
|
66
|
+
*/
|
|
67
|
+
getPresignedUploadUrl(path: string, expiresIn?: number): Promise<PresignedUrlResult>;
|
|
68
|
+
/**
|
|
69
|
+
* Generate a fake presigned delete URL
|
|
70
|
+
*/
|
|
71
|
+
getPresignedDeleteUrl(path: string, expiresIn?: number): Promise<PresignedUrlResult>;
|
|
72
|
+
/**
|
|
73
|
+
* Chunked upload (same as regular upload for fake)
|
|
74
|
+
*/
|
|
75
|
+
chunkedUpload(body: StreamingBlobPayloadInputTypes, path: string, options: Omit<UploadOptions, 'size'> & {
|
|
76
|
+
size?: number;
|
|
77
|
+
}, disk?: string): Promise<UploadResult>;
|
|
78
|
+
/**
|
|
79
|
+
* Assert that a file exists at the given path
|
|
80
|
+
*
|
|
81
|
+
* @param path - Path to check
|
|
82
|
+
* @throws AssertionError if file does not exist
|
|
83
|
+
*/
|
|
84
|
+
assertExists(path: string): void;
|
|
85
|
+
/**
|
|
86
|
+
* Assert that a file does NOT exist at the given path
|
|
87
|
+
*
|
|
88
|
+
* @param path - Path to check
|
|
89
|
+
* @throws AssertionError if file exists
|
|
90
|
+
*/
|
|
91
|
+
assertMissing(path: string): void;
|
|
92
|
+
/**
|
|
93
|
+
* Assert storage is empty
|
|
94
|
+
*
|
|
95
|
+
* @throws AssertionError if any files exist
|
|
96
|
+
*/
|
|
97
|
+
assertEmpty(): void;
|
|
98
|
+
/**
|
|
99
|
+
* Assert storage has exactly N files
|
|
100
|
+
*
|
|
101
|
+
* @param count - Expected number of files
|
|
102
|
+
* @throws AssertionError if count doesn't match
|
|
103
|
+
*/
|
|
104
|
+
assertCount(count: number): void;
|
|
105
|
+
/**
|
|
106
|
+
* Get all stored files (for inspection)
|
|
107
|
+
*/
|
|
108
|
+
getStoredFiles(): Map<string, StoredFile>;
|
|
109
|
+
/**
|
|
110
|
+
* Get all stored file paths
|
|
111
|
+
*/
|
|
112
|
+
getStoredPaths(): string[];
|
|
113
|
+
/**
|
|
114
|
+
* Get a specific file by path
|
|
115
|
+
*/
|
|
116
|
+
getFile(path: string): StoredFile | undefined;
|
|
117
|
+
/**
|
|
118
|
+
* Clear all stored files (call in beforeEach for test isolation)
|
|
119
|
+
*/
|
|
120
|
+
clear(): void;
|
|
121
|
+
private createPresignedUrl;
|
|
122
|
+
private bodyToUint8Array;
|
|
123
|
+
}
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region src/core/http/test-response.d.ts
|
|
126
|
+
/**
|
|
127
|
+
* TestResponse
|
|
128
|
+
*
|
|
129
|
+
* Wrapper around Response with assertion methods.
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```typescript
|
|
133
|
+
* response
|
|
134
|
+
* .assertOk()
|
|
135
|
+
* .assertStatus(200)
|
|
136
|
+
* .assertJsonPath('data.id', userId)
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
declare class TestResponse {
|
|
140
|
+
private readonly response;
|
|
141
|
+
private jsonData;
|
|
142
|
+
private textData;
|
|
143
|
+
constructor(response: Response);
|
|
144
|
+
/**
|
|
145
|
+
* Get the raw Response object.
|
|
146
|
+
*/
|
|
147
|
+
get raw(): Response;
|
|
148
|
+
/**
|
|
149
|
+
* Get the response status code.
|
|
150
|
+
*/
|
|
151
|
+
get status(): number;
|
|
152
|
+
/**
|
|
153
|
+
* Get response headers.
|
|
154
|
+
*/
|
|
155
|
+
get headers(): Headers;
|
|
156
|
+
/**
|
|
157
|
+
* Get the response body as JSON.
|
|
158
|
+
*/
|
|
159
|
+
json<T = unknown>(): Promise<T>;
|
|
160
|
+
/**
|
|
161
|
+
* Get the response body as text.
|
|
162
|
+
*/
|
|
163
|
+
text(): Promise<string>;
|
|
164
|
+
/**
|
|
165
|
+
* Assert response status is 200 OK.
|
|
166
|
+
*/
|
|
167
|
+
assertOk(): this;
|
|
168
|
+
/**
|
|
169
|
+
* Assert response status is 201 Created.
|
|
170
|
+
*/
|
|
171
|
+
assertCreated(): this;
|
|
172
|
+
/**
|
|
173
|
+
* Assert response status is 204 No Content.
|
|
174
|
+
*/
|
|
175
|
+
assertNoContent(): this;
|
|
176
|
+
/**
|
|
177
|
+
* Assert response status is 400 Bad Request.
|
|
178
|
+
*/
|
|
179
|
+
assertBadRequest(): this;
|
|
180
|
+
/**
|
|
181
|
+
* Assert response status is 401 Unauthorized.
|
|
182
|
+
*/
|
|
183
|
+
assertUnauthorized(): this;
|
|
184
|
+
/**
|
|
185
|
+
* Assert response status is 403 Forbidden.
|
|
186
|
+
*/
|
|
187
|
+
assertForbidden(): this;
|
|
188
|
+
/**
|
|
189
|
+
* Assert response status is 404 Not Found.
|
|
190
|
+
*/
|
|
191
|
+
assertNotFound(): this;
|
|
192
|
+
/**
|
|
193
|
+
* Assert response status is 422 Unprocessable Entity.
|
|
194
|
+
*/
|
|
195
|
+
assertUnprocessable(): this;
|
|
196
|
+
/**
|
|
197
|
+
* Assert response status is 500 Internal Server Error.
|
|
198
|
+
*/
|
|
199
|
+
assertServerError(): this;
|
|
200
|
+
/**
|
|
201
|
+
* Assert response has the given status code.
|
|
202
|
+
*/
|
|
203
|
+
assertStatus(expected: number): this;
|
|
204
|
+
/**
|
|
205
|
+
* Assert response status is in the 2xx success range.
|
|
206
|
+
*/
|
|
207
|
+
assertSuccessful(): this;
|
|
208
|
+
/**
|
|
209
|
+
* Assert JSON response contains the given data.
|
|
210
|
+
*/
|
|
211
|
+
assertJson(expected: Record<string, unknown>): Promise<this>;
|
|
212
|
+
/**
|
|
213
|
+
* Assert JSON response has value at the given path.
|
|
214
|
+
*
|
|
215
|
+
* @param path - Dot-notation path (e.g., 'data.user.id')
|
|
216
|
+
* @param expected - Expected value at path
|
|
217
|
+
*/
|
|
218
|
+
assertJsonPath(path: string, expected: unknown): Promise<this>;
|
|
219
|
+
/**
|
|
220
|
+
* Assert JSON response structure matches the given schema.
|
|
221
|
+
*/
|
|
222
|
+
assertJsonStructure(structure: string[]): Promise<this>;
|
|
223
|
+
/**
|
|
224
|
+
* Assert a JSON path exists (value can be anything, including null).
|
|
225
|
+
*
|
|
226
|
+
* @param path - Dot-notation path (e.g., 'data.user.id')
|
|
227
|
+
*/
|
|
228
|
+
assertJsonPathExists(path: string): Promise<this>;
|
|
229
|
+
/**
|
|
230
|
+
* Assert a JSON path does not exist.
|
|
231
|
+
*
|
|
232
|
+
* @param path - Dot-notation path (e.g., 'data.user.deletedAt')
|
|
233
|
+
*/
|
|
234
|
+
assertJsonPathMissing(path: string): Promise<this>;
|
|
235
|
+
/**
|
|
236
|
+
* Assert JSON value at path matches a custom predicate.
|
|
237
|
+
*
|
|
238
|
+
* @param path - Dot-notation path (e.g., 'data.items')
|
|
239
|
+
* @param matcher - Predicate function to validate the value
|
|
240
|
+
*/
|
|
241
|
+
assertJsonPathMatches(path: string, matcher: (value: unknown) => boolean): Promise<this>;
|
|
242
|
+
/**
|
|
243
|
+
* Assert string value at path contains a substring.
|
|
244
|
+
*
|
|
245
|
+
* @param path - Dot-notation path (e.g., 'data.message')
|
|
246
|
+
* @param substring - Substring to search for
|
|
247
|
+
*/
|
|
248
|
+
assertJsonPathContains(path: string, substring: string): Promise<this>;
|
|
249
|
+
/**
|
|
250
|
+
* Assert array value at path includes a specific item.
|
|
251
|
+
*
|
|
252
|
+
* @param path - Dot-notation path (e.g., 'data.tags')
|
|
253
|
+
* @param item - Item to search for in the array
|
|
254
|
+
*/
|
|
255
|
+
assertJsonPathIncludes(path: string, item: unknown): Promise<this>;
|
|
256
|
+
/**
|
|
257
|
+
* Assert array length at path equals the expected count.
|
|
258
|
+
*
|
|
259
|
+
* @param path - Dot-notation path (e.g., 'data.items')
|
|
260
|
+
* @param count - Expected array length
|
|
261
|
+
*/
|
|
262
|
+
assertJsonPathCount(path: string, count: number): Promise<this>;
|
|
263
|
+
/**
|
|
264
|
+
* Assert multiple JSON paths at once (batch assertion).
|
|
265
|
+
*
|
|
266
|
+
* @param expectations - Object mapping paths to expected values
|
|
267
|
+
*/
|
|
268
|
+
assertJsonPaths(expectations: Record<string, unknown>): Promise<this>;
|
|
269
|
+
/**
|
|
270
|
+
* Assert response has the given header.
|
|
271
|
+
*/
|
|
272
|
+
assertHeader(name: string, expected?: string): this;
|
|
273
|
+
/**
|
|
274
|
+
* Assert response does not have the given header.
|
|
275
|
+
*/
|
|
276
|
+
assertHeaderMissing(name: string): this;
|
|
277
|
+
/**
|
|
278
|
+
* Get value at dot-notation path.
|
|
279
|
+
*/
|
|
280
|
+
private getValueAtPath;
|
|
281
|
+
/**
|
|
282
|
+
* Check if a path exists in the object (even if value is null/undefined).
|
|
283
|
+
*/
|
|
284
|
+
private hasValueAtPath;
|
|
285
|
+
}
|
|
286
|
+
//#endregion
|
|
287
|
+
//#region src/core/http/test-http-request.d.ts
|
|
288
|
+
/**
|
|
289
|
+
* TestHttpRequest
|
|
290
|
+
*
|
|
291
|
+
* Request builder with fluent API for configuring test HTTP requests.
|
|
292
|
+
*
|
|
293
|
+
* @example
|
|
294
|
+
* ```typescript
|
|
295
|
+
* const response = await module.http
|
|
296
|
+
* .post('/api/v1/register')
|
|
297
|
+
* .withBody({ name: 'Test School' })
|
|
298
|
+
* .withHeaders({ 'X-Custom': 'value' })
|
|
299
|
+
* .send()
|
|
300
|
+
* ```
|
|
301
|
+
*
|
|
302
|
+
* @example Authenticated request
|
|
303
|
+
* ```typescript
|
|
304
|
+
* const response = await module.http
|
|
305
|
+
* .get('/api/v1/profile')
|
|
306
|
+
* .actingAs({ id: user.id })
|
|
307
|
+
* .send()
|
|
308
|
+
* ```
|
|
309
|
+
*/
|
|
310
|
+
declare class TestHttpRequest {
|
|
311
|
+
private readonly method;
|
|
312
|
+
private readonly path;
|
|
313
|
+
private readonly module;
|
|
314
|
+
private readonly host;
|
|
315
|
+
private body;
|
|
316
|
+
private requestHeaders;
|
|
317
|
+
private actingAsUser;
|
|
318
|
+
constructor(method: string, path: string, headers: Headers, module: TestingModule, host?: string | null);
|
|
319
|
+
/**
|
|
320
|
+
* Set the request body
|
|
321
|
+
*/
|
|
322
|
+
withBody(data: unknown): this;
|
|
323
|
+
/**
|
|
324
|
+
* Add headers to the request
|
|
325
|
+
*/
|
|
326
|
+
withHeaders(headers: Record<string, string>): this;
|
|
327
|
+
/**
|
|
328
|
+
* Set Content-Type to application/json
|
|
329
|
+
*/
|
|
330
|
+
asJson(): this;
|
|
331
|
+
/**
|
|
332
|
+
* Authenticate the request as a specific user
|
|
333
|
+
*/
|
|
334
|
+
actingAs(user: {
|
|
335
|
+
id: string;
|
|
336
|
+
}): this;
|
|
337
|
+
/**
|
|
338
|
+
* Send the request and return response
|
|
339
|
+
*
|
|
340
|
+
* Calls module.fetch() - NOT SELF.fetch()
|
|
341
|
+
*/
|
|
342
|
+
send(): Promise<TestResponse>;
|
|
343
|
+
private applyAuthentication;
|
|
344
|
+
}
|
|
345
|
+
//#endregion
|
|
346
|
+
//#region src/core/http/test-http-client.d.ts
|
|
347
|
+
/**
|
|
348
|
+
* TestHttpClient
|
|
349
|
+
*
|
|
350
|
+
* Fluent HTTP client for making test requests.
|
|
351
|
+
*
|
|
352
|
+
* @example
|
|
353
|
+
* ```typescript
|
|
354
|
+
* const response = await module.http
|
|
355
|
+
* .forHost('example.com')
|
|
356
|
+
* .post('/api/v1/users')
|
|
357
|
+
* .withBody({ name: 'Test' })
|
|
358
|
+
* .send()
|
|
359
|
+
*
|
|
360
|
+
* response.assertCreated()
|
|
361
|
+
* ```
|
|
362
|
+
*/
|
|
363
|
+
declare class TestHttpClient {
|
|
364
|
+
private readonly module;
|
|
365
|
+
private defaultHeaders;
|
|
366
|
+
private host;
|
|
367
|
+
constructor(module: TestingModule);
|
|
368
|
+
/**
|
|
369
|
+
* Set the host for the request
|
|
370
|
+
*/
|
|
371
|
+
forHost(host: string): this;
|
|
372
|
+
/**
|
|
373
|
+
* Set default headers for all requests
|
|
374
|
+
*/
|
|
375
|
+
withHeaders(headers: Record<string, string>): this;
|
|
376
|
+
/**
|
|
377
|
+
* Create a GET request
|
|
378
|
+
*/
|
|
379
|
+
get(path: string): TestHttpRequest;
|
|
380
|
+
/**
|
|
381
|
+
* Create a POST request
|
|
382
|
+
*/
|
|
383
|
+
post(path: string): TestHttpRequest;
|
|
384
|
+
/**
|
|
385
|
+
* Create a PUT request
|
|
386
|
+
*/
|
|
387
|
+
put(path: string): TestHttpRequest;
|
|
388
|
+
/**
|
|
389
|
+
* Create a PATCH request
|
|
390
|
+
*/
|
|
391
|
+
patch(path: string): TestHttpRequest;
|
|
392
|
+
/**
|
|
393
|
+
* Create a DELETE request
|
|
394
|
+
*/
|
|
395
|
+
delete(path: string): TestHttpRequest;
|
|
396
|
+
private createRequest;
|
|
397
|
+
}
|
|
398
|
+
//#endregion
|
|
399
|
+
//#region src/core/quarry/test-command-result.d.ts
|
|
400
|
+
/**
|
|
401
|
+
* Fluent assertion wrapper for command results.
|
|
402
|
+
*
|
|
403
|
+
* @example
|
|
404
|
+
* ```typescript
|
|
405
|
+
* const result = await module
|
|
406
|
+
* .quarry('users:create')
|
|
407
|
+
* .withInput({ email: 'test@example.com' })
|
|
408
|
+
* .run()
|
|
409
|
+
*
|
|
410
|
+
* result.assertSuccessful()
|
|
411
|
+
* result.assertOutputContains('User created')
|
|
412
|
+
* ```
|
|
413
|
+
*/
|
|
414
|
+
declare class TestCommandResult {
|
|
415
|
+
private readonly result;
|
|
416
|
+
constructor(result: CommandResult);
|
|
417
|
+
get exitCode(): number;
|
|
418
|
+
get output(): string[];
|
|
419
|
+
get errors(): string[];
|
|
420
|
+
assertSuccessful(): this;
|
|
421
|
+
assertFailed(exitCode?: number): this;
|
|
422
|
+
assertExitCode(code: number): this;
|
|
423
|
+
assertOutputContains(text: string): this;
|
|
424
|
+
assertOutputMissing(text: string): this;
|
|
425
|
+
assertErrorContains(text: string): this;
|
|
426
|
+
assertErrorMissing(text: string): this;
|
|
427
|
+
}
|
|
428
|
+
//#endregion
|
|
429
|
+
//#region src/core/quarry/test-command-request.d.ts
|
|
430
|
+
/**
|
|
431
|
+
* Fluent builder for testing Quarry commands.
|
|
432
|
+
*
|
|
433
|
+
* @example
|
|
434
|
+
* ```typescript
|
|
435
|
+
* const result = await module
|
|
436
|
+
* .quarry('users:create')
|
|
437
|
+
* .withInput({ email: 'test@example.com', admin: true })
|
|
438
|
+
* .run()
|
|
439
|
+
*
|
|
440
|
+
* result.assertSuccessful()
|
|
441
|
+
* result.assertOutputContains('User created')
|
|
442
|
+
* ```
|
|
443
|
+
*/
|
|
444
|
+
declare class TestCommandRequest {
|
|
445
|
+
private readonly commandName;
|
|
446
|
+
private readonly module;
|
|
447
|
+
private _input;
|
|
448
|
+
constructor(commandName: string, module: TestingModule);
|
|
449
|
+
/**
|
|
450
|
+
* Set the flat input for the command.
|
|
451
|
+
*/
|
|
452
|
+
withInput(input: CommandInput): this;
|
|
453
|
+
/**
|
|
454
|
+
* Execute the command and return a TestCommandResult for assertions.
|
|
455
|
+
*/
|
|
456
|
+
run(): Promise<TestCommandResult>;
|
|
457
|
+
}
|
|
458
|
+
//#endregion
|
|
459
|
+
//#region src/core/sse/test-sse-connection.d.ts
|
|
460
|
+
/**
|
|
461
|
+
* Represents a parsed SSE event
|
|
462
|
+
*/
|
|
463
|
+
interface TestSseEvent {
|
|
464
|
+
data: string;
|
|
465
|
+
event?: string;
|
|
466
|
+
id?: string;
|
|
467
|
+
retry?: number;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* TestSseConnection
|
|
471
|
+
*
|
|
472
|
+
* Live SSE connection wrapper with assertion helpers for testing.
|
|
473
|
+
*
|
|
474
|
+
* @example
|
|
475
|
+
* ```typescript
|
|
476
|
+
* const sse = await module.sse('/streaming/sse').connect()
|
|
477
|
+
* await sse.assertEvent({ event: 'message', data: 'hello', id: '1' })
|
|
478
|
+
* await sse.waitForEnd()
|
|
479
|
+
* ```
|
|
480
|
+
*/
|
|
481
|
+
declare class TestSseConnection {
|
|
482
|
+
private readonly response;
|
|
483
|
+
private readonly eventQueue;
|
|
484
|
+
private eventWaiters;
|
|
485
|
+
private streamEnded;
|
|
486
|
+
private endWaiters;
|
|
487
|
+
constructor(response: Response);
|
|
488
|
+
/**
|
|
489
|
+
* Wait for the next SSE event
|
|
490
|
+
*/
|
|
491
|
+
waitForEvent(timeout?: number): Promise<TestSseEvent>;
|
|
492
|
+
/**
|
|
493
|
+
* Wait for the stream to end
|
|
494
|
+
*/
|
|
495
|
+
waitForEnd(timeout?: number): Promise<void>;
|
|
496
|
+
/**
|
|
497
|
+
* Collect all remaining events until the stream ends
|
|
498
|
+
*/
|
|
499
|
+
collectEvents(timeout?: number): Promise<TestSseEvent[]>;
|
|
500
|
+
/**
|
|
501
|
+
* Assert that the next event matches the expected partial shape
|
|
502
|
+
*/
|
|
503
|
+
assertEvent(expected: Partial<TestSseEvent>, timeout?: number): Promise<void>;
|
|
504
|
+
/**
|
|
505
|
+
* Assert that the next event's data matches the expected string
|
|
506
|
+
*/
|
|
507
|
+
assertEventData(expected: string, timeout?: number): Promise<void>;
|
|
508
|
+
/**
|
|
509
|
+
* Assert that the next event's data is JSON matching the expected value
|
|
510
|
+
*/
|
|
511
|
+
assertJsonEventData<T>(expected: T, timeout?: number): Promise<void>;
|
|
512
|
+
/**
|
|
513
|
+
* Access the raw Response
|
|
514
|
+
*/
|
|
515
|
+
get raw(): Response;
|
|
516
|
+
private startReading;
|
|
517
|
+
private parseEvent;
|
|
518
|
+
private dispatchEvent;
|
|
519
|
+
}
|
|
520
|
+
//#endregion
|
|
521
|
+
//#region src/core/sse/test-sse-request.d.ts
|
|
522
|
+
/**
|
|
523
|
+
* TestSseRequest
|
|
524
|
+
*
|
|
525
|
+
* Builder for SSE connection requests. Follows the TestWsRequest pattern.
|
|
526
|
+
*
|
|
527
|
+
* @example
|
|
528
|
+
* ```typescript
|
|
529
|
+
* const sse = await module.sse('/streaming/sse').connect()
|
|
530
|
+
* await sse.assertEvent({ event: 'message', data: 'hello' })
|
|
531
|
+
* await sse.waitForEnd()
|
|
532
|
+
* ```
|
|
533
|
+
*
|
|
534
|
+
* @example Authenticated SSE
|
|
535
|
+
* ```typescript
|
|
536
|
+
* const sse = await module.sse('/streaming/sse').actingAs({ id: user.id }).connect()
|
|
537
|
+
* ```
|
|
538
|
+
*/
|
|
539
|
+
declare class TestSseRequest {
|
|
540
|
+
private readonly path;
|
|
541
|
+
private readonly module;
|
|
542
|
+
private requestHeaders;
|
|
543
|
+
private actingAsUser;
|
|
544
|
+
constructor(path: string, module: TestingModule);
|
|
545
|
+
/**
|
|
546
|
+
* Add custom headers to the request
|
|
547
|
+
*/
|
|
548
|
+
withHeaders(headers: Record<string, string>): this;
|
|
549
|
+
/**
|
|
550
|
+
* Authenticate the SSE connection as a specific user
|
|
551
|
+
*/
|
|
552
|
+
actingAs(user: {
|
|
553
|
+
id: string;
|
|
554
|
+
}): this;
|
|
555
|
+
/**
|
|
556
|
+
* Send the request and return a live SSE connection
|
|
557
|
+
*/
|
|
558
|
+
connect(): Promise<TestSseConnection>;
|
|
559
|
+
private applyAuthentication;
|
|
560
|
+
}
|
|
561
|
+
//#endregion
|
|
562
|
+
//#region src/core/ws/test-ws-connection.d.ts
|
|
563
|
+
/**
|
|
564
|
+
* TestWsConnection
|
|
565
|
+
*
|
|
566
|
+
* Live WebSocket connection wrapper with assertion helpers for testing.
|
|
567
|
+
*
|
|
568
|
+
* @example
|
|
569
|
+
* ```typescript
|
|
570
|
+
* const ws = await module.ws('/ws/chat').connect()
|
|
571
|
+
* ws.send('hello')
|
|
572
|
+
* await ws.assertMessage('echo:hello')
|
|
573
|
+
* ws.close()
|
|
574
|
+
* await ws.waitForClose()
|
|
575
|
+
* ```
|
|
576
|
+
*/
|
|
577
|
+
declare class TestWsConnection {
|
|
578
|
+
private readonly ws;
|
|
579
|
+
private readonly messageQueue;
|
|
580
|
+
private messageWaiters;
|
|
581
|
+
private closeEvent;
|
|
582
|
+
private closeWaiters;
|
|
583
|
+
constructor(ws: WebSocket);
|
|
584
|
+
/**
|
|
585
|
+
* Send a message through the WebSocket
|
|
586
|
+
*/
|
|
587
|
+
send(data: string | ArrayBuffer | Uint8Array): void;
|
|
588
|
+
/**
|
|
589
|
+
* Close the WebSocket connection
|
|
590
|
+
*/
|
|
591
|
+
close(code?: number, reason?: string): void;
|
|
592
|
+
/**
|
|
593
|
+
* Wait for the next message, returning its data
|
|
594
|
+
*/
|
|
595
|
+
waitForMessage(timeout?: number): Promise<string | ArrayBuffer>;
|
|
596
|
+
/**
|
|
597
|
+
* Wait for the connection to close
|
|
598
|
+
*/
|
|
599
|
+
waitForClose(timeout?: number): Promise<{
|
|
600
|
+
code?: number;
|
|
601
|
+
reason?: string;
|
|
602
|
+
}>;
|
|
603
|
+
/**
|
|
604
|
+
* Assert that the next message equals the expected value
|
|
605
|
+
*/
|
|
606
|
+
assertMessage(expected: string, timeout?: number): Promise<void>;
|
|
607
|
+
/**
|
|
608
|
+
* Assert that the connection closes, optionally with an expected code
|
|
609
|
+
*/
|
|
610
|
+
assertClosed(expectedCode?: number, timeout?: number): Promise<void>;
|
|
611
|
+
/**
|
|
612
|
+
* Access the raw Cloudflare WebSocket
|
|
613
|
+
*/
|
|
614
|
+
get raw(): WebSocket;
|
|
615
|
+
}
|
|
616
|
+
//#endregion
|
|
617
|
+
//#region src/core/ws/test-ws-request.d.ts
|
|
618
|
+
/**
|
|
619
|
+
* TestWsRequest
|
|
620
|
+
*
|
|
621
|
+
* Builder for WebSocket upgrade requests. Follows the TestHttpRequest pattern.
|
|
622
|
+
*
|
|
623
|
+
* @example
|
|
624
|
+
* ```typescript
|
|
625
|
+
* const ws = await module.ws('/ws/chat').connect()
|
|
626
|
+
* ws.send('hello')
|
|
627
|
+
* await ws.assertMessage('echo:hello')
|
|
628
|
+
* ws.close()
|
|
629
|
+
* ```
|
|
630
|
+
*
|
|
631
|
+
* @example Authenticated WebSocket
|
|
632
|
+
* ```typescript
|
|
633
|
+
* const ws = await module.ws('/ws/chat').actingAs({ id: user.id }).connect()
|
|
634
|
+
* ```
|
|
635
|
+
*/
|
|
636
|
+
declare class TestWsRequest {
|
|
637
|
+
private readonly path;
|
|
638
|
+
private readonly module;
|
|
639
|
+
private requestHeaders;
|
|
640
|
+
private actingAsUser;
|
|
641
|
+
constructor(path: string, module: TestingModule);
|
|
642
|
+
/**
|
|
643
|
+
* Add custom headers to the upgrade request
|
|
644
|
+
*/
|
|
645
|
+
withHeaders(headers: Record<string, string>): this;
|
|
646
|
+
/**
|
|
647
|
+
* Authenticate the WebSocket connection as a specific user
|
|
648
|
+
*/
|
|
649
|
+
actingAs(user: {
|
|
650
|
+
id: string;
|
|
651
|
+
}): this;
|
|
652
|
+
/**
|
|
653
|
+
* Send the upgrade request and return a live WebSocket connection
|
|
654
|
+
*/
|
|
655
|
+
connect(): Promise<TestWsConnection>;
|
|
656
|
+
private applyAuthentication;
|
|
657
|
+
}
|
|
658
|
+
//#endregion
|
|
659
|
+
//#region src/core/testing-module.d.ts
|
|
660
|
+
/**
|
|
661
|
+
* TestingModule
|
|
662
|
+
*
|
|
663
|
+
* Provides access to the test application, container, HTTP client, and utilities.
|
|
664
|
+
*
|
|
665
|
+
* @example
|
|
666
|
+
* ```typescript
|
|
667
|
+
* const module = await Test.createTestingModule({
|
|
668
|
+
* modules: [RegistrationModule],
|
|
669
|
+
* }).compile()
|
|
670
|
+
*
|
|
671
|
+
* // Make HTTP requests
|
|
672
|
+
* const response = await module.http
|
|
673
|
+
* .post('/api/v1/register')
|
|
674
|
+
* .withBody({ ... })
|
|
675
|
+
* .send()
|
|
676
|
+
*
|
|
677
|
+
* // Access services
|
|
678
|
+
* const service = module.get(REGISTRATION_TOKENS.RegistrationService)
|
|
679
|
+
*
|
|
680
|
+
* // Database utilities
|
|
681
|
+
* await module.truncateDb()
|
|
682
|
+
* await module.seed(UserSeeder)
|
|
683
|
+
* await module.assertDatabaseHas('user', { email: 'test@example.com' })
|
|
684
|
+
*
|
|
685
|
+
* // Cleanup
|
|
686
|
+
* await module.close()
|
|
687
|
+
* ```
|
|
688
|
+
*/
|
|
689
|
+
declare class TestingModule {
|
|
690
|
+
private readonly app;
|
|
691
|
+
private readonly env;
|
|
692
|
+
private readonly ctx;
|
|
693
|
+
private _http;
|
|
694
|
+
private readonly _requestContainer;
|
|
695
|
+
constructor(app: Application, env: StratalEnv, ctx: ExecutionContext);
|
|
696
|
+
/**
|
|
697
|
+
* Resolve a service from the container
|
|
698
|
+
*/
|
|
699
|
+
get<T>(token: InjectionToken<T>): T;
|
|
700
|
+
/**
|
|
701
|
+
* Get HTTP test client for making requests
|
|
702
|
+
*/
|
|
703
|
+
get http(): TestHttpClient;
|
|
704
|
+
/**
|
|
705
|
+
* Get fake storage service for assertions
|
|
706
|
+
*/
|
|
707
|
+
get storage(): FakeStorageService;
|
|
708
|
+
/**
|
|
709
|
+
* Create a WebSocket test request builder for the given path
|
|
710
|
+
*/
|
|
711
|
+
ws(path: string): TestWsRequest;
|
|
712
|
+
/**
|
|
713
|
+
* Create an SSE test request builder for the given path
|
|
714
|
+
*/
|
|
715
|
+
sse(path: string): TestSseRequest;
|
|
716
|
+
/**
|
|
717
|
+
* Create a Quarry command test request builder
|
|
718
|
+
*/
|
|
719
|
+
quarry(name: string): TestCommandRequest;
|
|
720
|
+
/**
|
|
721
|
+
* Get Application instance
|
|
722
|
+
*/
|
|
723
|
+
get application(): Application;
|
|
724
|
+
/**
|
|
725
|
+
* Get DI Container (request-scoped)
|
|
726
|
+
*/
|
|
727
|
+
get container(): Container;
|
|
728
|
+
/**
|
|
729
|
+
* Execute an HTTP request through HonoApp
|
|
730
|
+
*/
|
|
731
|
+
fetch(request: Request): Promise<Response>;
|
|
732
|
+
/**
|
|
733
|
+
* Run callback in request scope (for DB operations, service access)
|
|
734
|
+
*/
|
|
735
|
+
runInRequestScope<T>(callback: (container: Container) => T | Promise<T>): Promise<T>;
|
|
736
|
+
/**
|
|
737
|
+
* Get database service instance (resolved in request scope)
|
|
738
|
+
*/
|
|
739
|
+
getDb(): DatabaseService;
|
|
740
|
+
getDb<K extends ConnectionName>(name: K): DatabaseService<K>;
|
|
741
|
+
/**
|
|
742
|
+
* Truncate all non-prisma tables in the database
|
|
743
|
+
*/
|
|
744
|
+
truncateDb(name?: ConnectionName): Promise<void>;
|
|
745
|
+
/**
|
|
746
|
+
* Run seeders by class constructor in the request-scoped container
|
|
747
|
+
*/
|
|
748
|
+
seed(...SeederClasses: Constructor<Seeder>[]): Promise<void>;
|
|
749
|
+
/**
|
|
750
|
+
* Assert that a record exists in the database
|
|
751
|
+
*/
|
|
752
|
+
assertDatabaseHas(table: string, data: Record<string, unknown>, name?: ConnectionName): Promise<void>;
|
|
753
|
+
/**
|
|
754
|
+
* Assert that a record does not exist in the database
|
|
755
|
+
*/
|
|
756
|
+
assertDatabaseMissing(table: string, data: Record<string, unknown>, name?: ConnectionName): Promise<void>;
|
|
757
|
+
/**
|
|
758
|
+
* Assert the number of records in a table
|
|
759
|
+
*/
|
|
760
|
+
assertDatabaseCount(table: string, expected: number, name?: ConnectionName): Promise<void>;
|
|
761
|
+
/**
|
|
762
|
+
* Cleanup - call in afterAll
|
|
763
|
+
*/
|
|
764
|
+
close(): Promise<void>;
|
|
765
|
+
}
|
|
766
|
+
//#endregion
|
|
767
|
+
//#region src/core/testing-module-builder.d.ts
|
|
768
|
+
/**
|
|
769
|
+
* Configuration for creating a testing module
|
|
770
|
+
*
|
|
771
|
+
* Extends ModuleOptions to support all module properties like NestJS.
|
|
772
|
+
*
|
|
773
|
+
* @example
|
|
774
|
+
* ```typescript
|
|
775
|
+
* const module = await Test.createTestingModule({
|
|
776
|
+
* imports: [RegistrationModule, GeoModule],
|
|
777
|
+
* providers: [{ provide: MOCK_TOKEN, useValue: mockValue }],
|
|
778
|
+
* controllers: [TestController],
|
|
779
|
+
* }).compile()
|
|
780
|
+
* ```
|
|
781
|
+
*/
|
|
782
|
+
interface TestingModuleConfig extends ModuleOptions {
|
|
783
|
+
/** Optional environment overrides */
|
|
784
|
+
env?: Partial<StratalEnv>;
|
|
785
|
+
/** Logging configuration. Defaults: level=ERROR, formatter='json' */
|
|
786
|
+
logging?: ApplicationConfig['logging'];
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Builder for creating test modules with provider overrides
|
|
790
|
+
*/
|
|
791
|
+
declare class TestingModuleBuilder {
|
|
792
|
+
private config;
|
|
793
|
+
private overrides;
|
|
794
|
+
constructor(config: TestingModuleConfig);
|
|
795
|
+
/**
|
|
796
|
+
* Override a provider with a custom implementation
|
|
797
|
+
*/
|
|
798
|
+
overrideProvider<T>(token: InjectionToken<T>): ProviderOverrideBuilder<T>;
|
|
799
|
+
/**
|
|
800
|
+
* Add a provider override (internal use by ProviderOverrideBuilder)
|
|
801
|
+
*
|
|
802
|
+
* @internal
|
|
803
|
+
*/
|
|
804
|
+
addProviderOverride<T>(override: ProviderOverrideConfig<T>): this;
|
|
805
|
+
/**
|
|
806
|
+
* Merge additional environment bindings
|
|
807
|
+
*/
|
|
808
|
+
withEnv(env: Partial<StratalEnv>): this;
|
|
809
|
+
/**
|
|
810
|
+
* Compile the testing module
|
|
811
|
+
*
|
|
812
|
+
* Creates the Application, applies overrides, initializes, and returns TestingModule.
|
|
813
|
+
*/
|
|
814
|
+
compile(): Promise<TestingModule>;
|
|
815
|
+
/**
|
|
816
|
+
* Create a test root module with the given options
|
|
817
|
+
*/
|
|
818
|
+
private createTestRootModule;
|
|
819
|
+
}
|
|
820
|
+
//#endregion
|
|
821
|
+
//#region src/core/override/provider-override-builder.d.ts
|
|
822
|
+
/**
|
|
823
|
+
* Provider override configuration
|
|
824
|
+
*/
|
|
825
|
+
interface ProviderOverrideConfig<T = unknown> {
|
|
826
|
+
token: InjectionToken<T>;
|
|
827
|
+
type: 'value' | 'class' | 'factory' | 'existing';
|
|
828
|
+
implementation: T | (new (...args: unknown[]) => T) | ((container: Container) => T) | InjectionToken<T>;
|
|
829
|
+
}
|
|
830
|
+
/**
|
|
831
|
+
* Fluent builder for provider overrides
|
|
832
|
+
*
|
|
833
|
+
* Provides a NestJS-style API for overriding providers in tests.
|
|
834
|
+
*
|
|
835
|
+
* @example
|
|
836
|
+
* ```typescript
|
|
837
|
+
* const module = await Test.createTestingModule({
|
|
838
|
+
* imports: [RegistrationModule],
|
|
839
|
+
* })
|
|
840
|
+
* .overrideProvider(EMAIL_TOKENS.EmailService)
|
|
841
|
+
* .useValue(mockEmailService)
|
|
842
|
+
* .compile()
|
|
843
|
+
* ```
|
|
844
|
+
*/
|
|
845
|
+
declare class ProviderOverrideBuilder<T> {
|
|
846
|
+
private readonly parent;
|
|
847
|
+
private readonly token;
|
|
848
|
+
constructor(parent: TestingModuleBuilder, token: InjectionToken<T>);
|
|
849
|
+
/**
|
|
850
|
+
* Use a static value as the provider
|
|
851
|
+
*
|
|
852
|
+
* The value will be registered directly in the container.
|
|
853
|
+
*
|
|
854
|
+
* @param value - The value to use as the provider
|
|
855
|
+
* @returns The parent TestingModuleBuilder for chaining
|
|
856
|
+
*/
|
|
857
|
+
useValue(value: T): TestingModuleBuilder;
|
|
858
|
+
/**
|
|
859
|
+
* Use a class as the provider
|
|
860
|
+
*
|
|
861
|
+
* The class will be registered as a singleton.
|
|
862
|
+
*
|
|
863
|
+
* @param cls - The class constructor to use as the provider
|
|
864
|
+
* @returns The parent TestingModuleBuilder for chaining
|
|
865
|
+
*/
|
|
866
|
+
useClass(cls: new (...args: unknown[]) => T): TestingModuleBuilder;
|
|
867
|
+
/**
|
|
868
|
+
* Use a factory function as the provider
|
|
869
|
+
*
|
|
870
|
+
* The factory receives the container and should return the provider instance.
|
|
871
|
+
*
|
|
872
|
+
* @param factory - Factory function that creates the provider
|
|
873
|
+
* @returns The parent TestingModuleBuilder for chaining
|
|
874
|
+
*/
|
|
875
|
+
useFactory(factory: (container: Container) => T): TestingModuleBuilder;
|
|
876
|
+
/**
|
|
877
|
+
* Use an existing token as the provider (alias)
|
|
878
|
+
*
|
|
879
|
+
* The override token will resolve to the same instance as the target token.
|
|
880
|
+
*
|
|
881
|
+
* @param existingToken - The token to alias
|
|
882
|
+
* @returns The parent TestingModuleBuilder for chaining
|
|
883
|
+
*
|
|
884
|
+
* @example
|
|
885
|
+
* ```typescript
|
|
886
|
+
* const module = await Test.createTestingModule({
|
|
887
|
+
* imports: [MyModule],
|
|
888
|
+
* })
|
|
889
|
+
* .overrideProvider(ABSTRACT_TOKEN)
|
|
890
|
+
* .useExisting(ConcreteService)
|
|
891
|
+
* .compile()
|
|
892
|
+
* ```
|
|
893
|
+
*/
|
|
894
|
+
useExisting(existingToken: InjectionToken<T>): TestingModuleBuilder;
|
|
895
|
+
}
|
|
896
|
+
//#endregion
|
|
897
|
+
//#region src/core/test.d.ts
|
|
898
|
+
/**
|
|
899
|
+
* Test
|
|
900
|
+
*
|
|
901
|
+
* Static class for creating testing modules.
|
|
902
|
+
* Provides a NestJS-style API for configuring test modules.
|
|
903
|
+
*
|
|
904
|
+
* @example
|
|
905
|
+
* ```typescript
|
|
906
|
+
* // In vitest.setup.ts:
|
|
907
|
+
* Test.setBaseModules([CoreModule])
|
|
908
|
+
*
|
|
909
|
+
* // In test files:
|
|
910
|
+
* const module = await Test.createTestingModule({
|
|
911
|
+
* imports: [RegistrationModule, GeoModule],
|
|
912
|
+
* })
|
|
913
|
+
* .overrideProvider(EMAIL_TOKENS.EmailService)
|
|
914
|
+
* .useValue(mockEmailService)
|
|
915
|
+
* .compile()
|
|
916
|
+
* ```
|
|
917
|
+
*/
|
|
918
|
+
declare class Test {
|
|
919
|
+
/**
|
|
920
|
+
* Base modules to include in all test modules
|
|
921
|
+
* Set once in vitest.setup.ts
|
|
922
|
+
*/
|
|
923
|
+
private static baseModules;
|
|
924
|
+
/**
|
|
925
|
+
* Set base modules to include in all test modules
|
|
926
|
+
* Should be called once in vitest.setup.ts
|
|
927
|
+
*
|
|
928
|
+
* @param modules - Modules to include before test-specific modules (e.g., CoreModule)
|
|
929
|
+
*/
|
|
930
|
+
static setBaseModules(modules: (ModuleClass | DynamicModule)[]): void;
|
|
931
|
+
/**
|
|
932
|
+
* Get base modules
|
|
933
|
+
*/
|
|
934
|
+
static getBaseModules(): (ModuleClass | DynamicModule)[];
|
|
935
|
+
/**
|
|
936
|
+
* Create a testing module builder
|
|
937
|
+
*
|
|
938
|
+
* @param config - Configuration with modules and optional env overrides
|
|
939
|
+
* @returns TestingModuleBuilder for configuring and compiling the module
|
|
940
|
+
*/
|
|
941
|
+
static createTestingModule(config: TestingModuleConfig): TestingModuleBuilder;
|
|
942
|
+
}
|
|
943
|
+
//#endregion
|
|
944
|
+
//#region src/core/http/fetch-mock.types.d.ts
|
|
945
|
+
/**
|
|
946
|
+
* Options for mocking JSON responses
|
|
947
|
+
*/
|
|
948
|
+
interface MockJsonOptions {
|
|
949
|
+
/**
|
|
950
|
+
* HTTP status code for the response
|
|
951
|
+
* @default 200
|
|
952
|
+
*/
|
|
953
|
+
status?: number;
|
|
954
|
+
/**
|
|
955
|
+
* Custom headers to include in the response
|
|
956
|
+
*/
|
|
957
|
+
headers?: Record<string, string>;
|
|
958
|
+
/**
|
|
959
|
+
* Delay in milliseconds before responding
|
|
960
|
+
*/
|
|
961
|
+
delay?: number;
|
|
962
|
+
/**
|
|
963
|
+
* HTTP method to match (GET, POST, PUT, PATCH, DELETE, etc.)
|
|
964
|
+
* @default 'GET'
|
|
965
|
+
*/
|
|
966
|
+
method?: string;
|
|
967
|
+
/**
|
|
968
|
+
* Specific path to override URL pathname
|
|
969
|
+
* If not provided, the pathname from the URL will be used
|
|
970
|
+
*/
|
|
971
|
+
path?: string;
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* Options for mocking error responses
|
|
975
|
+
*/
|
|
976
|
+
interface MockErrorOptions {
|
|
977
|
+
/**
|
|
978
|
+
* Custom headers to include in the error response
|
|
979
|
+
*/
|
|
980
|
+
headers?: Record<string, string>;
|
|
981
|
+
/**
|
|
982
|
+
* HTTP method to match (GET, POST, PUT, PATCH, DELETE, etc.)
|
|
983
|
+
* @default 'GET'
|
|
984
|
+
*/
|
|
985
|
+
method?: string;
|
|
986
|
+
/**
|
|
987
|
+
* Specific path to override URL pathname
|
|
988
|
+
* If not provided, the pathname from the URL will be used
|
|
989
|
+
*/
|
|
990
|
+
path?: string;
|
|
991
|
+
}
|
|
992
|
+
//#endregion
|
|
993
|
+
//#region src/core/http/mock-fetch.d.ts
|
|
994
|
+
/**
|
|
995
|
+
* MSW-based fetch mock for declarative HTTP mocking in tests.
|
|
996
|
+
*
|
|
997
|
+
* Replaces the old Cloudflare `fetchMock` (undici MockAgent) with MSW's `setupServer`.
|
|
998
|
+
* Works in both Node.js and workerd test environments.
|
|
999
|
+
*
|
|
1000
|
+
* @example
|
|
1001
|
+
* ```typescript
|
|
1002
|
+
* import { createMockFetch } from '@stratal/testing'
|
|
1003
|
+
*
|
|
1004
|
+
* const mock = createMockFetch()
|
|
1005
|
+
*
|
|
1006
|
+
* beforeAll(() => mock.listen())
|
|
1007
|
+
* afterEach(() => mock.reset())
|
|
1008
|
+
* afterAll(() => mock.close())
|
|
1009
|
+
*
|
|
1010
|
+
* it('should mock external API', async () => {
|
|
1011
|
+
* mock.mockJsonResponse('https://api.example.com/data', { success: true })
|
|
1012
|
+
*
|
|
1013
|
+
* const response = await fetch('https://api.example.com/data')
|
|
1014
|
+
* const json = await response.json()
|
|
1015
|
+
*
|
|
1016
|
+
* expect(json.success).toBe(true)
|
|
1017
|
+
* })
|
|
1018
|
+
* ```
|
|
1019
|
+
*/
|
|
1020
|
+
declare class MockFetch {
|
|
1021
|
+
private server;
|
|
1022
|
+
constructor(handlers?: RequestHandler[]);
|
|
1023
|
+
/** Start intercepting. Call in beforeAll/beforeEach. */
|
|
1024
|
+
listen(): void;
|
|
1025
|
+
/** Reset runtime handlers. Call in afterEach. */
|
|
1026
|
+
reset(): void;
|
|
1027
|
+
/** Stop intercepting. Call in afterAll. */
|
|
1028
|
+
close(): void;
|
|
1029
|
+
/** Add runtime handler(s) for a single test. */
|
|
1030
|
+
use(...handlers: RequestHandler[]): void;
|
|
1031
|
+
/**
|
|
1032
|
+
* Mock a JSON response.
|
|
1033
|
+
*
|
|
1034
|
+
* @param url - Full URL to mock (e.g., 'https://api.example.com/users')
|
|
1035
|
+
* @param data - JSON data to return
|
|
1036
|
+
* @param options - HTTP method, status code, headers
|
|
1037
|
+
*
|
|
1038
|
+
* @example
|
|
1039
|
+
* ```typescript
|
|
1040
|
+
* mock.mockJsonResponse('https://api.example.com/users', { users: [] })
|
|
1041
|
+
* mock.mockJsonResponse('https://api.example.com/users', { created: true }, { method: 'POST', status: 201 })
|
|
1042
|
+
* ```
|
|
1043
|
+
*/
|
|
1044
|
+
mockJsonResponse(url: string, data: Record<string, unknown> | unknown[], options?: MockJsonOptions): void;
|
|
1045
|
+
/**
|
|
1046
|
+
* Mock an error response.
|
|
1047
|
+
*
|
|
1048
|
+
* @param url - Full URL to mock
|
|
1049
|
+
* @param status - HTTP error status code
|
|
1050
|
+
* @param message - Optional error message
|
|
1051
|
+
* @param options - HTTP method, headers
|
|
1052
|
+
*
|
|
1053
|
+
* @example
|
|
1054
|
+
* ```typescript
|
|
1055
|
+
* mock.mockError('https://api.example.com/fail', 401, 'Unauthorized')
|
|
1056
|
+
* mock.mockError('https://api.example.com/fail', 500, 'Server Error', { method: 'POST' })
|
|
1057
|
+
* ```
|
|
1058
|
+
*/
|
|
1059
|
+
mockError(url: string, status: number, message?: string, options?: MockErrorOptions): void;
|
|
1060
|
+
}
|
|
1061
|
+
/**
|
|
1062
|
+
* Factory function to create a new MockFetch instance
|
|
1063
|
+
*
|
|
1064
|
+
* @param handlers - Optional initial MSW request handlers
|
|
1065
|
+
* @returns A new MockFetch instance
|
|
1066
|
+
*
|
|
1067
|
+
* @example
|
|
1068
|
+
* ```typescript
|
|
1069
|
+
* import { createMockFetch } from '@stratal/testing'
|
|
1070
|
+
*
|
|
1071
|
+
* const mock = createMockFetch()
|
|
1072
|
+
*
|
|
1073
|
+
* beforeAll(() => mock.listen())
|
|
1074
|
+
* afterEach(() => mock.reset())
|
|
1075
|
+
* afterAll(() => mock.close())
|
|
1076
|
+
* ```
|
|
1077
|
+
*/
|
|
1078
|
+
declare function createMockFetch(handlers?: RequestHandler[]): MockFetch;
|
|
1079
|
+
//#endregion
|
|
1080
|
+
//#region src/auth/acting-as.d.ts
|
|
1081
|
+
/**
|
|
1082
|
+
* ActingAs
|
|
1083
|
+
*
|
|
1084
|
+
* Creates authentication sessions for testing.
|
|
1085
|
+
* Uses Better Auth's internalAdapter to create real database sessions.
|
|
1086
|
+
*
|
|
1087
|
+
* @example
|
|
1088
|
+
* ```typescript
|
|
1089
|
+
* const actingAs = new ActingAs(authService)
|
|
1090
|
+
* const headers = await actingAs.createSessionForUser({ id: 'user-123' })
|
|
1091
|
+
* ```
|
|
1092
|
+
*/
|
|
1093
|
+
declare class ActingAs {
|
|
1094
|
+
private readonly authService;
|
|
1095
|
+
constructor(authService: AuthService);
|
|
1096
|
+
createSessionForUser(user: {
|
|
1097
|
+
id: string;
|
|
1098
|
+
}): Promise<Headers>;
|
|
1099
|
+
}
|
|
1100
|
+
//#endregion
|
|
1101
|
+
//#region src/core/env/test-env.d.ts
|
|
1102
|
+
/**
|
|
1103
|
+
* Get test environment with optional overrides
|
|
1104
|
+
*
|
|
1105
|
+
* @param overrides - Optional partial env to merge with cloudflare:test env
|
|
1106
|
+
* @returns Complete Env object for testing
|
|
1107
|
+
*/
|
|
1108
|
+
declare function getTestEnv(overrides?: Partial<StratalEnv>): StratalEnv;
|
|
1109
|
+
//#endregion
|
|
1110
|
+
//#region src/errors/test-error.d.ts
|
|
1111
|
+
/**
|
|
1112
|
+
* Base error class for all test framework errors.
|
|
1113
|
+
* Extends from Error and allows easy identification via `instanceof`.
|
|
1114
|
+
*/
|
|
1115
|
+
declare class TestError extends Error {
|
|
1116
|
+
readonly cause?: Error | undefined;
|
|
1117
|
+
constructor(message: string, cause?: Error | undefined);
|
|
1118
|
+
}
|
|
1119
|
+
//#endregion
|
|
1120
|
+
//#region src/errors/setup-error.d.ts
|
|
1121
|
+
/**
|
|
1122
|
+
* Error thrown when test setup fails.
|
|
1123
|
+
* Examples: schema creation failure, migration failure, application bootstrap failure.
|
|
1124
|
+
*/
|
|
1125
|
+
declare class TestSetupError extends TestError {
|
|
1126
|
+
constructor(message: string, cause?: Error);
|
|
1127
|
+
}
|
|
1128
|
+
//#endregion
|
|
1129
|
+
export { ActingAs, FakeStorageService, HttpResponse, type MockErrorOptions, MockFetch, type MockJsonOptions, ProviderOverrideBuilder, type ProviderOverrideConfig, type StoredFile, Test, TestCommandRequest, TestCommandResult, TestError, TestHttpClient, TestHttpRequest, TestResponse, TestSetupError, TestSseConnection, type TestSseEvent, TestSseRequest, TestWsConnection, TestWsRequest, TestingModule, TestingModuleBuilder, type TestingModuleConfig, createMockFetch, getTestEnv, http };
|
|
1130
|
+
//# sourceMappingURL=index.d.mts.map
|