msw 2.1.6 → 2.2.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/cli/init.js +9 -13
- package/lib/browser/index.js +29 -24
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/index.mjs +29 -24
- package/lib/browser/index.mjs.map +1 -1
- package/lib/core/HttpResponse.js +14 -1
- package/lib/core/HttpResponse.js.map +1 -1
- package/lib/core/HttpResponse.mjs +14 -1
- package/lib/core/HttpResponse.mjs.map +1 -1
- package/lib/core/SetupApi.d.mts +15 -3
- package/lib/core/SetupApi.d.ts +15 -3
- package/lib/core/SetupApi.js +26 -8
- package/lib/core/SetupApi.js.map +1 -1
- package/lib/core/SetupApi.mjs +26 -8
- package/lib/core/SetupApi.mjs.map +1 -1
- package/lib/iife/index.js +65 -33
- package/lib/iife/index.js.map +1 -1
- package/lib/mockServiceWorker.js +1 -1
- package/lib/native/index.d.mts +10 -5
- package/lib/native/index.d.ts +10 -5
- package/lib/native/index.js +12 -8
- package/lib/native/index.js.map +1 -1
- package/lib/native/index.mjs +12 -8
- package/lib/native/index.mjs.map +1 -1
- package/lib/node/index.d.mts +26 -4
- package/lib/node/index.d.ts +26 -4
- package/lib/node/index.js +62 -13
- package/lib/node/index.js.map +1 -1
- package/lib/node/index.mjs +62 -13
- package/lib/node/index.mjs.map +1 -1
- package/package.json +16 -8
- package/src/browser/setupWorker/glossary.ts +1 -1
- package/src/browser/setupWorker/setupWorker.ts +3 -11
- package/src/browser/setupWorker/start/createFallbackRequestListener.ts +1 -1
- package/src/browser/setupWorker/start/createRequestListener.ts +1 -1
- package/src/browser/setupWorker/start/createResponseListener.ts +13 -0
- package/src/core/HttpResponse.test.ts +34 -3
- package/src/core/HttpResponse.ts +24 -1
- package/src/core/SetupApi.ts +33 -9
- package/src/native/index.ts +8 -4
- package/src/node/SetupServerApi.ts +64 -95
- package/src/node/SetupServerCommonApi.ts +116 -0
- package/src/node/glossary.ts +17 -3
- package/src/node/setupServer.ts +3 -10
|
@@ -1,113 +1,82 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
} from '
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { RequestHandler } from '~/core/handlers/RequestHandler'
|
|
10
|
-
import { LifeCycleEventsMap, SharedOptions } from '~/core/sharedOptions'
|
|
11
|
-
import { RequiredDeep } from '~/core/typeUtils'
|
|
12
|
-
import { handleRequest } from '~/core/utils/handleRequest'
|
|
13
|
-
import { devUtils } from '~/core/utils/internal/devUtils'
|
|
14
|
-
import { mergeRight } from '~/core/utils/internal/mergeRight'
|
|
15
|
-
import { SetupServer } from './glossary'
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
2
|
+
import { ClientRequestInterceptor } from '@mswjs/interceptors/ClientRequest'
|
|
3
|
+
import { XMLHttpRequestInterceptor } from '@mswjs/interceptors/XMLHttpRequest'
|
|
4
|
+
import { FetchInterceptor } from '@mswjs/interceptors/fetch'
|
|
5
|
+
import { HandlersController } from '~/core/SetupApi'
|
|
6
|
+
import type { RequestHandler } from '~/core/handlers/RequestHandler'
|
|
7
|
+
import type { SetupServer } from './glossary'
|
|
8
|
+
import { SetupServerCommonApi } from './SetupServerCommonApi'
|
|
16
9
|
|
|
17
|
-
const
|
|
18
|
-
onUnhandledRequest: 'warn',
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export class SetupServerApi
|
|
22
|
-
extends SetupApi<LifeCycleEventsMap>
|
|
23
|
-
implements SetupServer
|
|
24
|
-
{
|
|
25
|
-
protected readonly interceptor: BatchInterceptor<
|
|
26
|
-
Array<Interceptor<HttpRequestEventMap>>,
|
|
27
|
-
HttpRequestEventMap
|
|
28
|
-
>
|
|
29
|
-
private resolvedOptions: RequiredDeep<SharedOptions>
|
|
10
|
+
const store = new AsyncLocalStorage<RequestHandlersContext>()
|
|
30
11
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
...handlers: Array<RequestHandler>
|
|
36
|
-
) {
|
|
37
|
-
super(...handlers)
|
|
12
|
+
type RequestHandlersContext = {
|
|
13
|
+
initialHandlers: Array<RequestHandler>
|
|
14
|
+
handlers: Array<RequestHandler>
|
|
15
|
+
}
|
|
38
16
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
17
|
+
/**
|
|
18
|
+
* A handlers controller that utilizes `AsyncLocalStorage` in Node.js
|
|
19
|
+
* to prevent the request handlers list from being a shared state
|
|
20
|
+
* across mutliple tests.
|
|
21
|
+
*/
|
|
22
|
+
class AsyncHandlersController implements HandlersController {
|
|
23
|
+
private rootContext: RequestHandlersContext
|
|
44
24
|
|
|
45
|
-
|
|
25
|
+
constructor(initialHandlers: Array<RequestHandler>) {
|
|
26
|
+
this.rootContext = { initialHandlers, handlers: [] }
|
|
46
27
|
}
|
|
47
28
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
private init(): void {
|
|
52
|
-
this.interceptor.on('request', async ({ request, requestId }) => {
|
|
53
|
-
const response = await handleRequest(
|
|
54
|
-
request,
|
|
55
|
-
requestId,
|
|
56
|
-
this.currentHandlers,
|
|
57
|
-
this.resolvedOptions,
|
|
58
|
-
this.emitter,
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
if (response) {
|
|
62
|
-
request.respondWith(response)
|
|
63
|
-
}
|
|
29
|
+
get context(): RequestHandlersContext {
|
|
30
|
+
return store.getStore() || this.rootContext
|
|
31
|
+
}
|
|
64
32
|
|
|
65
|
-
|
|
66
|
-
|
|
33
|
+
public prepend(runtimeHandlers: Array<RequestHandler>) {
|
|
34
|
+
this.context.handlers.unshift(...runtimeHandlers)
|
|
35
|
+
}
|
|
67
36
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
{
|
|
74
|
-
response,
|
|
75
|
-
request,
|
|
76
|
-
requestId,
|
|
77
|
-
},
|
|
78
|
-
)
|
|
79
|
-
},
|
|
80
|
-
)
|
|
37
|
+
public reset(nextHandlers: Array<RequestHandler>) {
|
|
38
|
+
const context = this.context
|
|
39
|
+
context.handlers = []
|
|
40
|
+
context.initialHandlers =
|
|
41
|
+
nextHandlers.length > 0 ? nextHandlers : context.initialHandlers
|
|
81
42
|
}
|
|
82
43
|
|
|
83
|
-
public
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
44
|
+
public currentHandlers(): Array<RequestHandler> {
|
|
45
|
+
const { initialHandlers, handlers } = this.context
|
|
46
|
+
return handlers.concat(initialHandlers)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
88
49
|
|
|
89
|
-
|
|
90
|
-
|
|
50
|
+
export class SetupServerApi
|
|
51
|
+
extends SetupServerCommonApi
|
|
52
|
+
implements SetupServer
|
|
53
|
+
{
|
|
54
|
+
constructor(handlers: Array<RequestHandler>) {
|
|
55
|
+
super(
|
|
56
|
+
[ClientRequestInterceptor, XMLHttpRequestInterceptor, FetchInterceptor],
|
|
57
|
+
handlers,
|
|
58
|
+
)
|
|
91
59
|
|
|
92
|
-
this.
|
|
93
|
-
|
|
94
|
-
})
|
|
60
|
+
this.handlersController = new AsyncHandlersController(handlers)
|
|
61
|
+
}
|
|
95
62
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
63
|
+
public boundary<Fn extends (...args: Array<any>) => unknown>(
|
|
64
|
+
callback: Fn,
|
|
65
|
+
): (...args: Parameters<Fn>) => ReturnType<Fn> {
|
|
66
|
+
return (...args: Parameters<Fn>): ReturnType<Fn> => {
|
|
67
|
+
return store.run<any, any>(
|
|
68
|
+
{
|
|
69
|
+
initialHandlers: this.handlersController.currentHandlers(),
|
|
70
|
+
handlers: [],
|
|
71
|
+
},
|
|
72
|
+
callback,
|
|
73
|
+
...args,
|
|
74
|
+
)
|
|
75
|
+
}
|
|
108
76
|
}
|
|
109
77
|
|
|
110
78
|
public close(): void {
|
|
111
|
-
|
|
79
|
+
super.close()
|
|
80
|
+
store.disable()
|
|
112
81
|
}
|
|
113
82
|
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @note This API is extended by both "msw/node" and "msw/native"
|
|
3
|
+
* so be minding about the things you import!
|
|
4
|
+
*/
|
|
5
|
+
import type { RequiredDeep } from 'type-fest'
|
|
6
|
+
import { invariant } from 'outvariant'
|
|
7
|
+
import {
|
|
8
|
+
BatchInterceptor,
|
|
9
|
+
InterceptorReadyState,
|
|
10
|
+
type HttpRequestEventMap,
|
|
11
|
+
type Interceptor,
|
|
12
|
+
} from '@mswjs/interceptors'
|
|
13
|
+
import type { LifeCycleEventsMap, SharedOptions } from '~/core/sharedOptions'
|
|
14
|
+
import { SetupApi } from '~/core/SetupApi'
|
|
15
|
+
import { handleRequest } from '~/core/utils/handleRequest'
|
|
16
|
+
import type { RequestHandler } from '~/core/handlers/RequestHandler'
|
|
17
|
+
import { mergeRight } from '~/core/utils/internal/mergeRight'
|
|
18
|
+
import { devUtils } from '~/core/utils/internal/devUtils'
|
|
19
|
+
import type { SetupServerCommon } from './glossary'
|
|
20
|
+
|
|
21
|
+
export const DEFAULT_LISTEN_OPTIONS: RequiredDeep<SharedOptions> = {
|
|
22
|
+
onUnhandledRequest: 'warn',
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class SetupServerCommonApi
|
|
26
|
+
extends SetupApi<LifeCycleEventsMap>
|
|
27
|
+
implements SetupServerCommon
|
|
28
|
+
{
|
|
29
|
+
protected readonly interceptor: BatchInterceptor<
|
|
30
|
+
Array<Interceptor<HttpRequestEventMap>>,
|
|
31
|
+
HttpRequestEventMap
|
|
32
|
+
>
|
|
33
|
+
private resolvedOptions: RequiredDeep<SharedOptions>
|
|
34
|
+
|
|
35
|
+
constructor(
|
|
36
|
+
interceptors: Array<{ new (): Interceptor<HttpRequestEventMap> }>,
|
|
37
|
+
handlers: Array<RequestHandler>,
|
|
38
|
+
) {
|
|
39
|
+
super(...handlers)
|
|
40
|
+
|
|
41
|
+
this.interceptor = new BatchInterceptor({
|
|
42
|
+
name: 'setup-server',
|
|
43
|
+
interceptors: interceptors.map((Interceptor) => new Interceptor()),
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
this.resolvedOptions = {} as RequiredDeep<SharedOptions>
|
|
47
|
+
|
|
48
|
+
this.init()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Subscribe to all requests that are using the interceptor object
|
|
53
|
+
*/
|
|
54
|
+
private init(): void {
|
|
55
|
+
this.interceptor.on('request', async ({ request, requestId }) => {
|
|
56
|
+
const response = await handleRequest(
|
|
57
|
+
request,
|
|
58
|
+
requestId,
|
|
59
|
+
this.handlersController.currentHandlers(),
|
|
60
|
+
this.resolvedOptions,
|
|
61
|
+
this.emitter,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
if (response) {
|
|
65
|
+
request.respondWith(response)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
this.interceptor.on(
|
|
72
|
+
'response',
|
|
73
|
+
({ response, isMockedResponse, request, requestId }) => {
|
|
74
|
+
this.emitter.emit(
|
|
75
|
+
isMockedResponse ? 'response:mocked' : 'response:bypass',
|
|
76
|
+
{
|
|
77
|
+
response,
|
|
78
|
+
request,
|
|
79
|
+
requestId,
|
|
80
|
+
},
|
|
81
|
+
)
|
|
82
|
+
},
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public listen(options: Partial<SharedOptions> = {}): void {
|
|
87
|
+
this.resolvedOptions = mergeRight(
|
|
88
|
+
DEFAULT_LISTEN_OPTIONS,
|
|
89
|
+
options,
|
|
90
|
+
) as RequiredDeep<SharedOptions>
|
|
91
|
+
|
|
92
|
+
// Apply the interceptor when starting the server.
|
|
93
|
+
this.interceptor.apply()
|
|
94
|
+
|
|
95
|
+
this.subscriptions.push(() => {
|
|
96
|
+
this.interceptor.dispose()
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
// Assert that the interceptor has been applied successfully.
|
|
100
|
+
// Also guards us from forgetting to call "interceptor.apply()"
|
|
101
|
+
// as a part of the "listen" method.
|
|
102
|
+
invariant(
|
|
103
|
+
[InterceptorReadyState.APPLYING, InterceptorReadyState.APPLIED].includes(
|
|
104
|
+
this.interceptor.readyState,
|
|
105
|
+
),
|
|
106
|
+
devUtils.formatMessage(
|
|
107
|
+
'Failed to start "setupServer": the interceptor failed to apply. This is likely an issue with the library and you should report it at "%s".',
|
|
108
|
+
),
|
|
109
|
+
'https://github.com/mswjs/msw/issues/new/choose',
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
public close(): void {
|
|
114
|
+
this.dispose()
|
|
115
|
+
}
|
|
116
|
+
}
|
package/src/node/glossary.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import type { PartialDeep } from 'type-fest'
|
|
2
|
-
import {
|
|
2
|
+
import type {
|
|
3
3
|
RequestHandler,
|
|
4
4
|
RequestHandlerDefaultInfo,
|
|
5
5
|
} from '~/core/handlers/RequestHandler'
|
|
6
|
-
import {
|
|
6
|
+
import type {
|
|
7
7
|
LifeCycleEventEmitter,
|
|
8
8
|
LifeCycleEventsMap,
|
|
9
9
|
SharedOptions,
|
|
10
10
|
} from '~/core/sharedOptions'
|
|
11
11
|
|
|
12
|
-
export interface
|
|
12
|
+
export interface SetupServerCommon {
|
|
13
13
|
/**
|
|
14
14
|
* Starts requests interception based on the previously provided request handlers.
|
|
15
15
|
*
|
|
@@ -60,3 +60,17 @@ export interface SetupServer {
|
|
|
60
60
|
*/
|
|
61
61
|
events: LifeCycleEventEmitter<LifeCycleEventsMap>
|
|
62
62
|
}
|
|
63
|
+
|
|
64
|
+
export interface SetupServer extends SetupServerCommon {
|
|
65
|
+
/**
|
|
66
|
+
* Wraps the given function in a boundary. Any changes to the
|
|
67
|
+
* network behavior (e.g. adding runtime request handlers via
|
|
68
|
+
* `server.use()`) will be scoped to this boundary only.
|
|
69
|
+
* @param callback A function to run (e.g. a test)
|
|
70
|
+
*
|
|
71
|
+
* @see {@link https://mswjs.io/docs/api/setup-server/boundary `server.boundary()` API reference}
|
|
72
|
+
*/
|
|
73
|
+
boundary<Fn extends (...args: Array<any>) => unknown>(
|
|
74
|
+
callback: Fn,
|
|
75
|
+
): (...args: Parameters<Fn>) => ReturnType<Fn>
|
|
76
|
+
}
|
package/src/node/setupServer.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { XMLHttpRequestInterceptor } from '@mswjs/interceptors/XMLHttpRequest'
|
|
3
|
-
import { FetchInterceptor } from '@mswjs/interceptors/fetch'
|
|
4
|
-
import { RequestHandler } from '~/core/handlers/RequestHandler'
|
|
1
|
+
import type { RequestHandler } from '~/core/handlers/RequestHandler'
|
|
5
2
|
import { SetupServerApi } from './SetupServerApi'
|
|
6
|
-
import { SetupServer } from './glossary'
|
|
7
3
|
|
|
8
4
|
/**
|
|
9
5
|
* Sets up a requests interception in Node.js with the given request handlers.
|
|
@@ -13,9 +9,6 @@ import { SetupServer } from './glossary'
|
|
|
13
9
|
*/
|
|
14
10
|
export const setupServer = (
|
|
15
11
|
...handlers: Array<RequestHandler>
|
|
16
|
-
):
|
|
17
|
-
return new SetupServerApi(
|
|
18
|
-
[ClientRequestInterceptor, XMLHttpRequestInterceptor, FetchInterceptor],
|
|
19
|
-
...handlers,
|
|
20
|
-
)
|
|
12
|
+
): SetupServerApi => {
|
|
13
|
+
return new SetupServerApi(handlers)
|
|
21
14
|
}
|