@stratal/testing 0.0.12 → 0.0.13

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.
Files changed (33) hide show
  1. package/dist/core/sse/index.d.ts +3 -0
  2. package/dist/core/sse/index.d.ts.map +1 -0
  3. package/dist/core/sse/index.js +3 -0
  4. package/dist/core/sse/index.js.map +1 -0
  5. package/dist/core/sse/test-sse-connection.d.ts +61 -0
  6. package/dist/core/sse/test-sse-connection.d.ts.map +1 -0
  7. package/dist/core/sse/test-sse-connection.js +233 -0
  8. package/dist/core/sse/test-sse-connection.js.map +1 -0
  9. package/dist/core/sse/test-sse-request.d.ts +42 -0
  10. package/dist/core/sse/test-sse-request.d.ts.map +1 -0
  11. package/dist/core/sse/test-sse-request.js +76 -0
  12. package/dist/core/sse/test-sse-request.js.map +1 -0
  13. package/dist/core/testing-module.d.ts +10 -0
  14. package/dist/core/testing-module.d.ts.map +1 -1
  15. package/dist/core/testing-module.js +15 -3
  16. package/dist/core/testing-module.js.map +1 -1
  17. package/dist/core/ws/index.d.ts +3 -0
  18. package/dist/core/ws/index.d.ts.map +1 -0
  19. package/dist/core/ws/index.js +3 -0
  20. package/dist/core/ws/index.js.map +1 -0
  21. package/dist/core/ws/test-ws-connection.d.ts +54 -0
  22. package/dist/core/ws/test-ws-connection.d.ts.map +1 -0
  23. package/dist/core/ws/test-ws-connection.js +119 -0
  24. package/dist/core/ws/test-ws-connection.js.map +1 -0
  25. package/dist/core/ws/test-ws-request.d.ts +43 -0
  26. package/dist/core/ws/test-ws-request.d.ts.map +1 -0
  27. package/dist/core/ws/test-ws-request.js +83 -0
  28. package/dist/core/ws/test-ws-request.js.map +1 -0
  29. package/dist/index.d.ts +5 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +6 -0
  32. package/dist/index.js.map +1 -1
  33. package/package.json +3 -3
@@ -0,0 +1,3 @@
1
+ export { TestSseRequest } from './test-sse-request';
2
+ export { TestSseConnection, type TestSseEvent } from './test-sse-connection';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/sse/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAE,iBAAiB,EAAE,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAA"}
@@ -0,0 +1,3 @@
1
+ export { TestSseRequest } from './test-sse-request';
2
+ export { TestSseConnection } from './test-sse-connection';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/sse/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAE,iBAAiB,EAAqB,MAAM,uBAAuB,CAAA"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Represents a parsed SSE event
3
+ */
4
+ export interface TestSseEvent {
5
+ data: string;
6
+ event?: string;
7
+ id?: string;
8
+ retry?: number;
9
+ }
10
+ /**
11
+ * TestSseConnection
12
+ *
13
+ * Live SSE connection wrapper with assertion helpers for testing.
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const sse = await module.sse('/streaming/sse').connect()
18
+ * await sse.assertEvent({ event: 'message', data: 'hello', id: '1' })
19
+ * await sse.waitForEnd()
20
+ * ```
21
+ */
22
+ export declare class TestSseConnection {
23
+ private readonly response;
24
+ private readonly eventQueue;
25
+ private eventWaiters;
26
+ private streamEnded;
27
+ private endWaiters;
28
+ constructor(response: Response);
29
+ /**
30
+ * Wait for the next SSE event
31
+ */
32
+ waitForEvent(timeout?: number): Promise<TestSseEvent>;
33
+ /**
34
+ * Wait for the stream to end
35
+ */
36
+ waitForEnd(timeout?: number): Promise<void>;
37
+ /**
38
+ * Collect all remaining events until the stream ends
39
+ */
40
+ collectEvents(timeout?: number): Promise<TestSseEvent[]>;
41
+ /**
42
+ * Assert that the next event matches the expected partial shape
43
+ */
44
+ assertEvent(expected: Partial<TestSseEvent>, timeout?: number): Promise<void>;
45
+ /**
46
+ * Assert that the next event's data matches the expected string
47
+ */
48
+ assertEventData(expected: string, timeout?: number): Promise<void>;
49
+ /**
50
+ * Assert that the next event's data is JSON matching the expected value
51
+ */
52
+ assertJsonEventData<T>(expected: T, timeout?: number): Promise<void>;
53
+ /**
54
+ * Access the raw Response
55
+ */
56
+ get raw(): Response;
57
+ private startReading;
58
+ private parseEvent;
59
+ private dispatchEvent;
60
+ }
61
+ //# sourceMappingURL=test-sse-connection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-sse-connection.d.ts","sourceRoot":"","sources":["../../../src/core/sse/test-sse-connection.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,iBAAiB;IAMjB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IALrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAqB;IAChD,OAAO,CAAC,YAAY,CAAwC;IAC5D,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,UAAU,CAAqB;gBAEV,QAAQ,EAAE,QAAQ;IAI/C;;OAEG;IACG,YAAY,CAAC,OAAO,SAAO,GAAG,OAAO,CAAC,YAAY,CAAC;IAyBzD;;OAEG;IACG,UAAU,CAAC,OAAO,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB/C;;OAEG;IACG,aAAa,CAAC,OAAO,SAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAmC5D;;OAEG;IACG,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,YAAY,CAAC,EAAE,OAAO,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjF;;OAEG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAKtE;;OAEG;IACG,mBAAmB,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,OAAO,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAMxE;;OAEG;IACH,IAAI,GAAG,IAAI,QAAQ,CAElB;IAED,OAAO,CAAC,YAAY;IAwDpB,OAAO,CAAC,UAAU;IA6ClB,OAAO,CAAC,aAAa;CAOrB"}
@@ -0,0 +1,233 @@
1
+ import { expect } from "vitest";
2
+ /**
3
+ * TestSseConnection
4
+ *
5
+ * Live SSE connection wrapper with assertion helpers for testing.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const sse = await module.sse('/streaming/sse').connect()
10
+ * await sse.assertEvent({ event: 'message', data: 'hello', id: '1' })
11
+ * await sse.waitForEnd()
12
+ * ```
13
+ */
14
+ export class TestSseConnection {
15
+ response;
16
+ eventQueue = [];
17
+ eventWaiters = [];
18
+ streamEnded = false;
19
+ endWaiters = [];
20
+ constructor(response) {
21
+ this.response = response;
22
+ this.startReading();
23
+ }
24
+ /**
25
+ * Wait for the next SSE event
26
+ */
27
+ async waitForEvent(timeout = 5000) {
28
+ if (this.eventQueue.length > 0) {
29
+ return this.eventQueue.shift();
30
+ }
31
+ if (this.streamEnded) {
32
+ throw new Error('SSE: stream has ended, no more events');
33
+ }
34
+ return new Promise((resolve, reject) => {
35
+ const waiter = (event) => {
36
+ clearTimeout(timer);
37
+ resolve(event);
38
+ };
39
+ const timer = setTimeout(() => {
40
+ const index = this.eventWaiters.indexOf(waiter);
41
+ if (index !== -1)
42
+ this.eventWaiters.splice(index, 1);
43
+ reject(new Error(`SSE: no event received within ${timeout}ms`));
44
+ }, timeout);
45
+ this.eventWaiters.push(waiter);
46
+ });
47
+ }
48
+ /**
49
+ * Wait for the stream to end
50
+ */
51
+ async waitForEnd(timeout = 5000) {
52
+ if (this.streamEnded)
53
+ return;
54
+ return new Promise((resolve, reject) => {
55
+ const waiter = () => {
56
+ clearTimeout(timer);
57
+ resolve();
58
+ };
59
+ const timer = setTimeout(() => {
60
+ const index = this.endWaiters.indexOf(waiter);
61
+ if (index !== -1)
62
+ this.endWaiters.splice(index, 1);
63
+ reject(new Error(`SSE: stream did not end within ${timeout}ms`));
64
+ }, timeout);
65
+ this.endWaiters.push(waiter);
66
+ });
67
+ }
68
+ /**
69
+ * Collect all remaining events until the stream ends
70
+ */
71
+ async collectEvents(timeout = 5000) {
72
+ const events = [];
73
+ if (this.streamEnded) {
74
+ return [...this.eventQueue.splice(0)];
75
+ }
76
+ return new Promise((resolve, reject) => {
77
+ // Listen for new events until stream ends
78
+ const originalDispatch = this.dispatchEvent.bind(this);
79
+ this.dispatchEvent = (event) => {
80
+ events.push(event);
81
+ originalDispatch(event);
82
+ };
83
+ const endWaiter = () => {
84
+ clearTimeout(timer);
85
+ this.dispatchEvent = originalDispatch;
86
+ resolve(events);
87
+ };
88
+ const timer = setTimeout(() => {
89
+ this.dispatchEvent = originalDispatch;
90
+ const index = this.endWaiters.indexOf(endWaiter);
91
+ if (index !== -1)
92
+ this.endWaiters.splice(index, 1);
93
+ reject(new Error(`SSE: stream did not end within ${timeout}ms`));
94
+ }, timeout);
95
+ // Drain any queued events first
96
+ events.push(...this.eventQueue.splice(0));
97
+ this.endWaiters.push(endWaiter);
98
+ });
99
+ }
100
+ /**
101
+ * Assert that the next event matches the expected partial shape
102
+ */
103
+ async assertEvent(expected, timeout = 5000) {
104
+ const event = await this.waitForEvent(timeout);
105
+ expect(event).toMatchObject(expected);
106
+ }
107
+ /**
108
+ * Assert that the next event's data matches the expected string
109
+ */
110
+ async assertEventData(expected, timeout = 5000) {
111
+ const event = await this.waitForEvent(timeout);
112
+ expect(event.data, `Expected SSE data "${expected}", got "${event.data}"`).toBe(expected);
113
+ }
114
+ /**
115
+ * Assert that the next event's data is JSON matching the expected value
116
+ */
117
+ async assertJsonEventData(expected, timeout = 5000) {
118
+ const event = await this.waitForEvent(timeout);
119
+ const parsed = JSON.parse(event.data);
120
+ expect(parsed).toEqual(expected);
121
+ }
122
+ /**
123
+ * Access the raw Response
124
+ */
125
+ get raw() {
126
+ return this.response;
127
+ }
128
+ startReading() {
129
+ const body = this.response.body;
130
+ if (!body) {
131
+ this.streamEnded = true;
132
+ return;
133
+ }
134
+ const reader = body.getReader();
135
+ const decoder = new TextDecoder();
136
+ let buffer = '';
137
+ const read = async () => {
138
+ try {
139
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
140
+ while (true) {
141
+ const { done, value } = await reader.read();
142
+ if (done) {
143
+ // Parse any remaining buffered data
144
+ if (buffer.trim()) {
145
+ const event = this.parseEvent(buffer);
146
+ if (event)
147
+ this.dispatchEvent(event);
148
+ }
149
+ this.streamEnded = true;
150
+ for (const waiter of this.endWaiters) {
151
+ waiter();
152
+ }
153
+ this.endWaiters = [];
154
+ return;
155
+ }
156
+ buffer += decoder.decode(value, { stream: true });
157
+ // Split on double newlines (SSE event boundary)
158
+ const parts = buffer.split('\n\n');
159
+ // Last part may be incomplete, keep it in the buffer
160
+ buffer = parts.pop();
161
+ for (const part of parts) {
162
+ if (!part.trim())
163
+ continue;
164
+ const event = this.parseEvent(part);
165
+ if (event)
166
+ this.dispatchEvent(event);
167
+ }
168
+ }
169
+ }
170
+ catch {
171
+ this.streamEnded = true;
172
+ for (const waiter of this.endWaiters) {
173
+ waiter();
174
+ }
175
+ this.endWaiters = [];
176
+ }
177
+ };
178
+ void read();
179
+ }
180
+ parseEvent(raw) {
181
+ const lines = raw.split('\n');
182
+ const dataLines = [];
183
+ let event;
184
+ let id;
185
+ let retry;
186
+ for (const line of lines) {
187
+ if (line.startsWith(':'))
188
+ continue; // comment line
189
+ const colonIndex = line.indexOf(':');
190
+ if (colonIndex === -1)
191
+ continue;
192
+ const field = line.slice(0, colonIndex);
193
+ // Strip optional leading space after colon
194
+ const value = line[colonIndex + 1] === ' ' ? line.slice(colonIndex + 2) : line.slice(colonIndex + 1);
195
+ switch (field) {
196
+ case 'data':
197
+ dataLines.push(value);
198
+ break;
199
+ case 'event':
200
+ event = value;
201
+ break;
202
+ case 'id':
203
+ id = value;
204
+ break;
205
+ case 'retry': {
206
+ const parsed = parseInt(value, 10);
207
+ if (!isNaN(parsed))
208
+ retry = parsed;
209
+ break;
210
+ }
211
+ }
212
+ }
213
+ if (dataLines.length === 0)
214
+ return null;
215
+ const result = { data: dataLines.join('\n') };
216
+ if (event !== undefined)
217
+ result.event = event;
218
+ if (id !== undefined)
219
+ result.id = id;
220
+ if (retry !== undefined)
221
+ result.retry = retry;
222
+ return result;
223
+ }
224
+ dispatchEvent(event) {
225
+ if (this.eventWaiters.length > 0) {
226
+ this.eventWaiters.shift()(event);
227
+ }
228
+ else {
229
+ this.eventQueue.push(event);
230
+ }
231
+ }
232
+ }
233
+ //# sourceMappingURL=test-sse-connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-sse-connection.js","sourceRoot":"","sources":["../../../src/core/sse/test-sse-connection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import type { TestingModule } from '../testing-module';
2
+ import { TestSseConnection } from './test-sse-connection';
3
+ /**
4
+ * TestSseRequest
5
+ *
6
+ * Builder for SSE connection requests. Follows the TestWsRequest pattern.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const sse = await module.sse('/streaming/sse').connect()
11
+ * await sse.assertEvent({ event: 'message', data: 'hello' })
12
+ * await sse.waitForEnd()
13
+ * ```
14
+ *
15
+ * @example Authenticated SSE
16
+ * ```typescript
17
+ * const sse = await module.sse('/streaming/sse').actingAs({ id: user.id }).connect()
18
+ * ```
19
+ */
20
+ export declare class TestSseRequest {
21
+ private readonly path;
22
+ private readonly module;
23
+ private requestHeaders;
24
+ private actingAsUser;
25
+ constructor(path: string, module: TestingModule);
26
+ /**
27
+ * Add custom headers to the request
28
+ */
29
+ withHeaders(headers: Record<string, string>): this;
30
+ /**
31
+ * Authenticate the SSE connection as a specific user
32
+ */
33
+ actingAs(user: {
34
+ id: string;
35
+ }): this;
36
+ /**
37
+ * Send the request and return a live SSE connection
38
+ */
39
+ connect(): Promise<TestSseConnection>;
40
+ private applyAuthentication;
41
+ }
42
+ //# sourceMappingURL=test-sse-request.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-sse-request.d.ts","sourceRoot":"","sources":["../../../src/core/sse/test-sse-request.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAEzD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,cAAc;IAKzB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM;IALxB,OAAO,CAAC,cAAc,CAAyB;IAC/C,OAAO,CAAC,YAAY,CAA8B;gBAGhC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,aAAa;IAGvC;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IAOlD;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAKpC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,iBAAiB,CAAC;YA0B7B,mBAAmB;CAajC"}
@@ -0,0 +1,76 @@
1
+ import { AUTH_SERVICE } from '@stratal/framework/auth';
2
+ import { expect } from 'vitest';
3
+ import { ActingAs } from '../../auth';
4
+ import { TestSseConnection } from './test-sse-connection';
5
+ /**
6
+ * TestSseRequest
7
+ *
8
+ * Builder for SSE connection requests. Follows the TestWsRequest pattern.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const sse = await module.sse('/streaming/sse').connect()
13
+ * await sse.assertEvent({ event: 'message', data: 'hello' })
14
+ * await sse.waitForEnd()
15
+ * ```
16
+ *
17
+ * @example Authenticated SSE
18
+ * ```typescript
19
+ * const sse = await module.sse('/streaming/sse').actingAs({ id: user.id }).connect()
20
+ * ```
21
+ */
22
+ export class TestSseRequest {
23
+ path;
24
+ module;
25
+ requestHeaders = new Headers();
26
+ actingAsUser = null;
27
+ constructor(path, module) {
28
+ this.path = path;
29
+ this.module = module;
30
+ }
31
+ /**
32
+ * Add custom headers to the request
33
+ */
34
+ withHeaders(headers) {
35
+ for (const [key, value] of Object.entries(headers)) {
36
+ this.requestHeaders.set(key, value);
37
+ }
38
+ return this;
39
+ }
40
+ /**
41
+ * Authenticate the SSE connection as a specific user
42
+ */
43
+ actingAs(user) {
44
+ this.actingAsUser = user;
45
+ return this;
46
+ }
47
+ /**
48
+ * Send the request and return a live SSE connection
49
+ */
50
+ async connect() {
51
+ await this.applyAuthentication();
52
+ this.requestHeaders.set('Accept', 'text/event-stream');
53
+ const url = new URL(this.path, 'http://localhost');
54
+ const request = new Request(url.toString(), {
55
+ headers: this.requestHeaders,
56
+ });
57
+ const response = await this.module.fetch(request);
58
+ expect(response.status, `Expected status 200, got ${response.status}`).toBe(200);
59
+ const contentType = response.headers.get('content-type') ?? '';
60
+ expect(contentType.includes('text/event-stream'), `Expected content-type "text/event-stream", got "${contentType}"`).toBe(true);
61
+ return new TestSseConnection(response);
62
+ }
63
+ async applyAuthentication() {
64
+ if (!this.actingAsUser)
65
+ return;
66
+ await this.module.runInRequestScope(async () => {
67
+ const authService = this.module.get(AUTH_SERVICE);
68
+ const actingAs = new ActingAs(authService);
69
+ const authHeaders = this.actingAsUser ? await actingAs.createSessionForUser(this.actingAsUser) : new Headers();
70
+ for (const [key, value] of authHeaders.entries()) {
71
+ this.requestHeaders.set(key, value);
72
+ }
73
+ });
74
+ }
75
+ }
76
+ //# sourceMappingURL=test-sse-request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-sse-request.js","sourceRoot":"","sources":["../../../src/core/sse/test-sse-request.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAErC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAEzD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,cAAc;IAKR;IACA;IALV,cAAc,GAAY,IAAI,OAAO,EAAE,CAAA;IACvC,YAAY,GAA0B,IAAI,CAAA;IAElD,YACkB,IAAY,EACZ,MAAqB;QADrB,SAAI,GAAJ,IAAI,CAAQ;QACZ,WAAM,GAAN,MAAM,CAAe;IACnC,CAAC;IAEL;;OAEG;IACH,WAAW,CAAC,OAA+B;QAC1C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YACpD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QACpC,CAAC;QACD,OAAO,IAAI,CAAA;IACZ,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,IAAoB;QAC5B,IAAI,CAAC,YAAY,GAAG,IAAI,CAAA;QACxB,OAAO,IAAI,CAAA;IACZ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO;QACZ,MAAM,IAAI,CAAC,mBAAmB,EAAE,CAAA;QAEhC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAA;QAEtD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAA;QAClD,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE;YAC3C,OAAO,EAAE,IAAI,CAAC,cAAc;SAC5B,CAAC,CAAA;QAEF,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;QAEjD,MAAM,CACL,QAAQ,CAAC,MAAM,EACf,4BAA4B,QAAQ,CAAC,MAAM,EAAE,CAC7C,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAEX,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAA;QAC9D,MAAM,CACL,WAAW,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EACzC,mDAAmD,WAAW,GAAG,CACjE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAEZ,OAAO,IAAI,iBAAiB,CAAC,QAAQ,CAAC,CAAA;IACvC,CAAC;IAEO,KAAK,CAAC,mBAAmB;QAChC,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAM;QAE9B,MAAM,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,KAAK,IAAI,EAAE;YAC9C,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAc,YAAY,CAAC,CAAA;YAC9D,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,WAAW,CAAC,CAAA;YAC1C,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,QAAQ,CAAC,oBAAoB,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAA;YAE9G,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC;gBAClD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;YACpC,CAAC;QACF,CAAC,CAAC,CAAA;IACH,CAAC;CACD"}
@@ -5,6 +5,8 @@ import { type InjectionToken } from 'stratal/module';
5
5
  import type { FakeStorageService } from '../storage';
6
6
  import type { Seeder } from '../types';
7
7
  import { TestHttpClient } from './http/test-http-client';
8
+ import { TestSseRequest } from './sse/test-sse-request';
9
+ import { TestWsRequest } from './ws/test-ws-request';
8
10
  /**
9
11
  * TestingModule
10
12
  *
@@ -53,6 +55,14 @@ export declare class TestingModule {
53
55
  * Get fake storage service for assertions
54
56
  */
55
57
  get storage(): FakeStorageService;
58
+ /**
59
+ * Create a WebSocket test request builder for the given path
60
+ */
61
+ ws(path: string): TestWsRequest;
62
+ /**
63
+ * Create an SSE test request builder for the given path
64
+ */
65
+ sse(path: string): TestSseRequest;
56
66
  /**
57
67
  * Get Application instance
58
68
  */
@@ -1 +1 @@
1
- {"version":3,"file":"testing-module.d.ts","sourceRoot":"","sources":["../../src/core/testing-module.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAElF,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACtD,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,YAAY,CAAA;AACtD,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AACpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBAAa,aAAa;IAKtB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,GAAG;IANtB,OAAO,CAAC,KAAK,CAA8B;IAC3C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAW;gBAG1B,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,UAAU,EACf,GAAG,EAAE,gBAAgB;IAMxC;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC;IAInC;;OAEG;IACH,IAAI,IAAI,IAAI,cAAc,CAGzB;IAED;;OAEG;IACH,IAAI,OAAO,IAAI,kBAAkB,CAEhC;IAED;;OAEG;IACH,IAAI,WAAW,IAAI,WAAW,CAE7B;IAED;;OAEG;IACH,IAAI,SAAS,IAAI,SAAS,CAEzB;IAED;;OAEG;IACG,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;IAIhD;;OAEG;IACG,iBAAiB,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAK1F;;OAEG;IACH,KAAK,IAAI,eAAe;IACxB,KAAK,CAAC,CAAC,SAAS,cAAc,EAAE,IAAI,EAAE,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC;IAM5D;;OAEG;IACG,UAAU,CAAC,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAYtD;;OAEG;IACG,IAAI,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IACzC,IAAI,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAoBrE;;OAEG;IACG,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ3G;;OAEG;IACG,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ/G;;OAEG;IACG,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAQhG;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAI7B"}
1
+ {"version":3,"file":"testing-module.d.ts","sourceRoot":"","sources":["../../src/core/testing-module.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,10 @@
1
1
  import { connectionSymbol } from '@stratal/framework/database';
2
2
  import { DI_TOKENS } from 'stratal/di';
3
3
  import { STORAGE_TOKENS } from 'stratal/storage';
4
+ import { expect } from 'vitest';
4
5
  import { TestHttpClient } from './http/test-http-client';
6
+ import { TestSseRequest } from './sse/test-sse-request';
7
+ import { TestWsRequest } from './ws/test-ws-request';
5
8
  /**
6
9
  * TestingModule
7
10
  *
@@ -63,6 +66,18 @@ export class TestingModule {
63
66
  get storage() {
64
67
  return this.get(STORAGE_TOKENS.StorageService);
65
68
  }
69
+ /**
70
+ * Create a WebSocket test request builder for the given path
71
+ */
72
+ ws(path) {
73
+ return new TestWsRequest(path, this);
74
+ }
75
+ /**
76
+ * Create an SSE test request builder for the given path
77
+ */
78
+ sse(path) {
79
+ return new TestSseRequest(path, this);
80
+ }
66
81
  /**
67
82
  * Get Application instance
68
83
  */
@@ -128,7 +143,6 @@ export class TestingModule {
128
143
  * Assert that a record exists in the database
129
144
  */
130
145
  async assertDatabaseHas(table, data, name) {
131
- const { expect } = await import('vitest');
132
146
  const db = this.getDb(name);
133
147
  const model = db[table];
134
148
  const result = await model.findFirst({ where: data });
@@ -138,7 +152,6 @@ export class TestingModule {
138
152
  * Assert that a record does not exist in the database
139
153
  */
140
154
  async assertDatabaseMissing(table, data, name) {
141
- const { expect } = await import('vitest');
142
155
  const db = this.getDb(name);
143
156
  const model = db[table];
144
157
  const result = await model.findFirst({ where: data });
@@ -148,7 +161,6 @@ export class TestingModule {
148
161
  * Assert the number of records in a table
149
162
  */
150
163
  async assertDatabaseCount(table, expected, name) {
151
- const { expect } = await import('vitest');
152
164
  const db = this.getDb(name);
153
165
  const model = db[table];
154
166
  const actual = await model.count();
@@ -1 +1 @@
1
- {"version":3,"file":"testing-module.js","sourceRoot":"","sources":["../../src/core/testing-module.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AAE9D,OAAO,EAAE,SAAS,EAAkB,MAAM,YAAY,CAAA;AAEtD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAGhD,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,OAAO,aAAa;IAKL;IACA;IACA;IANX,KAAK,GAA0B,IAAI,CAAA;IAC1B,iBAAiB,CAAW;IAE7C,YACmB,GAAgB,EAChB,GAAe,EACf,GAAqB;QAFrB,QAAG,GAAH,GAAG,CAAa;QAChB,QAAG,GAAH,GAAG,CAAY;QACf,QAAG,GAAH,GAAG,CAAkB;QAEtC,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,uBAAuB,EAAE,CAAA;QACtD,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAA;IAC7E,CAAC;IAED;;OAEG;IACH,GAAG,CAAI,KAAwB;QAC7B,OAAO,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IAC9C,CAAC;IAED;;OAEG;IACH,IAAI,IAAI;QACN,IAAI,CAAC,KAAK,KAAK,IAAI,cAAc,CAAC,IAAI,CAAC,CAAA;QACvC,OAAO,IAAI,CAAC,KAAK,CAAA;IACnB,CAAC;IAED;;OAEG;IACH,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,GAAG,CAAqB,cAAc,CAAC,cAAc,CAAC,CAAA;IACpE,CAAC;IAED;;OAEG;IACH,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,GAAG,CAAA;IACjB,CAAC;IAED;;OAEG;IACH,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,iBAAiB,CAAA;IAC/B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK,CAAC,OAAgB;QAC1B,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;IACzD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,iBAAiB,CAAI,QAAkD;QAC3E,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,uBAAuB,EAAE,CAAA;QACtD,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,iBAAiB,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;IACpE,CAAC;IAOD,KAAK,CAAC,IAAa;QACjB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAA;QAChE,OAAO,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IAC9C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU,CAAC,IAAqB;QACpC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAK,CAAC,CAAA;QAC5B,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,SAAS,CAAyB;;;;KAIzD,CAAA;QACD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAM;QAC/B,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClE,MAAM,EAAE,CAAC,iBAAiB,CAAC,YAAY,SAAS,2BAA2B,CAAC,CAAA;IAC9E,CAAC;IAOD,KAAK,CAAC,IAAI,CAAC,GAAG,IAAe;QAC3B,IAAI,IAAwB,CAAA;QAC5B,IAAI,OAAiB,CAAA;QAErB,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;YAChC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;YACd,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAa,CAAA;QACrC,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,IAAgB,CAAA;QAC5B,CAAC;QAED,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAK,CAAC,CAAA;QAC5B,MAAM,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YACjC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,MAAM,MAAM,CAAC,GAAG,CAAC,EAAqB,CAAC,CAAA;YACzC,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,iBAAiB,CAAC,KAAa,EAAE,IAA6B,EAAE,IAAqB;QACzF,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAA;QACzC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAK,CAAC,CAAA;QAC5B,MAAM,KAAK,GAAI,EAAyC,CAAC,KAAK,CAAuD,CAAA;QACrH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QACrD,MAAM,CAAC,MAAM,EAAE,YAAY,KAAK,SAAS,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAA;IACjF,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,qBAAqB,CAAC,KAAa,EAAE,IAA6B,EAAE,IAAqB;QAC7F,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAA;QACzC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAK,CAAC,CAAA;QAC5B,MAAM,KAAK,GAAI,EAAyC,CAAC,KAAK,CAAuD,CAAA;QACrH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QACrD,MAAM,CAAC,MAAM,EAAE,YAAY,KAAK,gBAAgB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAA;IACpF,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,mBAAmB,CAAC,KAAa,EAAE,QAAgB,EAAE,IAAqB;QAC9E,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAA;QACzC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAK,CAAC,CAAA;QAC5B,MAAM,KAAK,GAAI,EAAyC,CAAC,KAAK,CAAqC,CAAA;QACnG,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,CAAA;QAClC,MAAM,CAAC,MAAM,EAAE,YAAY,KAAK,UAAU,QAAQ,SAAS,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IACrF,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,CAAA;QACtC,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAA;IAC3B,CAAC;CACF"}
1
+ {"version":3,"file":"testing-module.js","sourceRoot":"","sources":["../../src/core/testing-module.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA;AAE9D,OAAO,EAAE,SAAS,EAAkB,MAAM,YAAY,CAAA;AAEtD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAG/B,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAEpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,OAAO,aAAa;IAKL;IACA;IACA;IANX,KAAK,GAA0B,IAAI,CAAA;IAC1B,iBAAiB,CAAW;IAE7C,YACmB,GAAgB,EAChB,GAAe,EACf,GAAqB;QAFrB,QAAG,GAAH,GAAG,CAAa;QAChB,QAAG,GAAH,GAAG,CAAY;QACf,QAAG,GAAH,GAAG,CAAkB;QAEtC,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,uBAAuB,EAAE,CAAA;QACtD,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAA;IAC7E,CAAC;IAED;;OAEG;IACH,GAAG,CAAI,KAAwB;QAC7B,OAAO,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IAC9C,CAAC;IAED;;OAEG;IACH,IAAI,IAAI;QACN,IAAI,CAAC,KAAK,KAAK,IAAI,cAAc,CAAC,IAAI,CAAC,CAAA;QACvC,OAAO,IAAI,CAAC,KAAK,CAAA;IACnB,CAAC;IAED;;OAEG;IACH,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,GAAG,CAAqB,cAAc,CAAC,cAAc,CAAC,CAAA;IACpE,CAAC;IAED;;OAEG;IACH,EAAE,CAAC,IAAY;QACb,OAAO,IAAI,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IACtC,CAAC;IAED;;OAEG;IACH,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IACvC,CAAC;IAED;;OAEG;IACH,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,GAAG,CAAA;IACjB,CAAC;IAED;;OAEG;IACH,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,iBAAiB,CAAA;IAC/B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK,CAAC,OAAgB;QAC1B,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAA;IACzD,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,iBAAiB,CAAI,QAAkD;QAC3E,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,uBAAuB,EAAE,CAAA;QACtD,OAAO,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,iBAAiB,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;IACpE,CAAC;IAOD,KAAK,CAAC,IAAa;QACjB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAA;QAChE,OAAO,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;IAC9C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,UAAU,CAAC,IAAqB;QACpC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAK,CAAC,CAAA;QAC5B,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,SAAS,CAAyB;;;;KAIzD,CAAA;QACD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAM;QAC/B,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAClE,MAAM,EAAE,CAAC,iBAAiB,CAAC,YAAY,SAAS,2BAA2B,CAAC,CAAA;IAC9E,CAAC;IAOD,KAAK,CAAC,IAAI,CAAC,GAAG,IAAe;QAC3B,IAAI,IAAwB,CAAA;QAC5B,IAAI,OAAiB,CAAA;QAErB,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;YAChC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;YACd,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAa,CAAA;QACrC,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,IAAgB,CAAA;QAC5B,CAAC;QAED,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAK,CAAC,CAAA;QAC5B,MAAM,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;YACjC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;gBAC7B,MAAM,MAAM,CAAC,GAAG,CAAC,EAAqB,CAAC,CAAA;YACzC,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,iBAAiB,CAAC,KAAa,EAAE,IAA6B,EAAE,IAAqB;QACzF,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAK,CAAC,CAAA;QAC5B,MAAM,KAAK,GAAI,EAAyC,CAAC,KAAK,CAAuD,CAAA;QACrH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QACrD,MAAM,CAAC,MAAM,EAAE,YAAY,KAAK,SAAS,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAA;IACjF,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,qBAAqB,CAAC,KAAa,EAAE,IAA6B,EAAE,IAAqB;QAC7F,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAK,CAAC,CAAA;QAC5B,MAAM,KAAK,GAAI,EAAyC,CAAC,KAAK,CAAuD,CAAA;QACrH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QACrD,MAAM,CAAC,MAAM,EAAE,YAAY,KAAK,gBAAgB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAA;IACpF,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,mBAAmB,CAAC,KAAa,EAAE,QAAgB,EAAE,IAAqB;QAC9E,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAK,CAAC,CAAA;QAC5B,MAAM,KAAK,GAAI,EAAyC,CAAC,KAAK,CAAqC,CAAA;QACnG,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,KAAK,EAAE,CAAA;QAClC,MAAM,CAAC,MAAM,EAAE,YAAY,KAAK,UAAU,QAAQ,SAAS,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IACrF,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,CAAA;QACtC,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAA;IAC3B,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ export { TestWsRequest } from './test-ws-request';
2
+ export { TestWsConnection } from './test-ws-connection';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/ws/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA"}
@@ -0,0 +1,3 @@
1
+ export { TestWsRequest } from './test-ws-request';
2
+ export { TestWsConnection } from './test-ws-connection';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/ws/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * TestWsConnection
3
+ *
4
+ * Live WebSocket connection wrapper with assertion helpers for testing.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * const ws = await module.ws('/ws/chat').connect()
9
+ * ws.send('hello')
10
+ * await ws.assertMessage('echo:hello')
11
+ * ws.close()
12
+ * await ws.waitForClose()
13
+ * ```
14
+ */
15
+ export declare class TestWsConnection {
16
+ private readonly ws;
17
+ private readonly messageQueue;
18
+ private messageWaiters;
19
+ private closeEvent;
20
+ private closeWaiters;
21
+ constructor(ws: WebSocket);
22
+ /**
23
+ * Send a message through the WebSocket
24
+ */
25
+ send(data: string | ArrayBuffer | Uint8Array): void;
26
+ /**
27
+ * Close the WebSocket connection
28
+ */
29
+ close(code?: number, reason?: string): void;
30
+ /**
31
+ * Wait for the next message, returning its data
32
+ */
33
+ waitForMessage(timeout?: number): Promise<string | ArrayBuffer>;
34
+ /**
35
+ * Wait for the connection to close
36
+ */
37
+ waitForClose(timeout?: number): Promise<{
38
+ code?: number;
39
+ reason?: string;
40
+ }>;
41
+ /**
42
+ * Assert that the next message equals the expected value
43
+ */
44
+ assertMessage(expected: string, timeout?: number): Promise<void>;
45
+ /**
46
+ * Assert that the connection closes, optionally with an expected code
47
+ */
48
+ assertClosed(expectedCode?: number, timeout?: number): Promise<void>;
49
+ /**
50
+ * Access the raw Cloudflare WebSocket
51
+ */
52
+ get raw(): WebSocket;
53
+ }
54
+ //# sourceMappingURL=test-ws-connection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-ws-connection.d.ts","sourceRoot":"","sources":["../../../src/core/ws/test-ws-connection.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;GAaG;AACH,qBAAa,gBAAgB;IAMhB,OAAO,CAAC,QAAQ,CAAC,EAAE;IAL/B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA+B;IAC5D,OAAO,CAAC,cAAc,CAA+C;IACrE,OAAO,CAAC,UAAU,CAAkD;IACpE,OAAO,CAAC,YAAY,CAA8D;gBAErD,EAAE,EAAE,SAAS;IAmB1C;;OAEG;IACH,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,IAAI;IAInD;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;IAI3C;;OAEG;IACG,cAAc,CAAC,OAAO,SAAO,GAAG,OAAO,CAAC,MAAM,GAAG,WAAW,CAAC;IAqBnE;;OAEG;IACG,YAAY,CAAC,OAAO,SAAO,GAAG,OAAO,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAqB/E;;OAEG;IACG,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAMpE;;OAEG;IACG,YAAY,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,OAAO,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAOxE;;OAEG;IACH,IAAI,GAAG,IAAI,SAAS,CAEnB;CACD"}
@@ -0,0 +1,119 @@
1
+ import { expect } from "vitest";
2
+ /**
3
+ * TestWsConnection
4
+ *
5
+ * Live WebSocket connection wrapper with assertion helpers for testing.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const ws = await module.ws('/ws/chat').connect()
10
+ * ws.send('hello')
11
+ * await ws.assertMessage('echo:hello')
12
+ * ws.close()
13
+ * await ws.waitForClose()
14
+ * ```
15
+ */
16
+ export class TestWsConnection {
17
+ ws;
18
+ messageQueue = [];
19
+ messageWaiters = [];
20
+ closeEvent = null;
21
+ closeWaiters = [];
22
+ constructor(ws) {
23
+ this.ws = ws;
24
+ this.ws.addEventListener('message', (event) => {
25
+ const data = event.data;
26
+ if (this.messageWaiters.length > 0) {
27
+ this.messageWaiters.shift()(data);
28
+ }
29
+ else {
30
+ this.messageQueue.push(data);
31
+ }
32
+ });
33
+ this.ws.addEventListener('close', (event) => {
34
+ this.closeEvent = { code: event.code, reason: event.reason };
35
+ for (const waiter of this.closeWaiters) {
36
+ waiter(this.closeEvent);
37
+ }
38
+ this.closeWaiters = [];
39
+ });
40
+ }
41
+ /**
42
+ * Send a message through the WebSocket
43
+ */
44
+ send(data) {
45
+ this.ws.send(data);
46
+ }
47
+ /**
48
+ * Close the WebSocket connection
49
+ */
50
+ close(code, reason) {
51
+ this.ws.close(code, reason);
52
+ }
53
+ /**
54
+ * Wait for the next message, returning its data
55
+ */
56
+ async waitForMessage(timeout = 5000) {
57
+ if (this.messageQueue.length > 0) {
58
+ return this.messageQueue.shift();
59
+ }
60
+ return new Promise((resolve, reject) => {
61
+ const waiter = (data) => {
62
+ clearTimeout(timer);
63
+ resolve(data);
64
+ };
65
+ const timer = setTimeout(() => {
66
+ const index = this.messageWaiters.indexOf(waiter);
67
+ if (index !== -1)
68
+ this.messageWaiters.splice(index, 1);
69
+ reject(new Error(`WebSocket: no message received within ${timeout}ms`));
70
+ }, timeout);
71
+ this.messageWaiters.push(waiter);
72
+ });
73
+ }
74
+ /**
75
+ * Wait for the connection to close
76
+ */
77
+ async waitForClose(timeout = 5000) {
78
+ if (this.closeEvent) {
79
+ return this.closeEvent;
80
+ }
81
+ return new Promise((resolve, reject) => {
82
+ const waiter = (event) => {
83
+ clearTimeout(timer);
84
+ resolve(event);
85
+ };
86
+ const timer = setTimeout(() => {
87
+ const index = this.closeWaiters.indexOf(waiter);
88
+ if (index !== -1)
89
+ this.closeWaiters.splice(index, 1);
90
+ reject(new Error(`WebSocket: connection did not close within ${timeout}ms`));
91
+ }, timeout);
92
+ this.closeWaiters.push(waiter);
93
+ });
94
+ }
95
+ /**
96
+ * Assert that the next message equals the expected value
97
+ */
98
+ async assertMessage(expected, timeout = 5000) {
99
+ const data = await this.waitForMessage(timeout);
100
+ const message = typeof data === 'string' ? data : '[ArrayBuffer]';
101
+ expect(message, `Expected WebSocket message "${expected}", got "${message}"`).toBe(expected);
102
+ }
103
+ /**
104
+ * Assert that the connection closes, optionally with an expected code
105
+ */
106
+ async assertClosed(expectedCode, timeout = 5000) {
107
+ const event = await this.waitForClose(timeout);
108
+ if (expectedCode !== undefined) {
109
+ expect(event.code, `Expected close code ${expectedCode}, got ${event.code}`).toBe(expectedCode);
110
+ }
111
+ }
112
+ /**
113
+ * Access the raw Cloudflare WebSocket
114
+ */
115
+ get raw() {
116
+ return this.ws;
117
+ }
118
+ }
119
+ //# sourceMappingURL=test-ws-connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-ws-connection.js","sourceRoot":"","sources":["../../../src/core/ws/test-ws-connection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import type { TestingModule } from '../testing-module';
2
+ import { TestWsConnection } from './test-ws-connection';
3
+ /**
4
+ * TestWsRequest
5
+ *
6
+ * Builder for WebSocket upgrade requests. Follows the TestHttpRequest pattern.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const ws = await module.ws('/ws/chat').connect()
11
+ * ws.send('hello')
12
+ * await ws.assertMessage('echo:hello')
13
+ * ws.close()
14
+ * ```
15
+ *
16
+ * @example Authenticated WebSocket
17
+ * ```typescript
18
+ * const ws = await module.ws('/ws/chat').actingAs({ id: user.id }).connect()
19
+ * ```
20
+ */
21
+ export declare class TestWsRequest {
22
+ private readonly path;
23
+ private readonly module;
24
+ private requestHeaders;
25
+ private actingAsUser;
26
+ constructor(path: string, module: TestingModule);
27
+ /**
28
+ * Add custom headers to the upgrade request
29
+ */
30
+ withHeaders(headers: Record<string, string>): this;
31
+ /**
32
+ * Authenticate the WebSocket connection as a specific user
33
+ */
34
+ actingAs(user: {
35
+ id: string;
36
+ }): this;
37
+ /**
38
+ * Send the upgrade request and return a live WebSocket connection
39
+ */
40
+ connect(): Promise<TestWsConnection>;
41
+ private applyAuthentication;
42
+ }
43
+ //# sourceMappingURL=test-ws-request.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-ws-request.d.ts","sourceRoot":"","sources":["../../../src/core/ws/test-ws-request.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAEvD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,aAAa;IAKxB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM;IALxB,OAAO,CAAC,cAAc,CAAyB;IAC/C,OAAO,CAAC,YAAY,CAA8B;gBAGhC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,aAAa;IAGvC;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI;IAOlD;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAKpC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,gBAAgB,CAAC;YA8B5B,mBAAmB;CAajC"}
@@ -0,0 +1,83 @@
1
+ import { AUTH_SERVICE } from '@stratal/framework/auth';
2
+ import { expect } from 'vitest';
3
+ import { ActingAs } from '../../auth';
4
+ import { TestWsConnection } from './test-ws-connection';
5
+ /**
6
+ * TestWsRequest
7
+ *
8
+ * Builder for WebSocket upgrade requests. Follows the TestHttpRequest pattern.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const ws = await module.ws('/ws/chat').connect()
13
+ * ws.send('hello')
14
+ * await ws.assertMessage('echo:hello')
15
+ * ws.close()
16
+ * ```
17
+ *
18
+ * @example Authenticated WebSocket
19
+ * ```typescript
20
+ * const ws = await module.ws('/ws/chat').actingAs({ id: user.id }).connect()
21
+ * ```
22
+ */
23
+ export class TestWsRequest {
24
+ path;
25
+ module;
26
+ requestHeaders = new Headers();
27
+ actingAsUser = null;
28
+ constructor(path, module) {
29
+ this.path = path;
30
+ this.module = module;
31
+ }
32
+ /**
33
+ * Add custom headers to the upgrade request
34
+ */
35
+ withHeaders(headers) {
36
+ for (const [key, value] of Object.entries(headers)) {
37
+ this.requestHeaders.set(key, value);
38
+ }
39
+ return this;
40
+ }
41
+ /**
42
+ * Authenticate the WebSocket connection as a specific user
43
+ */
44
+ actingAs(user) {
45
+ this.actingAsUser = user;
46
+ return this;
47
+ }
48
+ /**
49
+ * Send the upgrade request and return a live WebSocket connection
50
+ */
51
+ async connect() {
52
+ await this.applyAuthentication();
53
+ this.requestHeaders.set('Upgrade', 'websocket');
54
+ this.requestHeaders.set('Connection', 'Upgrade');
55
+ this.requestHeaders.set('Sec-WebSocket-Key', 'dGhlIHNhbXBsZSBub25jZQ==');
56
+ this.requestHeaders.set('Sec-WebSocket-Version', '13');
57
+ const url = new URL(this.path, 'http://localhost');
58
+ const request = new Request(url.toString(), {
59
+ headers: this.requestHeaders,
60
+ });
61
+ const response = await this.module.fetch(request);
62
+ expect(response.status, `Expected status 101 (Switching Protocols), got ${response.status}`).toBe(101);
63
+ const ws = response.webSocket;
64
+ if (!ws) {
65
+ throw new Error('Response did not include a WebSocket connection');
66
+ }
67
+ ws.accept();
68
+ return new TestWsConnection(ws);
69
+ }
70
+ async applyAuthentication() {
71
+ if (!this.actingAsUser)
72
+ return;
73
+ await this.module.runInRequestScope(async () => {
74
+ const authService = this.module.get(AUTH_SERVICE);
75
+ const actingAs = new ActingAs(authService);
76
+ const authHeaders = this.actingAsUser ? await actingAs.createSessionForUser(this.actingAsUser) : new Headers();
77
+ for (const [key, value] of authHeaders.entries()) {
78
+ this.requestHeaders.set(key, value);
79
+ }
80
+ });
81
+ }
82
+ }
83
+ //# sourceMappingURL=test-ws-request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-ws-request.js","sourceRoot":"","sources":["../../../src/core/ws/test-ws-request.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -7,6 +7,11 @@ export type { MockErrorOptions, MockJsonOptions } from './core/http/fetch-mock.t
7
7
  export { TestHttpClient } from './core/http/test-http-client';
8
8
  export { TestHttpRequest } from './core/http/test-http-request';
9
9
  export { TestResponse } from './core/http/test-response';
10
+ export { TestWsRequest } from './core/ws/test-ws-request';
11
+ export { TestWsConnection } from './core/ws/test-ws-connection';
12
+ export { TestSseRequest } from './core/sse/test-sse-request';
13
+ export { TestSseConnection } from './core/sse/test-sse-connection';
14
+ export type { TestSseEvent } from './core/sse/test-sse-connection';
10
15
  export { http, HttpResponse } from 'msw';
11
16
  export { ActingAs } from './auth';
12
17
  export { FakeStorageService, type StoredFile } from './storage';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,KAAK,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AACtF,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,EAAE,oBAAoB,EAAE,KAAK,mBAAmB,EAAE,MAAM,+BAA+B,CAAA;AAG9F,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AACnE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AACrF,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAGxD,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,KAAK,CAAA;AAGxC,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAGjC,OAAO,EAAE,kBAAkB,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAA;AAG/D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAGhC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAGvC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,KAAK,sBAAsB,EAAE,MAAM,iBAAiB,CAAA;AACtF,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,EAAE,oBAAoB,EAAE,KAAK,mBAAmB,EAAE,MAAM,+BAA+B,CAAA;AAG9F,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AACnE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA;AACrF,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAGxD,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAG/D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAClE,YAAY,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AAGlE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,KAAK,CAAA;AAGxC,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAGjC,OAAO,EAAE,kBAAkB,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAA;AAG/D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAGhC,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAGvC,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA"}
package/dist/index.js CHANGED
@@ -8,6 +8,12 @@ export { createMockFetch, MockFetch } from './core/http/mock-fetch';
8
8
  export { TestHttpClient } from './core/http/test-http-client';
9
9
  export { TestHttpRequest } from './core/http/test-http-request';
10
10
  export { TestResponse } from './core/http/test-response';
11
+ // WebSocket Testing
12
+ export { TestWsRequest } from './core/ws/test-ws-request';
13
+ export { TestWsConnection } from './core/ws/test-ws-connection';
14
+ // SSE Testing
15
+ export { TestSseRequest } from './core/sse/test-sse-request';
16
+ export { TestSseConnection } from './core/sse/test-sse-connection';
11
17
  // Re-export MSW utilities for convenience
12
18
  export { http, HttpResponse } from 'msw';
13
19
  // Auth
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,uBAAuB,EAA+B,MAAM,iBAAiB,CAAA;AACtF,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,EAAE,oBAAoB,EAA4B,MAAM,+BAA+B,CAAA;AAE9F,eAAe;AACf,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAEnE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAExD,0CAA0C;AAC1C,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,KAAK,CAAA;AAExC,OAAO;AACP,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAEjC,UAAU;AACV,OAAO,EAAE,kBAAkB,EAAmB,MAAM,WAAW,CAAA;AAE/D,QAAQ;AACR,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAEhC,wBAAwB;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAEvC,SAAS;AACT,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EAAE,uBAAuB,EAA+B,MAAM,iBAAiB,CAAA;AACtF,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,EAAE,oBAAoB,EAA4B,MAAM,+BAA+B,CAAA;AAE9F,eAAe;AACf,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAEnE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAExD,oBAAoB;AACpB,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAA;AAE/D,cAAc;AACd,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAGlE,0CAA0C;AAC1C,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,KAAK,CAAA;AAExC,OAAO;AACP,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAEjC,UAAU;AACV,OAAO,EAAE,kBAAkB,EAAmB,MAAM,WAAW,CAAA;AAE/D,QAAQ;AACR,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAEhC,wBAAwB;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAEvC,SAAS;AACT,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stratal/testing",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
4
4
  "description": "Testing utilities and mocks for Stratal framework applications",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -66,9 +66,9 @@
66
66
  "msw": "^2.12.10"
67
67
  },
68
68
  "peerDependencies": {
69
- "@stratal/framework": "^0.0.12",
69
+ "@stratal/framework": "^0.0.13",
70
70
  "better-auth": "^1.4.9",
71
- "stratal": "^0.0.12",
71
+ "stratal": "^0.0.13",
72
72
  "vitest": "^4.1.0"
73
73
  },
74
74
  "peerDependenciesMeta": {