@velajs/testing 0.5.0 → 0.5.1
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/CHANGELOG.md +7 -2
- package/dist/index.d.ts +484 -15
- package/dist/index.js +866 -14
- package/dist/index.js.map +1 -0
- package/dist/test-ws-connection-BHlEKwQz.js +166 -0
- package/dist/test-ws-connection-BHlEKwQz.js.map +1 -0
- package/dist/websocket-node/index.d.ts +1 -1
- package/dist/websocket-node/index.js +67 -102
- package/dist/websocket-node/index.js.map +1 -0
- package/package.json +59 -45
- package/dist/db/test-database.d.ts +0 -27
- package/dist/db/test-database.js +0 -19
- package/dist/http/path-utils.d.ts +0 -11
- package/dist/http/path-utils.js +0 -37
- package/dist/http/test-http-client.d.ts +0 -37
- package/dist/http/test-http-client.js +0 -61
- package/dist/http/test-http-request.d.ts +0 -46
- package/dist/http/test-http-request.js +0 -87
- package/dist/http/test-response.d.ts +0 -76
- package/dist/http/test-response.js +0 -166
- package/dist/sse/test-sse-connection.d.ts +0 -46
- package/dist/sse/test-sse-connection.js +0 -196
- package/dist/sse/test-sse-request.d.ts +0 -30
- package/dist/sse/test-sse-request.js +0 -62
- package/dist/test.d.ts +0 -5
- package/dist/test.js +0 -6
- package/dist/testing-module.builder.d.ts +0 -25
- package/dist/testing-module.builder.js +0 -160
- package/dist/testing-module.d.ts +0 -87
- package/dist/testing-module.js +0 -141
- package/dist/ws/test-ws-connection.d.ts +0 -41
- package/dist/ws/test-ws-connection.js +0 -105
- package/dist/ws/test-ws-request.d.ts +0 -43
- package/dist/ws/test-ws-request.js +0 -69
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 647fd5f: Modernize the package build, validation, and release toolchain.
|
|
8
|
+
|
|
3
9
|
## 0.3.0 (2026-07-04)
|
|
4
10
|
|
|
5
11
|
- `ComponentManager.init` call removed; provider overrides use the supported `Container.replaceProvider`; registers `DiscoveryService` mirroring bootstrap. Requires `@velajs/vela >=1.11.0`.
|
|
6
12
|
|
|
7
|
-
|
|
8
13
|
## 0.2.1 (2026-05-14)
|
|
9
14
|
|
|
10
15
|
### Fixes
|
|
@@ -25,7 +30,7 @@ Bugs fixed, rebuilt on `@velajs/vela/internal`, no more `reflect-metadata` dep.
|
|
|
25
30
|
- **Provider override shape was wrong.** `overrideProvider(token).useValue(v)` constructed `{ token, useValue }` but vela's container reads `{ provide, useValue }`. The misleading `as ProviderOptions` cast hid this; nothing actually overrode. Fixed.
|
|
26
31
|
- **`useClass` now uses the container's native `useClass` path** instead of the bogus `useFactory: () => new cls()` workaround. The previous comment claimed `Container.registerOptions` doesn't read `useClass` — it does (`vela/src/container/container.ts`).
|
|
27
32
|
- **`loader.resolveAllInstances()` is now awaited.** Was called synchronously even though vela's signature is async; lifecycle hooks fired before instance resolution finished.
|
|
28
|
-
- **
|
|
33
|
+
- **APP\_\* token wiring uses vela's canonical `bindAppProviders` helper.** Replaces the five duplicated `useGlobalGuards/Pipes/Interceptors/Filters/Middleware(container.resolve(APP_*))` blocks that handled only the single-value case (vela switched to array form months ago). Now stays in lockstep with `VelaFactory.create` automatically.
|
|
29
34
|
|
|
30
35
|
### Breaking changes
|
|
31
36
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,484 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
import { ModuleOptions, Token, Type, VelaApplication } from "@velajs/vela";
|
|
2
|
+
import { Container } from "@velajs/vela/internal";
|
|
3
|
+
import { ISeeder } from "@velajs/vela/seeder";
|
|
4
|
+
//#region src/db/test-database.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* TestDatabase
|
|
7
|
+
*
|
|
8
|
+
* A minimal driver contract for database assertions in tests. Vela has no ORM
|
|
9
|
+
* in core, so the harness ships only this interface plus thin assertion
|
|
10
|
+
* wrappers (`module.assertDatabaseHas/Missing/Count`). A consumer — or a future
|
|
11
|
+
* `@velajs/crud` driver — provides the concrete implementation; the harness
|
|
12
|
+
* never couples to a specific database library.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* class MyTestDb implements TestDatabase {
|
|
17
|
+
* async truncate() { ... }
|
|
18
|
+
* async has(table, where) { ... }
|
|
19
|
+
* async count(table) { ... }
|
|
20
|
+
* }
|
|
21
|
+
* await module.assertDatabaseHas(new MyTestDb(), 'user', { email: 'a@b.com' });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
interface TestDatabase {
|
|
25
|
+
/** Remove all rows from every table (reset between tests). */
|
|
26
|
+
truncate(): Promise<void>;
|
|
27
|
+
/** Whether a row matching `where` exists in `table`. */
|
|
28
|
+
has(table: string, where: Record<string, unknown>): Promise<boolean>;
|
|
29
|
+
/** The number of rows in `table`. */
|
|
30
|
+
count(table: string): Promise<number>;
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/http/test-response.d.ts
|
|
34
|
+
/**
|
|
35
|
+
* TestResponse
|
|
36
|
+
*
|
|
37
|
+
* Wraps a `Response` with fluent, chainable assertions. Synchronous status /
|
|
38
|
+
* header assertions return `this`; JSON assertions (which must read the body)
|
|
39
|
+
* return `Promise<this>`.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* const res = await module.http.get('/users/1').send();
|
|
44
|
+
* res.assertOk();
|
|
45
|
+
* await res.assertJsonPath('data.id', 1);
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
declare class TestResponse {
|
|
49
|
+
private readonly response;
|
|
50
|
+
private jsonData;
|
|
51
|
+
private textData;
|
|
52
|
+
constructor(response: Response);
|
|
53
|
+
/** The raw `Response`. */
|
|
54
|
+
get raw(): Response;
|
|
55
|
+
/** The response status code. */
|
|
56
|
+
get status(): number;
|
|
57
|
+
/** The response headers. */
|
|
58
|
+
get headers(): Headers;
|
|
59
|
+
/** Parse (and cache) the response body as JSON. */
|
|
60
|
+
json<T = unknown>(): Promise<T>;
|
|
61
|
+
/** Read (and cache) the response body as text. */
|
|
62
|
+
text(): Promise<string>;
|
|
63
|
+
/** Assert status is 200 OK. */
|
|
64
|
+
assertOk(): this;
|
|
65
|
+
/** Assert status is 201 Created. */
|
|
66
|
+
assertCreated(): this;
|
|
67
|
+
/** Assert status is 204 No Content. */
|
|
68
|
+
assertNoContent(): this;
|
|
69
|
+
/** Assert status is 400 Bad Request. */
|
|
70
|
+
assertBadRequest(): this;
|
|
71
|
+
/** Assert status is 401 Unauthorized. */
|
|
72
|
+
assertUnauthorized(): this;
|
|
73
|
+
/** Assert status is 403 Forbidden. */
|
|
74
|
+
assertForbidden(): this;
|
|
75
|
+
/** Assert status is 404 Not Found. */
|
|
76
|
+
assertNotFound(): this;
|
|
77
|
+
/** Assert status is 422 Unprocessable Entity. */
|
|
78
|
+
assertUnprocessable(): this;
|
|
79
|
+
/** Assert status is 500 Internal Server Error. */
|
|
80
|
+
assertServerError(): this;
|
|
81
|
+
/** Assert the response has the given status code. */
|
|
82
|
+
assertStatus(expected: number): this;
|
|
83
|
+
/** Assert the status is in the 2xx range. */
|
|
84
|
+
assertSuccessful(): this;
|
|
85
|
+
/** Assert each key in `expected` equals the corresponding top-level value. */
|
|
86
|
+
assertJson(expected: Record<string, unknown>): Promise<this>;
|
|
87
|
+
/** Assert the value at a dot-notation path equals `expected`. */
|
|
88
|
+
assertJsonPath(path: string, expected: unknown): Promise<this>;
|
|
89
|
+
/** Assert every path/value pair in `expectations` matches (batch assert). */
|
|
90
|
+
assertJsonPaths(expectations: Record<string, unknown>): Promise<this>;
|
|
91
|
+
/** Assert the top-level JSON object has every key in `structure`. */
|
|
92
|
+
assertJsonStructure(structure: string[]): Promise<this>;
|
|
93
|
+
/** Assert a path exists (value may be anything, including `null`). */
|
|
94
|
+
assertJsonPathExists(path: string): Promise<this>;
|
|
95
|
+
/** Assert a path does not exist. */
|
|
96
|
+
assertJsonPathMissing(path: string): Promise<this>;
|
|
97
|
+
/** Assert the value at a path satisfies a predicate. */
|
|
98
|
+
assertJsonPathMatches(path: string, matcher: (value: unknown) => boolean): Promise<this>;
|
|
99
|
+
/** Assert the string value at a path contains `substring`. */
|
|
100
|
+
assertJsonPathContains(path: string, substring: string): Promise<this>;
|
|
101
|
+
/** Assert the array value at a path includes `item`. */
|
|
102
|
+
assertJsonPathIncludes(path: string, item: unknown): Promise<this>;
|
|
103
|
+
/** Assert the array value at a path has `count` items. */
|
|
104
|
+
assertJsonPathCount(path: string, count: number): Promise<this>;
|
|
105
|
+
/** Assert a header is present, optionally equal to `expected`. */
|
|
106
|
+
assertHeader(name: string, expected?: string): this;
|
|
107
|
+
/** Assert a header is absent. */
|
|
108
|
+
assertHeaderMissing(name: string): this;
|
|
109
|
+
}
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region src/http/test-http-request.d.ts
|
|
112
|
+
/**
|
|
113
|
+
* TestHttpRequest
|
|
114
|
+
*
|
|
115
|
+
* Fluent builder for a single test HTTP request. `send()` builds a `Request`
|
|
116
|
+
* and drives it through `module.fetch()` (the full Hono pipeline).
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```ts
|
|
120
|
+
* const res = await module.http
|
|
121
|
+
* .post('/users')
|
|
122
|
+
* .withBody({ name: 'A' })
|
|
123
|
+
* .withHeaders({ 'X-Trace': '1' })
|
|
124
|
+
* .send();
|
|
125
|
+
* res.assertCreated();
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
declare class TestHttpRequest {
|
|
129
|
+
private readonly method;
|
|
130
|
+
private readonly path;
|
|
131
|
+
private readonly module;
|
|
132
|
+
private readonly host;
|
|
133
|
+
private body;
|
|
134
|
+
private readonly requestHeaders;
|
|
135
|
+
private principal;
|
|
136
|
+
private resolver;
|
|
137
|
+
constructor(method: string, path: string, headers: Headers, module: TestingModule, host?: string | null);
|
|
138
|
+
/** Set the request body (JSON-serialized on send). */
|
|
139
|
+
withBody(data: unknown): this;
|
|
140
|
+
/** Merge additional headers. */
|
|
141
|
+
withHeaders(headers: Record<string, string>): this;
|
|
142
|
+
/** Set `Content-Type: application/json`. */
|
|
143
|
+
asJson(): this;
|
|
144
|
+
/**
|
|
145
|
+
* Authenticate the request as `principal`. The `resolver` (or a default one
|
|
146
|
+
* registered via `module.setAuthResolver`) turns the principal into request
|
|
147
|
+
* headers. The resolver signature `(module, principal) => Promise<Headers>`
|
|
148
|
+
* is the cross-package contract sibling packages (e.g. `@velajs/better-auth`)
|
|
149
|
+
* build against.
|
|
150
|
+
*/
|
|
151
|
+
actingAs(principal: TestPrincipal, resolver?: ActingAsResolver): this;
|
|
152
|
+
/** Build the `Request` and send it through `module.fetch()`. */
|
|
153
|
+
send(): Promise<TestResponse>;
|
|
154
|
+
private applyAuthentication;
|
|
155
|
+
}
|
|
156
|
+
//#endregion
|
|
157
|
+
//#region src/http/test-http-client.d.ts
|
|
158
|
+
/**
|
|
159
|
+
* TestHttpClient
|
|
160
|
+
*
|
|
161
|
+
* Fluent entry point for test HTTP requests. `forHost`/`withHeaders` return a
|
|
162
|
+
* new immutable client; the verb methods start a {@link TestHttpRequest}.
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```ts
|
|
166
|
+
* const res = await module.http
|
|
167
|
+
* .forHost('example.com')
|
|
168
|
+
* .post('/users')
|
|
169
|
+
* .withBody({ name: 'A' })
|
|
170
|
+
* .send();
|
|
171
|
+
* res.assertCreated();
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
174
|
+
declare class TestHttpClient {
|
|
175
|
+
private readonly module;
|
|
176
|
+
private readonly host;
|
|
177
|
+
private readonly defaultHeaders;
|
|
178
|
+
constructor(module: TestingModule, host?: string | null, defaultHeaders?: Headers);
|
|
179
|
+
/**
|
|
180
|
+
* Return a new client bound to `host`. Also sets the `Host` header so domain
|
|
181
|
+
* routing works even when the runtime reads the header rather than the URL.
|
|
182
|
+
*/
|
|
183
|
+
forHost(host: string): TestHttpClient;
|
|
184
|
+
/** Return a new client with additional default headers on every request. */
|
|
185
|
+
withHeaders(headers: Record<string, string>): TestHttpClient;
|
|
186
|
+
get(path: string): TestHttpRequest;
|
|
187
|
+
post(path: string): TestHttpRequest;
|
|
188
|
+
put(path: string): TestHttpRequest;
|
|
189
|
+
patch(path: string): TestHttpRequest;
|
|
190
|
+
delete(path: string): TestHttpRequest;
|
|
191
|
+
private createRequest;
|
|
192
|
+
}
|
|
193
|
+
//#endregion
|
|
194
|
+
//#region src/sse/test-sse-connection.d.ts
|
|
195
|
+
/** A parsed Server-Sent Event. */
|
|
196
|
+
interface TestSseEvent {
|
|
197
|
+
data: string;
|
|
198
|
+
event?: string;
|
|
199
|
+
id?: string;
|
|
200
|
+
retry?: number;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* TestSseConnection
|
|
204
|
+
*
|
|
205
|
+
* Reads a streaming `text/event-stream` response body and exposes queue-based
|
|
206
|
+
* wait/assert helpers over the parsed events.
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```ts
|
|
210
|
+
* const sse = await module.sse('/stream/events').connect();
|
|
211
|
+
* await sse.assertEventData('ping');
|
|
212
|
+
* await sse.waitForEnd();
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
declare class TestSseConnection {
|
|
216
|
+
private readonly response;
|
|
217
|
+
private readonly eventQueue;
|
|
218
|
+
private eventWaiters;
|
|
219
|
+
private streamEnded;
|
|
220
|
+
private endWaiters;
|
|
221
|
+
constructor(response: Response);
|
|
222
|
+
/** The raw `Response`. */
|
|
223
|
+
get raw(): Response;
|
|
224
|
+
/** Wait for the next event (rejects after `timeout` ms). */
|
|
225
|
+
waitForEvent(timeout?: number): Promise<TestSseEvent>;
|
|
226
|
+
/** Wait for the stream to end (rejects after `timeout` ms). */
|
|
227
|
+
waitForEnd(timeout?: number): Promise<void>;
|
|
228
|
+
/** Collect all remaining events until the stream ends. */
|
|
229
|
+
collectEvents(timeout?: number): Promise<TestSseEvent[]>;
|
|
230
|
+
/** Assert the next event matches the expected partial shape. */
|
|
231
|
+
assertEvent(expected: Partial<TestSseEvent>, timeout?: number): Promise<void>;
|
|
232
|
+
/** Assert the next event's `data` equals `expected`. */
|
|
233
|
+
assertEventData(expected: string, timeout?: number): Promise<void>;
|
|
234
|
+
/** Assert the next event's `data` is JSON equal to `expected`. */
|
|
235
|
+
assertJsonEventData<T>(expected: T, timeout?: number): Promise<void>;
|
|
236
|
+
private startReading;
|
|
237
|
+
private endStream;
|
|
238
|
+
private parseEvent;
|
|
239
|
+
private dispatchEvent;
|
|
240
|
+
}
|
|
241
|
+
//#endregion
|
|
242
|
+
//#region src/sse/test-sse-request.d.ts
|
|
243
|
+
/**
|
|
244
|
+
* TestSseRequest
|
|
245
|
+
*
|
|
246
|
+
* Builder for a Server-Sent Events connection. `connect()` issues a GET through
|
|
247
|
+
* `module.fetch()`, asserts a `text/event-stream` 200, and wraps the streaming
|
|
248
|
+
* body in a {@link TestSseConnection}.
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* ```ts
|
|
252
|
+
* const sse = await module.sse('/stream/events').connect();
|
|
253
|
+
* await sse.assertEvent({ event: 'message', data: 'hello' });
|
|
254
|
+
* ```
|
|
255
|
+
*/
|
|
256
|
+
declare class TestSseRequest {
|
|
257
|
+
private readonly path;
|
|
258
|
+
private readonly module;
|
|
259
|
+
private readonly requestHeaders;
|
|
260
|
+
private principal;
|
|
261
|
+
private resolver;
|
|
262
|
+
constructor(path: string, module: TestingModule);
|
|
263
|
+
/** Merge additional headers onto the SSE request. */
|
|
264
|
+
withHeaders(headers: Record<string, string>): this;
|
|
265
|
+
/** Authenticate the connection (see {@link TestHttpRequest.actingAs}). */
|
|
266
|
+
actingAs(principal: TestPrincipal, resolver?: ActingAsResolver): this;
|
|
267
|
+
/** Open the stream and return a live {@link TestSseConnection}. */
|
|
268
|
+
connect(): Promise<TestSseConnection>;
|
|
269
|
+
private applyAuthentication;
|
|
270
|
+
}
|
|
271
|
+
//#endregion
|
|
272
|
+
//#region src/ws/test-ws-connection.d.ts
|
|
273
|
+
/**
|
|
274
|
+
* TestWsConnection
|
|
275
|
+
*
|
|
276
|
+
* Wraps a live `WebSocket` with queue-based wait/assert helpers. Transport is
|
|
277
|
+
* supplied by the caller — the core harness never opens a socket itself (see
|
|
278
|
+
* `@velajs/testing/websocket-node`).
|
|
279
|
+
*
|
|
280
|
+
* @example
|
|
281
|
+
* ```ts
|
|
282
|
+
* const ws = await module.ws('/ws/chat').connect();
|
|
283
|
+
* ws.send('hi');
|
|
284
|
+
* await ws.assertMessage('echo:hi');
|
|
285
|
+
* ws.close();
|
|
286
|
+
* ```
|
|
287
|
+
*/
|
|
288
|
+
declare class TestWsConnection {
|
|
289
|
+
private readonly ws;
|
|
290
|
+
private readonly cleanup?;
|
|
291
|
+
private readonly messageQueue;
|
|
292
|
+
private messageWaiters;
|
|
293
|
+
private closeEvent;
|
|
294
|
+
private closeWaiters;
|
|
295
|
+
constructor(ws: WebSocket, cleanup?: (() => void | Promise<void>) | undefined);
|
|
296
|
+
/** The raw `WebSocket`. */
|
|
297
|
+
get raw(): WebSocket;
|
|
298
|
+
/** Send a message. */
|
|
299
|
+
send(data: string | ArrayBufferLike | ArrayBufferView): void;
|
|
300
|
+
/** Close the connection. */
|
|
301
|
+
close(code?: number, reason?: string): void;
|
|
302
|
+
/** Wait for the next message (rejects after `timeout` ms). */
|
|
303
|
+
waitForMessage(timeout?: number): Promise<string | ArrayBuffer>;
|
|
304
|
+
/** Wait for the connection to close (rejects after `timeout` ms). */
|
|
305
|
+
waitForClose(timeout?: number): Promise<{
|
|
306
|
+
code?: number;
|
|
307
|
+
reason?: string;
|
|
308
|
+
}>;
|
|
309
|
+
/** Assert the next message equals `expected`. */
|
|
310
|
+
assertMessage(expected: string, timeout?: number): Promise<void>;
|
|
311
|
+
/** Assert the connection closes, optionally with `expectedCode`. */
|
|
312
|
+
assertClosed(expectedCode?: number, timeout?: number): Promise<void>;
|
|
313
|
+
}
|
|
314
|
+
//#endregion
|
|
315
|
+
//#region src/ws/test-ws-request.d.ts
|
|
316
|
+
/**
|
|
317
|
+
* A transport adapter that performs the WebSocket upgrade and returns a live
|
|
318
|
+
* connection. Registered by a platform package (e.g. websocket-node).
|
|
319
|
+
*/
|
|
320
|
+
type WsConnector = (module: TestingModule, path: string, headers: Headers) => Promise<TestWsConnection>;
|
|
321
|
+
/**
|
|
322
|
+
* Register the transport that {@link TestWsRequest.connect} uses. Called by a
|
|
323
|
+
* platform adapter's side-effect import (e.g. `@velajs/testing/websocket-node`).
|
|
324
|
+
*/
|
|
325
|
+
declare function registerWsConnector(connector: WsConnector): void;
|
|
326
|
+
/** The currently registered WebSocket connector, if any. */
|
|
327
|
+
declare function getWsConnector(): WsConnector | null;
|
|
328
|
+
/**
|
|
329
|
+
* TestWsRequest
|
|
330
|
+
*
|
|
331
|
+
* Builder for a WebSocket connection. `connect()` requires a transport adapter
|
|
332
|
+
* to be registered; without one it throws a clear, actionable error.
|
|
333
|
+
*
|
|
334
|
+
* @example
|
|
335
|
+
* ```ts
|
|
336
|
+
* import '@velajs/testing/websocket-node';
|
|
337
|
+
* const ws = await module.ws('/ws/chat').connect();
|
|
338
|
+
* ws.send('hi');
|
|
339
|
+
* await ws.assertMessage('echo:hi');
|
|
340
|
+
* ```
|
|
341
|
+
*/
|
|
342
|
+
declare class TestWsRequest {
|
|
343
|
+
private readonly path;
|
|
344
|
+
private readonly module;
|
|
345
|
+
private readonly requestHeaders;
|
|
346
|
+
private principal;
|
|
347
|
+
private resolver;
|
|
348
|
+
constructor(path: string, module: TestingModule);
|
|
349
|
+
/** Merge additional headers onto the upgrade request. */
|
|
350
|
+
withHeaders(headers: Record<string, string>): this;
|
|
351
|
+
/** Authenticate the connection (see {@link TestHttpRequest.actingAs}). */
|
|
352
|
+
actingAs(principal: TestPrincipal, resolver?: ActingAsResolver): this;
|
|
353
|
+
/** Open the socket via the registered transport adapter. */
|
|
354
|
+
connect(): Promise<TestWsConnection>;
|
|
355
|
+
private applyAuthentication;
|
|
356
|
+
}
|
|
357
|
+
//#endregion
|
|
358
|
+
//#region src/testing-module.d.ts
|
|
359
|
+
/** A test principal — an opaque object the auth resolver turns into headers. */
|
|
360
|
+
type TestPrincipal = Record<string, unknown>;
|
|
361
|
+
/**
|
|
362
|
+
* Turns a principal into request headers (session cookie, bearer token, …).
|
|
363
|
+
* The signature `(module, principal) => Promise<Headers>` is a cross-package
|
|
364
|
+
* contract: sibling packages (e.g. `@velajs/better-auth/testing`) build a
|
|
365
|
+
* resolver against it. Kept generic so `@velajs/testing` needs no auth deps.
|
|
366
|
+
*/
|
|
367
|
+
type ActingAsResolver = (module: TestingModule, principal: TestPrincipal) => Promise<Headers>;
|
|
368
|
+
/**
|
|
369
|
+
* TestingModule
|
|
370
|
+
*
|
|
371
|
+
* The compiled test harness. Beyond `get`/`createApplication`/`close`, it adds
|
|
372
|
+
* Laravel-flavored ergonomics: a fluent HTTP client, SSE/WS builders, request-
|
|
373
|
+
* scope execution, seeding, and database assertion wrappers.
|
|
374
|
+
*
|
|
375
|
+
* @example
|
|
376
|
+
* ```ts
|
|
377
|
+
* const module = await Test.createTestingModule({ imports: [AppModule] }).compile();
|
|
378
|
+
* await module.http.post('/users').withBody({ name: 'A' }).send()
|
|
379
|
+
* .then((r) => r.assertCreated());
|
|
380
|
+
* ```
|
|
381
|
+
*/
|
|
382
|
+
declare class TestingModule {
|
|
383
|
+
private readonly app;
|
|
384
|
+
private readonly container;
|
|
385
|
+
private _http;
|
|
386
|
+
private honoApp;
|
|
387
|
+
private authResolver;
|
|
388
|
+
constructor(app: VelaApplication, container: Container);
|
|
389
|
+
/** Resolve a provider from the root container. */
|
|
390
|
+
get<T>(token: Token<T>): T;
|
|
391
|
+
/** Build (once) and return the underlying application. */
|
|
392
|
+
createApplication(): Promise<VelaApplication>;
|
|
393
|
+
/** Lazy fluent HTTP client bound to this module. */
|
|
394
|
+
get http(): TestHttpClient;
|
|
395
|
+
/** Start an SSE connection builder for `path`. */
|
|
396
|
+
sse(path: string): TestSseRequest;
|
|
397
|
+
/** Start a WebSocket connection builder for `path` (needs a transport adapter). */
|
|
398
|
+
ws(path: string): TestWsRequest;
|
|
399
|
+
/**
|
|
400
|
+
* Drive a `Request` through the full Hono pipeline. The Hono app is built
|
|
401
|
+
* once and reused across requests.
|
|
402
|
+
*/
|
|
403
|
+
fetch(request: Request, env?: unknown, ctx?: unknown): Promise<Response>;
|
|
404
|
+
/**
|
|
405
|
+
* Register a default auth resolver used by `actingAs(principal)` when no
|
|
406
|
+
* resolver is passed explicitly.
|
|
407
|
+
*/
|
|
408
|
+
setAuthResolver(resolver: ActingAsResolver): this;
|
|
409
|
+
/** The default auth resolver, if one was registered. */
|
|
410
|
+
getAuthResolver(): ActingAsResolver | null;
|
|
411
|
+
/**
|
|
412
|
+
* Run `callback` inside a request-scoped child container seeded with a mock
|
|
413
|
+
* {@link RequestContext}, so REQUEST-scoped providers (and anything injecting
|
|
414
|
+
* `REQUEST_CONTEXT`) resolve. The child is disposed afterwards.
|
|
415
|
+
*/
|
|
416
|
+
runInRequestScope<T>(callback: (container: Container) => T | Promise<T>): Promise<T>;
|
|
417
|
+
/**
|
|
418
|
+
* Run the given `@Seeder()` classes, each in its own request scope. Throws if
|
|
419
|
+
* a class is not a registered seeder. Requires `SeederModule` (or the seeders
|
|
420
|
+
* themselves) to be present in the module graph.
|
|
421
|
+
*/
|
|
422
|
+
seed(...SeederClasses: Type<ISeeder>[]): Promise<void>;
|
|
423
|
+
/** Assert a row matching `where` exists in `table` (via a {@link TestDatabase}). */
|
|
424
|
+
assertDatabaseHas(db: TestDatabase, table: string, where: Record<string, unknown>): Promise<void>;
|
|
425
|
+
/** Assert no row matching `where` exists in `table`. */
|
|
426
|
+
assertDatabaseMissing(db: TestDatabase, table: string, where: Record<string, unknown>): Promise<void>;
|
|
427
|
+
/** Assert `table` has exactly `expected` rows. */
|
|
428
|
+
assertDatabaseCount(db: TestDatabase, table: string, expected: number): Promise<void>;
|
|
429
|
+
/** Dispose the application. */
|
|
430
|
+
close(signal?: string): Promise<void>;
|
|
431
|
+
private ensureHono;
|
|
432
|
+
/**
|
|
433
|
+
* Build a minimal, functional {@link RequestContext} for out-of-band request
|
|
434
|
+
* scopes. Vela has no `createMockRouterContext`; a real (empty) Hono `Context`
|
|
435
|
+
* backs the `hono` field so nothing dangles.
|
|
436
|
+
*/
|
|
437
|
+
private createMockRequestContext;
|
|
438
|
+
}
|
|
439
|
+
//#endregion
|
|
440
|
+
//#region src/testing-module.builder.d.ts
|
|
441
|
+
declare class OverrideBy {
|
|
442
|
+
private readonly builder;
|
|
443
|
+
private readonly token;
|
|
444
|
+
constructor(builder: TestingModuleBuilder, token: Token);
|
|
445
|
+
useValue(value: unknown): TestingModuleBuilder;
|
|
446
|
+
useClass(cls: Type): TestingModuleBuilder;
|
|
447
|
+
useFactory(options: {
|
|
448
|
+
factory: (...args: unknown[]) => unknown;
|
|
449
|
+
inject?: Token[];
|
|
450
|
+
}): TestingModuleBuilder;
|
|
451
|
+
}
|
|
452
|
+
declare class TestingModuleBuilder {
|
|
453
|
+
private readonly metadata;
|
|
454
|
+
private overrides;
|
|
455
|
+
constructor(metadata: ModuleOptions);
|
|
456
|
+
overrideProvider(token: Token): OverrideBy;
|
|
457
|
+
overrideGuard(guard: Type): OverrideBy;
|
|
458
|
+
overridePipe(pipe: Type): OverrideBy;
|
|
459
|
+
overrideInterceptor(interceptor: Type): OverrideBy;
|
|
460
|
+
overrideFilter(filter: Type): OverrideBy;
|
|
461
|
+
private addOverride;
|
|
462
|
+
compile(): Promise<TestingModule>;
|
|
463
|
+
}
|
|
464
|
+
//#endregion
|
|
465
|
+
//#region src/test.d.ts
|
|
466
|
+
declare const Test: {
|
|
467
|
+
createTestingModule(metadata: ModuleOptions): TestingModuleBuilder;
|
|
468
|
+
};
|
|
469
|
+
//#endregion
|
|
470
|
+
//#region src/http/path-utils.d.ts
|
|
471
|
+
/**
|
|
472
|
+
* Read the value at a dot-notation path (e.g. `data.user.id`).
|
|
473
|
+
* Returns `undefined` when any segment along the way is null/undefined.
|
|
474
|
+
*/
|
|
475
|
+
declare function getValueAtPath(obj: unknown, path: string): unknown;
|
|
476
|
+
/**
|
|
477
|
+
* Whether a dot-notation path exists on the object, even when the value at the
|
|
478
|
+
* path is `null`/`undefined`. Distinguishes "key present but null" from "key
|
|
479
|
+
* absent".
|
|
480
|
+
*/
|
|
481
|
+
declare function hasValueAtPath(obj: unknown, path: string): boolean;
|
|
482
|
+
//#endregion
|
|
483
|
+
export { type ActingAsResolver, OverrideBy, Test, type TestDatabase, TestHttpClient, TestHttpRequest, type TestPrincipal, TestResponse, TestSseConnection, type TestSseEvent, TestSseRequest, TestWsConnection, TestWsRequest, TestingModule, TestingModuleBuilder, type WsConnector, getValueAtPath, getWsConnector, hasValueAtPath, registerWsConnector };
|
|
484
|
+
//# sourceMappingURL=index.d.ts.map
|