@mswjs/interceptors 0.21.0 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/interceptors/XMLHttpRequest/index.js +0 -4
- package/lib/browser/interceptors/XMLHttpRequest/index.mjs +0 -4
- package/lib/node/RemoteHttpInterceptor.js +11 -15
- package/lib/node/RemoteHttpInterceptor.mjs +5 -9
- package/lib/node/{chunk-ZSI7MX3V.mjs → chunk-37CATPNG.mjs} +0 -34
- package/lib/node/{chunk-ZWCZGO3W.mjs → chunk-CYWTKHFI.mjs} +2 -7
- package/lib/node/{chunk-CIN5URNI.mjs → chunk-G6ZTHYZQ.mjs} +1 -1
- package/lib/node/{chunk-HDUJCCWF.js → chunk-GGD5JOGB.js} +9 -14
- package/lib/node/{chunk-JISWS3Y3.mjs → chunk-KZEQH4YW.mjs} +1 -1
- package/lib/node/{chunk-VKKFXSTL.js → chunk-PRX3F52M.js} +31 -24
- package/lib/node/{chunk-KZJG2UW7.js → chunk-Q56TMOP5.js} +2 -2
- package/lib/node/{chunk-6GWWOJ23.js → chunk-SNNL2EXF.js} +3 -3
- package/lib/node/{chunk-FCIAOT7W.mjs → chunk-SWJ33XIS.mjs} +24 -17
- package/lib/node/{chunk-QMIXLBOU.js → chunk-WWHITCCI.js} +2 -36
- package/lib/node/index.js +4 -4
- package/lib/node/index.mjs +3 -3
- package/lib/node/interceptors/ClientRequest/index.js +3 -4
- package/lib/node/interceptors/ClientRequest/index.mjs +2 -3
- package/lib/node/interceptors/XMLHttpRequest/index.js +4 -5
- package/lib/node/interceptors/XMLHttpRequest/index.mjs +3 -4
- package/lib/node/interceptors/fetch/index.js +2 -2
- package/lib/node/interceptors/fetch/index.mjs +1 -1
- package/package.json +17 -11
- package/src/BatchInterceptor.test.ts +8 -7
- package/src/Interceptor.test.ts +6 -5
- package/src/RemoteHttpInterceptor.ts +0 -1
- package/src/interceptors/ClientRequest/NodeClientRequest.test.ts +108 -86
- package/src/interceptors/ClientRequest/NodeClientRequest.ts +40 -22
- package/src/interceptors/ClientRequest/index.test.ts +20 -8
- package/src/interceptors/ClientRequest/utils/cloneIncomingMessage.test.ts +2 -1
- package/src/interceptors/ClientRequest/utils/createRequest.test.ts +1 -0
- package/src/interceptors/ClientRequest/utils/createRequest.ts +0 -1
- package/src/interceptors/ClientRequest/utils/createResponse.test.ts +1 -3
- package/src/interceptors/ClientRequest/utils/createResponse.ts +0 -1
- package/src/interceptors/ClientRequest/utils/getIncomingMessageBody.test.ts +5 -4
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestArgs.test.ts +19 -18
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestEndArgs.test.ts +6 -5
- package/src/interceptors/ClientRequest/utils/normalizeClientRequestWriteArgs.test.ts +5 -4
- package/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts +0 -1
- package/src/interceptors/XMLHttpRequest/utils/concateArrayBuffer.test.ts +1 -3
- package/src/interceptors/XMLHttpRequest/utils/createEvent.test.ts +4 -5
- package/src/interceptors/XMLHttpRequest/utils/createResponse.ts +0 -1
- package/src/interceptors/fetch/index.ts +1 -2
- package/src/utils/AsyncEventEmitter.test.ts +8 -7
- package/src/utils/bufferUtils.test.ts +1 -0
- package/src/utils/cloneObject.test.ts +6 -5
- package/src/utils/getCleanUrl.test.ts +5 -4
- package/src/utils/getUrlByRequestOptions.test.ts +11 -10
- package/src/utils/getUrlByRequestOptions.ts +14 -1
- package/src/utils/isObject.test.ts +4 -3
- package/src/utils/parseJson.test.ts +3 -2
- package/lib/node/chunk-6V3JXLBF.js +0 -6093
- package/lib/node/chunk-NNVTJLQA.mjs +0 -6093
|
@@ -17,6 +17,7 @@ import { createResponse } from './utils/createResponse'
|
|
|
17
17
|
import { createRequest } from './utils/createRequest'
|
|
18
18
|
import { toInteractiveRequest } from '../../utils/toInteractiveRequest'
|
|
19
19
|
import { uuidv4 } from '../../utils/uuid'
|
|
20
|
+
import { DeferredPromise } from '@open-draft/deferred-promise'
|
|
20
21
|
|
|
21
22
|
export type Protocol = 'http' | 'https'
|
|
22
23
|
|
|
@@ -176,6 +177,20 @@ export class NodeClientRequest extends ClientRequest {
|
|
|
176
177
|
}).then(([resolverException, mockedResponse]) => {
|
|
177
178
|
this.log('the listeners promise awaited!')
|
|
178
179
|
|
|
180
|
+
/**
|
|
181
|
+
* @fixme We are in the "end()" method that still executes in parallel
|
|
182
|
+
* to our mocking logic here. This can be solved by migrating to the
|
|
183
|
+
* Proxy-based approach and deferring the passthrough "end()" properly.
|
|
184
|
+
* @see https://github.com/mswjs/interceptors/issues/346
|
|
185
|
+
*/
|
|
186
|
+
if (!this.headersSent) {
|
|
187
|
+
// Forward any request headers that the "request" listener
|
|
188
|
+
// may have modified before proceeding with this request.
|
|
189
|
+
for (const [headerName, headerValue] of capturedRequest.headers) {
|
|
190
|
+
this.setHeader(headerName, headerValue)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
179
194
|
// Halt the request whenever the resolver throws an exception.
|
|
180
195
|
if (resolverException) {
|
|
181
196
|
this.log(
|
|
@@ -188,12 +203,6 @@ export class NodeClientRequest extends ClientRequest {
|
|
|
188
203
|
return this
|
|
189
204
|
}
|
|
190
205
|
|
|
191
|
-
// Forward any request headers that the "request" listener
|
|
192
|
-
// may have modified before proceeding with this request.
|
|
193
|
-
for (const [headerName, headerValue] of capturedRequest.headers) {
|
|
194
|
-
this.setHeader(headerName, headerValue)
|
|
195
|
-
}
|
|
196
|
-
|
|
197
206
|
if (mockedResponse) {
|
|
198
207
|
const responseClone = mockedResponse.clone()
|
|
199
208
|
|
|
@@ -372,11 +381,18 @@ export class NodeClientRequest extends ClientRequest {
|
|
|
372
381
|
}
|
|
373
382
|
this.log('mocked response headers ready:', headers)
|
|
374
383
|
|
|
384
|
+
const isResponseStreamRead = new DeferredPromise<void>()
|
|
385
|
+
|
|
375
386
|
const closeResponseStream = () => {
|
|
387
|
+
this.log('closing response stream...')
|
|
388
|
+
|
|
376
389
|
// Push "null" to indicate that the response body is complete
|
|
377
390
|
// and shouldn't be written to anymore.
|
|
378
391
|
this.response.push(null)
|
|
379
392
|
this.response.complete = true
|
|
393
|
+
|
|
394
|
+
isResponseStreamRead.resolve()
|
|
395
|
+
this.log('closed response stream!')
|
|
380
396
|
}
|
|
381
397
|
|
|
382
398
|
if (body) {
|
|
@@ -400,24 +416,26 @@ export class NodeClientRequest extends ClientRequest {
|
|
|
400
416
|
closeResponseStream()
|
|
401
417
|
}
|
|
402
418
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
419
|
+
isResponseStreamRead.then(() => {
|
|
420
|
+
/**
|
|
421
|
+
* Set the internal "res" property to the mocked "OutgoingMessage"
|
|
422
|
+
* to make the "ClientRequest" instance think there's data received
|
|
423
|
+
* from the socket.
|
|
424
|
+
* @see https://github.com/nodejs/node/blob/9c405f2591f5833d0247ed0fafdcd68c5b14ce7a/lib/_http_client.js#L501
|
|
425
|
+
*/
|
|
426
|
+
// @ts-ignore
|
|
427
|
+
this.res = this.response
|
|
428
|
+
|
|
429
|
+
this.finished = true
|
|
430
|
+
Object.defineProperty(this, 'writableEnded', {
|
|
431
|
+
value: true,
|
|
432
|
+
})
|
|
416
433
|
|
|
417
|
-
|
|
418
|
-
|
|
434
|
+
this.emit('finish')
|
|
435
|
+
this.emit('response', this.response)
|
|
419
436
|
|
|
420
|
-
|
|
437
|
+
this.terminate()
|
|
438
|
+
})
|
|
421
439
|
}
|
|
422
440
|
|
|
423
441
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { it, expect, beforeAll, afterAll } from 'vitest'
|
|
2
|
+
import http from 'http'
|
|
2
3
|
import { HttpServer } from '@open-draft/test-server/http'
|
|
3
|
-
import {
|
|
4
|
+
import { DeferredPromise } from '@open-draft/deferred-promise'
|
|
4
5
|
import { ClientRequestInterceptor } from '.'
|
|
5
6
|
|
|
6
7
|
const httpServer = new HttpServer((app) => {
|
|
@@ -15,8 +16,8 @@ const httpServer = new HttpServer((app) => {
|
|
|
15
16
|
const interceptor = new ClientRequestInterceptor()
|
|
16
17
|
|
|
17
18
|
beforeAll(async () => {
|
|
18
|
-
await httpServer.listen()
|
|
19
19
|
interceptor.apply()
|
|
20
|
+
await httpServer.listen()
|
|
20
21
|
})
|
|
21
22
|
|
|
22
23
|
afterAll(async () => {
|
|
@@ -24,22 +25,33 @@ afterAll(async () => {
|
|
|
24
25
|
await httpServer.close()
|
|
25
26
|
})
|
|
26
27
|
|
|
27
|
-
it('forbids calling "respondWith" multiple times for the same request', (
|
|
28
|
+
it('forbids calling "respondWith" multiple times for the same request', async () => {
|
|
28
29
|
const requestUrl = httpServer.http.url('/')
|
|
29
30
|
|
|
30
|
-
interceptor.on('request', (request)
|
|
31
|
+
interceptor.on('request', function firstRequestListener(request) {
|
|
31
32
|
request.respondWith(new Response())
|
|
32
33
|
})
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
const secondRequestEmitted = new DeferredPromise<void>()
|
|
36
|
+
interceptor.on('request', function secondRequestListener(request) {
|
|
35
37
|
expect(() =>
|
|
36
38
|
request.respondWith(new Response(null, { status: 301 }))
|
|
37
39
|
).toThrow(
|
|
38
40
|
`Failed to respond to "GET ${requestUrl}" request: the "request" event has already been responded to.`
|
|
39
41
|
)
|
|
40
42
|
|
|
41
|
-
|
|
43
|
+
secondRequestEmitted.resolve()
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const request = http.get(requestUrl)
|
|
47
|
+
await secondRequestEmitted
|
|
48
|
+
|
|
49
|
+
const responseReceived = new DeferredPromise<http.IncomingMessage>()
|
|
50
|
+
request.on('response', (response) => {
|
|
51
|
+
responseReceived.resolve(response)
|
|
42
52
|
})
|
|
43
53
|
|
|
44
|
-
|
|
54
|
+
const response = await responseReceived
|
|
55
|
+
expect(response.statusCode).toBe(200)
|
|
56
|
+
expect(response.statusMessage).toBe('')
|
|
45
57
|
})
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { it, expect } from 'vitest'
|
|
1
2
|
import { Socket } from 'net'
|
|
2
3
|
import { IncomingMessage } from 'http'
|
|
3
4
|
import { Stream, Readable, EventEmitter } from 'stream'
|
|
4
5
|
import { cloneIncomingMessage, IS_CLONE } from './cloneIncomingMessage'
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
it('clones a given IncomingMessage', () => {
|
|
7
8
|
const message = new IncomingMessage(new Socket())
|
|
8
9
|
message.statusCode = 200
|
|
9
10
|
message.statusMessage = 'OK'
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { it, expect } from 'vitest'
|
|
1
2
|
import { IncomingMessage } from 'http'
|
|
2
3
|
import { Socket } from 'net'
|
|
3
4
|
import * as zlib from 'zlib'
|
|
4
5
|
import { getIncomingMessageBody } from './getIncomingMessageBody'
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
it('returns utf8 string given a utf8 response body', async () => {
|
|
7
8
|
const utfBuffer = Buffer.from('one')
|
|
8
9
|
const message = new IncomingMessage(new Socket())
|
|
9
10
|
|
|
@@ -14,7 +15,7 @@ test('returns utf8 string given a utf8 response body', async () => {
|
|
|
14
15
|
expect(await pendingResponseBody).toEqual('one')
|
|
15
16
|
})
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
it('returns utf8 string given a gzipped response body', async () => {
|
|
18
19
|
const utfBuffer = zlib.gzipSync(Buffer.from('two'))
|
|
19
20
|
const message = new IncomingMessage(new Socket())
|
|
20
21
|
message.headers = {
|
|
@@ -28,7 +29,7 @@ test('returns utf8 string given a gzipped response body', async () => {
|
|
|
28
29
|
expect(await pendingResponseBody).toEqual('two')
|
|
29
30
|
})
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
it('returns utf8 string given a gzipped response body with incorrect "content-lenght"', async () => {
|
|
32
33
|
const utfBuffer = zlib.gzipSync(Buffer.from('three'))
|
|
33
34
|
const message = new IncomingMessage(new Socket())
|
|
34
35
|
message.headers = {
|
|
@@ -43,7 +44,7 @@ test('returns utf8 string given a gzipped response body with incorrect "content-
|
|
|
43
44
|
expect(await pendingResponseBody).toEqual('three')
|
|
44
45
|
})
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
it('returns empty string given an empty body', async () => {
|
|
47
48
|
const message = new IncomingMessage(new Socket())
|
|
48
49
|
|
|
49
50
|
const pendingResponseBody = getIncomingMessageBody(message)
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
import { it, expect } from 'vitest'
|
|
1
2
|
import { parse } from 'url'
|
|
2
3
|
import { globalAgent as httpGlobalAgent, RequestOptions } from 'http'
|
|
3
4
|
import { Agent as HttpsAgent, globalAgent as httpsGlobalAgent } from 'https'
|
|
4
5
|
import { getUrlByRequestOptions } from '../../../utils/getUrlByRequestOptions'
|
|
5
6
|
import { normalizeClientRequestArgs } from './normalizeClientRequestArgs'
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
it('handles [string, callback] input', () => {
|
|
8
9
|
const [url, options, callback] = normalizeClientRequestArgs(
|
|
9
10
|
'https:',
|
|
10
11
|
'https://mswjs.io/resource',
|
|
@@ -24,7 +25,7 @@ test('handles [string, callback] input', () => {
|
|
|
24
25
|
expect(callback?.name).toEqual('cb')
|
|
25
26
|
})
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
it('handles [string, RequestOptions, callback] input', () => {
|
|
28
29
|
const initialOptions = {
|
|
29
30
|
headers: {
|
|
30
31
|
'Content-Type': 'text/plain',
|
|
@@ -47,7 +48,7 @@ test('handles [string, RequestOptions, callback] input', () => {
|
|
|
47
48
|
expect(callback?.name).toEqual('cb')
|
|
48
49
|
})
|
|
49
50
|
|
|
50
|
-
|
|
51
|
+
it('handles [URL, callback] input', () => {
|
|
51
52
|
const [url, options, callback] = normalizeClientRequestArgs(
|
|
52
53
|
'https:',
|
|
53
54
|
new URL('https://mswjs.io/resource'),
|
|
@@ -67,7 +68,7 @@ test('handles [URL, callback] input', () => {
|
|
|
67
68
|
expect(callback?.name).toEqual('cb')
|
|
68
69
|
})
|
|
69
70
|
|
|
70
|
-
|
|
71
|
+
it('handles [Absolute Legacy URL, callback] input', () => {
|
|
71
72
|
const [url, options, callback] = normalizeClientRequestArgs(
|
|
72
73
|
'https:',
|
|
73
74
|
parse('https://cherry:durian@mswjs.io:12345/resource?apple=banana'),
|
|
@@ -93,7 +94,7 @@ test('handles [Absolute Legacy URL, callback] input', () => {
|
|
|
93
94
|
expect(callback?.name).toEqual('cb')
|
|
94
95
|
})
|
|
95
96
|
|
|
96
|
-
|
|
97
|
+
it('handles [Relative Legacy URL, RequestOptions without path set, callback] input', () => {
|
|
97
98
|
const [url, options, callback] = normalizeClientRequestArgs(
|
|
98
99
|
'http:',
|
|
99
100
|
parse('/resource?apple=banana'),
|
|
@@ -115,7 +116,7 @@ test('handles [Relative Legacy URL, RequestOptions without path set, callback] i
|
|
|
115
116
|
expect(callback?.name).toEqual('cb')
|
|
116
117
|
})
|
|
117
118
|
|
|
118
|
-
|
|
119
|
+
it('handles [Relative Legacy URL, RequestOptions with path set, callback] input', () => {
|
|
119
120
|
const [url, options, callback] = normalizeClientRequestArgs(
|
|
120
121
|
'http:',
|
|
121
122
|
parse('/resource?apple=banana'),
|
|
@@ -137,7 +138,7 @@ test('handles [Relative Legacy URL, RequestOptions with path set, callback] inpu
|
|
|
137
138
|
expect(callback?.name).toEqual('cb')
|
|
138
139
|
})
|
|
139
140
|
|
|
140
|
-
|
|
141
|
+
it('handles [Relative Legacy URL, callback] input', () => {
|
|
141
142
|
const [url, options, callback] = normalizeClientRequestArgs(
|
|
142
143
|
'http:',
|
|
143
144
|
parse('/resource?apple=banana'),
|
|
@@ -157,7 +158,7 @@ test('handles [Relative Legacy URL, callback] input', () => {
|
|
|
157
158
|
expect(callback?.name).toEqual('cb')
|
|
158
159
|
})
|
|
159
160
|
|
|
160
|
-
|
|
161
|
+
it('handles [Relative Legacy URL] input', () => {
|
|
161
162
|
const [url, options, callback] = normalizeClientRequestArgs(
|
|
162
163
|
'http:',
|
|
163
164
|
parse('/resource?apple=banana')
|
|
@@ -176,7 +177,7 @@ test('handles [Relative Legacy URL] input', () => {
|
|
|
176
177
|
expect(callback).toBeUndefined()
|
|
177
178
|
})
|
|
178
179
|
|
|
179
|
-
|
|
180
|
+
it('handles [URL, RequestOptions, callback] input', () => {
|
|
180
181
|
const [url, options, callback] = normalizeClientRequestArgs(
|
|
181
182
|
'https:',
|
|
182
183
|
new URL('https://mswjs.io/resource'),
|
|
@@ -211,7 +212,7 @@ test('handles [URL, RequestOptions, callback] input', () => {
|
|
|
211
212
|
expect(callback?.name).toEqual('cb')
|
|
212
213
|
})
|
|
213
214
|
|
|
214
|
-
|
|
215
|
+
it('handles [RequestOptions, callback] input', () => {
|
|
215
216
|
const initialOptions = {
|
|
216
217
|
method: 'POST',
|
|
217
218
|
protocol: 'https:',
|
|
@@ -241,7 +242,7 @@ test('handles [RequestOptions, callback] input', () => {
|
|
|
241
242
|
expect(callback?.name).toEqual('cb')
|
|
242
243
|
})
|
|
243
244
|
|
|
244
|
-
|
|
245
|
+
it('handles [Empty RequestOptions, callback] input', () => {
|
|
245
246
|
const [_, options, callback] = normalizeClientRequestArgs(
|
|
246
247
|
'https:',
|
|
247
248
|
{},
|
|
@@ -257,7 +258,7 @@ test('handles [Empty RequestOptions, callback] input', () => {
|
|
|
257
258
|
/**
|
|
258
259
|
* @see https://github.com/mswjs/interceptors/issues/19
|
|
259
260
|
*/
|
|
260
|
-
|
|
261
|
+
it('handles [PartialRequestOptions, callback] input', () => {
|
|
261
262
|
const initialOptions = {
|
|
262
263
|
method: 'GET',
|
|
263
264
|
port: '50176',
|
|
@@ -291,7 +292,7 @@ test('handles [PartialRequestOptions, callback] input', () => {
|
|
|
291
292
|
expect(callback?.name).toEqual('cb')
|
|
292
293
|
})
|
|
293
294
|
|
|
294
|
-
|
|
295
|
+
it('sets fallback Agent based on the URL protocol', () => {
|
|
295
296
|
const [url, options] = normalizeClientRequestArgs(
|
|
296
297
|
'https:',
|
|
297
298
|
'https://github.com'
|
|
@@ -303,7 +304,7 @@ test('sets fallback Agent based on the URL protocol', () => {
|
|
|
303
304
|
expect(agent).toHaveProperty('protocol', url.protocol)
|
|
304
305
|
})
|
|
305
306
|
|
|
306
|
-
|
|
307
|
+
it('does not set any fallback Agent given "agent: false" option', () => {
|
|
307
308
|
const [, options] = normalizeClientRequestArgs(
|
|
308
309
|
'https:',
|
|
309
310
|
'https://github.com',
|
|
@@ -313,7 +314,7 @@ test('does not set any fallback Agent given "agent: false" option', () => {
|
|
|
313
314
|
expect(options.agent).toEqual(false)
|
|
314
315
|
})
|
|
315
316
|
|
|
316
|
-
|
|
317
|
+
it('sets the default Agent for HTTP request', () => {
|
|
317
318
|
const [, options] = normalizeClientRequestArgs(
|
|
318
319
|
'http:',
|
|
319
320
|
'http://github.com',
|
|
@@ -323,7 +324,7 @@ test('sets the default Agent for HTTP request', () => {
|
|
|
323
324
|
expect(options._defaultAgent).toEqual(httpGlobalAgent)
|
|
324
325
|
})
|
|
325
326
|
|
|
326
|
-
|
|
327
|
+
it('sets the default Agent for HTTPS request', () => {
|
|
327
328
|
const [, options] = normalizeClientRequestArgs(
|
|
328
329
|
'https:',
|
|
329
330
|
'https://github.com',
|
|
@@ -333,7 +334,7 @@ test('sets the default Agent for HTTPS request', () => {
|
|
|
333
334
|
expect(options._defaultAgent).toEqual(httpsGlobalAgent)
|
|
334
335
|
})
|
|
335
336
|
|
|
336
|
-
|
|
337
|
+
it('preserves a custom default Agent when set', () => {
|
|
337
338
|
const [, options] = normalizeClientRequestArgs(
|
|
338
339
|
'https:',
|
|
339
340
|
'https://github.com',
|
|
@@ -348,7 +349,7 @@ test('preserves a custom default Agent when set', () => {
|
|
|
348
349
|
expect(options._defaultAgent).toEqual(httpGlobalAgent)
|
|
349
350
|
})
|
|
350
351
|
|
|
351
|
-
|
|
352
|
+
it('merges URL-based RequestOptions with the custom RequestOptions', () => {
|
|
352
353
|
const [url, options] = normalizeClientRequestArgs(
|
|
353
354
|
'https:',
|
|
354
355
|
'https://github.com/graphql',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { it, expect } from 'vitest'
|
|
1
2
|
import { normalizeClientRequestEndArgs } from './normalizeClientRequestEndArgs'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
it('returns [null, null, cb] given only the callback', () => {
|
|
4
5
|
const callback = () => {}
|
|
5
6
|
expect(normalizeClientRequestEndArgs(callback)).toEqual([
|
|
6
7
|
null,
|
|
@@ -9,11 +10,11 @@ test('returns [null, null, cb] given only the callback', () => {
|
|
|
9
10
|
])
|
|
10
11
|
})
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
it('returns [chunk, null, null] given only the chunk', () => {
|
|
13
14
|
expect(normalizeClientRequestEndArgs('chunk')).toEqual(['chunk', null, null])
|
|
14
15
|
})
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
it('returns [chunk, cb] given the chunk and the callback', () => {
|
|
17
18
|
const callback = () => {}
|
|
18
19
|
expect(normalizeClientRequestEndArgs('chunk', callback)).toEqual([
|
|
19
20
|
'chunk',
|
|
@@ -22,7 +23,7 @@ test('returns [chunk, cb] given the chunk and the callback', () => {
|
|
|
22
23
|
])
|
|
23
24
|
})
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
it('returns [chunk, encoding] given the chunk with the encoding', () => {
|
|
26
27
|
expect(normalizeClientRequestEndArgs('chunk', 'utf8')).toEqual([
|
|
27
28
|
'chunk',
|
|
28
29
|
'utf8',
|
|
@@ -30,7 +31,7 @@ test('returns [chunk, encoding] given the chunk with the encoding', () => {
|
|
|
30
31
|
])
|
|
31
32
|
})
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
it('returns [chunk, encoding, cb] given all three arguments', () => {
|
|
34
35
|
const callback = () => {}
|
|
35
36
|
expect(normalizeClientRequestEndArgs('chunk', 'utf8', callback)).toEqual([
|
|
36
37
|
'chunk',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { it, expect } from 'vitest'
|
|
1
2
|
import { normalizeClientRequestWriteArgs } from './normalizeClientRequestWriteArgs'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
it('returns a triplet of null given no chunk, encoding, or callback', () => {
|
|
4
5
|
expect(
|
|
5
6
|
normalizeClientRequestWriteArgs([
|
|
6
7
|
// @ts-ignore
|
|
@@ -11,7 +12,7 @@ test('returns a triplet of null given no chunk, encoding, or callback', () => {
|
|
|
11
12
|
).toEqual([undefined, undefined, undefined])
|
|
12
13
|
})
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
it('returns [chunk, null, null] given only a chunk', () => {
|
|
15
16
|
expect(normalizeClientRequestWriteArgs(['chunk', undefined])).toEqual([
|
|
16
17
|
'chunk',
|
|
17
18
|
undefined,
|
|
@@ -19,7 +20,7 @@ test('returns [chunk, null, null] given only a chunk', () => {
|
|
|
19
20
|
])
|
|
20
21
|
})
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
it('returns [chunk, encoding] given only chunk and encoding', () => {
|
|
23
24
|
expect(normalizeClientRequestWriteArgs(['chunk', 'utf8'])).toEqual([
|
|
24
25
|
'chunk',
|
|
25
26
|
'utf8',
|
|
@@ -27,7 +28,7 @@ test('returns [chunk, encoding] given only chunk and encoding', () => {
|
|
|
27
28
|
])
|
|
28
29
|
})
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
it('returns [chunk, encoding, cb] given all three arguments', () => {
|
|
31
32
|
const callbackFn = () => {}
|
|
32
33
|
expect(
|
|
33
34
|
normalizeClientRequestWriteArgs(['chunk', 'utf8', callbackFn])
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*/
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { it, expect } from 'vitest'
|
|
4
3
|
import { createEvent } from './createEvent'
|
|
5
4
|
import { EventPolyfill } from '../polyfills/EventPolyfill'
|
|
6
5
|
|
|
7
6
|
const request = new XMLHttpRequest()
|
|
8
7
|
request.open('POST', '/user')
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
it('returns an EventPolyfill instance with the given target set', () => {
|
|
11
10
|
const event = createEvent(request, 'my-event')
|
|
12
11
|
const target = event.target as XMLHttpRequest
|
|
13
12
|
|
|
@@ -15,7 +14,7 @@ test('returns an EventPolyfill instance with the given target set', () => {
|
|
|
15
14
|
expect(target).toBeInstanceOf(XMLHttpRequest)
|
|
16
15
|
})
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
it('returns the ProgressEvent instance', () => {
|
|
19
18
|
const event = createEvent(request, 'load', {
|
|
20
19
|
loaded: 100,
|
|
21
20
|
total: 500,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { invariant } from 'outvariant'
|
|
2
|
-
import type { Response as ResponsePolyfill } from '@remix-run/web-fetch'
|
|
3
2
|
import { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'
|
|
4
3
|
import { Interceptor } from '../../Interceptor'
|
|
5
4
|
import { uuidv4 } from '../../utils/uuid'
|
|
@@ -81,7 +80,7 @@ export class FetchInterceptor extends Interceptor<HttpRequestEventMap> {
|
|
|
81
80
|
this.log('no mocked response received!')
|
|
82
81
|
|
|
83
82
|
return pureFetch(request).then((response) => {
|
|
84
|
-
const responseClone = response.clone()
|
|
83
|
+
const responseClone = response.clone()
|
|
85
84
|
this.log('original fetch performed', responseClone)
|
|
86
85
|
|
|
87
86
|
this.emitter.emit(
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import { vi, it, expect, afterEach } from 'vitest'
|
|
1
2
|
import { AsyncEventEmitter } from './AsyncEventEmitter'
|
|
2
3
|
import { sleep } from '../../test/helpers'
|
|
3
4
|
|
|
4
5
|
afterEach(() => {
|
|
5
|
-
|
|
6
|
+
vi.useRealTimers()
|
|
6
7
|
})
|
|
7
8
|
|
|
8
9
|
it('emits and listens to events', () => {
|
|
9
10
|
const emitter = new AsyncEventEmitter<{ hello: [string] }>()
|
|
10
|
-
const listener =
|
|
11
|
+
const listener = vi.fn()
|
|
11
12
|
emitter.on('hello', listener)
|
|
12
13
|
emitter.emit('hello', 'John')
|
|
13
14
|
|
|
@@ -19,10 +20,10 @@ it('resolves "untilIdle" when all the event listeners are done', async () => {
|
|
|
19
20
|
const emitter = new AsyncEventEmitter<{ speak: [string] }>()
|
|
20
21
|
|
|
21
22
|
const results: string[] = []
|
|
22
|
-
const firstListener =
|
|
23
|
+
const firstListener = vi.fn(() => results.push('first'))
|
|
23
24
|
emitter.on('speak', firstListener)
|
|
24
25
|
|
|
25
|
-
const secondListener =
|
|
26
|
+
const secondListener = vi.fn(async () => {
|
|
26
27
|
await sleep(150)
|
|
27
28
|
results.push('second')
|
|
28
29
|
})
|
|
@@ -43,7 +44,7 @@ it('resolves "untilIdle" only for the relevant listeners', async () => {
|
|
|
43
44
|
const emitter = new AsyncEventEmitter<{ signal: [number] }>()
|
|
44
45
|
|
|
45
46
|
const results: number[] = []
|
|
46
|
-
const listener =
|
|
47
|
+
const listener = vi.fn(async (code: number) => {
|
|
47
48
|
if (code !== 1) {
|
|
48
49
|
// Delay listener based on the signal code.
|
|
49
50
|
await sleep(150)
|
|
@@ -79,7 +80,7 @@ it('propagates listener exceptions to "untilIdle" promise', async () => {
|
|
|
79
80
|
const emitter = new AsyncEventEmitter<{ ping: never }>()
|
|
80
81
|
|
|
81
82
|
const error = new Error('oops')
|
|
82
|
-
const listener =
|
|
83
|
+
const listener = vi.fn(() => {
|
|
83
84
|
throw error
|
|
84
85
|
})
|
|
85
86
|
emitter.on('ping', listener)
|
|
@@ -91,7 +92,7 @@ it('propagates listener exceptions to "untilIdle" promise', async () => {
|
|
|
91
92
|
it('does not emit events once the emitter was deactivated', () => {
|
|
92
93
|
const emitter = new AsyncEventEmitter<{ ping: never }>()
|
|
93
94
|
|
|
94
|
-
const listener =
|
|
95
|
+
const listener = vi.fn()
|
|
95
96
|
emitter.on('ping', listener)
|
|
96
97
|
emitter.deactivate()
|
|
97
98
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { it, expect } from 'vitest'
|
|
1
2
|
import { cloneObject } from './cloneObject'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
it('clones a shallow object', () => {
|
|
4
5
|
const original = { a: 1, b: 2, c: [1, 2, 3] }
|
|
5
6
|
const clone = cloneObject(original)
|
|
6
7
|
|
|
@@ -18,7 +19,7 @@ test('clones a shallow object', () => {
|
|
|
18
19
|
expect(original).toHaveProperty('c', [1, 2, 3])
|
|
19
20
|
})
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
it('clones a nested object', () => {
|
|
22
23
|
const original = { a: { b: 1 }, c: { d: { e: 2 } } }
|
|
23
24
|
const clone = cloneObject(original)
|
|
24
25
|
|
|
@@ -33,7 +34,7 @@ test('clones a nested object', () => {
|
|
|
33
34
|
expect(original).toHaveProperty(['c', 'd', 'e'], 2)
|
|
34
35
|
})
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
it('clones a class instance', () => {
|
|
37
38
|
class Car {
|
|
38
39
|
public manufacturer: string
|
|
39
40
|
constructor() {
|
|
@@ -53,7 +54,7 @@ test('clones a class instance', () => {
|
|
|
53
54
|
expect(clone.getManufacturer()).toEqual('Audi')
|
|
54
55
|
})
|
|
55
56
|
|
|
56
|
-
|
|
57
|
+
it('ignores nested class instances', () => {
|
|
57
58
|
class Car {
|
|
58
59
|
name: string
|
|
59
60
|
constructor(name: string) {
|
|
@@ -81,7 +82,7 @@ test('ignores nested class instances', () => {
|
|
|
81
82
|
expect(original.car.getName()).toEqual('Audi')
|
|
82
83
|
})
|
|
83
84
|
|
|
84
|
-
|
|
85
|
+
it('clones an object with null prototype', () => {
|
|
85
86
|
const original = {
|
|
86
87
|
key: Object.create(null),
|
|
87
88
|
}
|