msw-fetch-mock 0.1.2 → 0.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/README.md +27 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/mock-server.d.ts +16 -1
- package/dist/mock-server.d.ts.map +1 -1
- package/dist/mock-server.js +30 -2
- package/docs/api.md +36 -3
- package/docs/cloudflare-migration.md +8 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ npm install -D msw-fetch-mock msw
|
|
|
23
23
|
```typescript
|
|
24
24
|
import { fetchMock } from 'msw-fetch-mock';
|
|
25
25
|
|
|
26
|
-
beforeAll(() => fetchMock.activate());
|
|
26
|
+
beforeAll(() => fetchMock.activate({ onUnhandledRequest: 'error' }));
|
|
27
27
|
afterAll(() => fetchMock.deactivate());
|
|
28
28
|
afterEach(() => fetchMock.assertNoPendingInterceptors());
|
|
29
29
|
|
|
@@ -62,6 +62,32 @@ afterEach(() => {
|
|
|
62
62
|
|
|
63
63
|
> **Note:** Only one MSW server can be active at a time. If another server is already listening, standalone `activate()` will throw an error guiding you to use `new FetchMock(server)` instead.
|
|
64
64
|
|
|
65
|
+
## Unhandled Requests
|
|
66
|
+
|
|
67
|
+
By default `activate()` uses `'error'` mode — unmatched requests cause `fetch()` to reject. This includes requests to **consumed** interceptors (once a one-shot interceptor has been used, its handler is removed from MSW).
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
// Reject unmatched requests (default)
|
|
71
|
+
fetchMock.activate();
|
|
72
|
+
fetchMock.activate({ onUnhandledRequest: 'error' });
|
|
73
|
+
|
|
74
|
+
// Log a warning but allow passthrough
|
|
75
|
+
fetchMock.activate({ onUnhandledRequest: 'warn' });
|
|
76
|
+
|
|
77
|
+
// Silently allow passthrough
|
|
78
|
+
fetchMock.activate({ onUnhandledRequest: 'bypass' });
|
|
79
|
+
|
|
80
|
+
// Custom callback
|
|
81
|
+
fetchMock.activate({
|
|
82
|
+
onUnhandledRequest: (request, print) => {
|
|
83
|
+
if (request.url.includes('/health')) return; // ignore
|
|
84
|
+
print.error(); // block everything else
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
> `enableNetConnect()` takes priority over `onUnhandledRequest` — allowed hosts always pass through.
|
|
90
|
+
|
|
65
91
|
## API Overview
|
|
66
92
|
|
|
67
93
|
### `fetchMock` (singleton)
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { FetchMock } from './mock-server';
|
|
|
2
2
|
export { createFetchMock, FetchMock } from './mock-server';
|
|
3
3
|
/** Pre-built singleton for quick standalone use (Cloudflare migration compatible). */
|
|
4
4
|
export declare const fetchMock: FetchMock;
|
|
5
|
-
export type { InterceptOptions, MockPool, MockInterceptor, MockReplyChain, ReplyOptions, PendingInterceptor, } from './mock-server';
|
|
5
|
+
export type { ActivateOptions, OnUnhandledRequest, InterceptOptions, MockPool, MockInterceptor, MockReplyChain, ReplyOptions, PendingInterceptor, } from './mock-server';
|
|
6
6
|
export { MockCallHistory, MockCallHistoryLog } from './mock-call-history';
|
|
7
7
|
export type { MockCallHistoryLogData, CallHistoryFilterCriteria } from './mock-call-history';
|
|
8
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE3D,sFAAsF;AACtF,eAAO,MAAM,SAAS,WAAkB,CAAC;AACzC,YAAY,EACV,gBAAgB,EAChB,QAAQ,EACR,eAAe,EACf,cAAc,EACd,YAAY,EACZ,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC1E,YAAY,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE3D,sFAAsF;AACtF,eAAO,MAAM,SAAS,WAAkB,CAAC;AACzC,YAAY,EACV,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,EACR,eAAe,EACf,cAAc,EACd,YAAY,EACZ,kBAAkB,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC1E,YAAY,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/mock-server.d.ts
CHANGED
|
@@ -45,18 +45,33 @@ export interface PendingInterceptor {
|
|
|
45
45
|
timesInvoked: number;
|
|
46
46
|
persist: boolean;
|
|
47
47
|
}
|
|
48
|
+
type PrintAPI = {
|
|
49
|
+
warning(): void;
|
|
50
|
+
error(): void;
|
|
51
|
+
};
|
|
52
|
+
type OnUnhandledRequestCallback = (request: Request, print: PrintAPI) => void;
|
|
53
|
+
export type OnUnhandledRequest = 'bypass' | 'warn' | 'error' | OnUnhandledRequestCallback;
|
|
54
|
+
export interface ActivateOptions {
|
|
55
|
+
onUnhandledRequest?: OnUnhandledRequest;
|
|
56
|
+
}
|
|
48
57
|
export declare class FetchMock {
|
|
49
58
|
private readonly _calls;
|
|
50
59
|
private server;
|
|
51
60
|
private readonly ownsServer;
|
|
52
61
|
private interceptors;
|
|
53
62
|
private netConnectAllowed;
|
|
63
|
+
private mswHandlers;
|
|
54
64
|
get calls(): MockCallHistory;
|
|
55
65
|
constructor(externalServer?: SetupServerLike);
|
|
56
|
-
activate(): void;
|
|
66
|
+
activate(options?: ActivateOptions): void;
|
|
57
67
|
disableNetConnect(): void;
|
|
58
68
|
enableNetConnect(matcher?: string | RegExp | ((host: string) => boolean)): void;
|
|
59
69
|
private isNetConnectAllowed;
|
|
70
|
+
/**
|
|
71
|
+
* Remove consumed MSW handlers so future requests to those URLs
|
|
72
|
+
* go through MSW's onUnhandledRequest instead of silently passing through.
|
|
73
|
+
*/
|
|
74
|
+
private syncMswHandlers;
|
|
60
75
|
getCallHistory(): MockCallHistory;
|
|
61
76
|
clearCallHistory(): void;
|
|
62
77
|
deactivate(): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mock-server.d.ts","sourceRoot":"","sources":["../src/mock-server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEtD,2FAA2F;AAC3F,UAAU,eAAe;IACvB,GAAG,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IACvC,aAAa,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IACjD,MAAM,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAChD,KAAK,IAAI,IAAI,CAAC;CACf;AAED,KAAK,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;AAC9D,KAAK,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC;AACjE,KAAK,kBAAkB,GAAG,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC;AACzE,KAAK,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC;AAEjE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;IAC7C,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,KAAK,aAAa,GAAG,CAAC,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAElF,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,IAAI,IAAI,CAAC;IAChB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,cAAc,CAAC;IAC9E,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,cAAc,CAAC;IAC/D,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,cAAc,CAAC;CAC9C;AAED,MAAM,WAAW,QAAQ;IACvB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,eAAe,CAAC;CACvD;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;CAClB;AAiGD,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyB;IAChD,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAU;IACrC,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,iBAAiB,CAA4B;IAErD,IAAI,KAAK,IAAI,eAAe,CAE3B;gBAEW,cAAc,CAAC,EAAE,eAAe;IAK5C,QAAQ,
|
|
1
|
+
{"version":3,"file":"mock-server.d.ts","sourceRoot":"","sources":["../src/mock-server.ts"],"names":[],"mappings":"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"}
|
package/dist/mock-server.js
CHANGED
|
@@ -99,6 +99,8 @@ export class FetchMock {
|
|
|
99
99
|
ownsServer;
|
|
100
100
|
interceptors = [];
|
|
101
101
|
netConnectAllowed = false;
|
|
102
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
103
|
+
mswHandlers = new Map();
|
|
102
104
|
get calls() {
|
|
103
105
|
return this._calls;
|
|
104
106
|
}
|
|
@@ -106,19 +108,29 @@ export class FetchMock {
|
|
|
106
108
|
this.server = externalServer ?? null;
|
|
107
109
|
this.ownsServer = !externalServer;
|
|
108
110
|
}
|
|
109
|
-
activate() {
|
|
111
|
+
activate(options) {
|
|
110
112
|
if (this.ownsServer) {
|
|
111
113
|
const isPatched = Object.getOwnPropertySymbols(globalThis.fetch).some((s) => s.description === 'isPatchedModule');
|
|
112
114
|
if (isPatched) {
|
|
113
115
|
throw new Error('Another MSW server is already active. ' +
|
|
114
116
|
'Pass your existing server to new FetchMock(server) instead.');
|
|
115
117
|
}
|
|
118
|
+
const mode = options?.onUnhandledRequest ?? 'error';
|
|
116
119
|
this.server = setupServer();
|
|
117
120
|
this.server.listen({
|
|
118
121
|
onUnhandledRequest: (request, print) => {
|
|
119
122
|
if (this.isNetConnectAllowed(request))
|
|
120
123
|
return;
|
|
121
|
-
|
|
124
|
+
if (typeof mode === 'function') {
|
|
125
|
+
mode(request, print);
|
|
126
|
+
}
|
|
127
|
+
else if (mode === 'error') {
|
|
128
|
+
print.error();
|
|
129
|
+
}
|
|
130
|
+
else if (mode === 'warn') {
|
|
131
|
+
print.warning();
|
|
132
|
+
}
|
|
133
|
+
// 'bypass' → do nothing
|
|
122
134
|
},
|
|
123
135
|
});
|
|
124
136
|
}
|
|
@@ -141,6 +153,18 @@ export class FetchMock {
|
|
|
141
153
|
return this.netConnectAllowed.test(host);
|
|
142
154
|
return this.netConnectAllowed(host);
|
|
143
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Remove consumed MSW handlers so future requests to those URLs
|
|
158
|
+
* go through MSW's onUnhandledRequest instead of silently passing through.
|
|
159
|
+
*/
|
|
160
|
+
syncMswHandlers() {
|
|
161
|
+
if (!this.server || !this.ownsServer)
|
|
162
|
+
return;
|
|
163
|
+
const activeHandlers = [...this.mswHandlers.entries()]
|
|
164
|
+
.filter(([p]) => !p.consumed || p.persist)
|
|
165
|
+
.map(([, handler]) => handler);
|
|
166
|
+
this.server.resetHandlers(...activeHandlers);
|
|
167
|
+
}
|
|
144
168
|
getCallHistory() {
|
|
145
169
|
return this._calls;
|
|
146
170
|
}
|
|
@@ -149,6 +173,7 @@ export class FetchMock {
|
|
|
149
173
|
}
|
|
150
174
|
deactivate() {
|
|
151
175
|
this.interceptors = [];
|
|
176
|
+
this.mswHandlers.clear();
|
|
152
177
|
this._calls.clear();
|
|
153
178
|
if (this.ownsServer) {
|
|
154
179
|
this.server?.close();
|
|
@@ -158,6 +183,7 @@ export class FetchMock {
|
|
|
158
183
|
assertNoPendingInterceptors() {
|
|
159
184
|
const unconsumed = this.interceptors.filter(isPending);
|
|
160
185
|
this.interceptors = [];
|
|
186
|
+
this.mswHandlers.clear();
|
|
161
187
|
this._calls.clear();
|
|
162
188
|
if (this.ownsServer) {
|
|
163
189
|
this.server?.resetHandlers();
|
|
@@ -207,6 +233,7 @@ export class FetchMock {
|
|
|
207
233
|
pending.timesInvoked++;
|
|
208
234
|
if (!pending.persist && pending.timesInvoked >= pending.times) {
|
|
209
235
|
pending.consumed = true;
|
|
236
|
+
this.syncMswHandlers();
|
|
210
237
|
}
|
|
211
238
|
recordCall(this._calls, request, bodyText);
|
|
212
239
|
return bodyText;
|
|
@@ -216,6 +243,7 @@ export class FetchMock {
|
|
|
216
243
|
if (!this.server) {
|
|
217
244
|
throw new Error('FetchMock server is not active. Call activate() before registering interceptors.');
|
|
218
245
|
}
|
|
246
|
+
this.mswHandlers.set(pending, handler);
|
|
219
247
|
this.server.use(handler);
|
|
220
248
|
};
|
|
221
249
|
const buildChain = (delayRef) => ({
|
package/docs/api.md
CHANGED
|
@@ -7,7 +7,7 @@ A pre-built `FetchMock` instance for standalone use. No setup required — just
|
|
|
7
7
|
```typescript
|
|
8
8
|
import { fetchMock } from 'msw-fetch-mock';
|
|
9
9
|
|
|
10
|
-
beforeAll(() => fetchMock.activate());
|
|
10
|
+
beforeAll(() => fetchMock.activate({ onUnhandledRequest: 'error' }));
|
|
11
11
|
afterAll(() => fetchMock.deactivate());
|
|
12
12
|
afterEach(() => fetchMock.assertNoPendingInterceptors());
|
|
13
13
|
```
|
|
@@ -41,14 +41,47 @@ const fetchMock = new FetchMock(server);
|
|
|
41
41
|
### Lifecycle
|
|
42
42
|
|
|
43
43
|
```typescript
|
|
44
|
-
fetchMock.activate(); // start intercepting (calls server.listen())
|
|
45
|
-
fetchMock.deactivate();
|
|
44
|
+
fetchMock.activate(options?); // start intercepting (calls server.listen())
|
|
45
|
+
fetchMock.deactivate(); // stop intercepting (calls server.close())
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
> If you pass an external server that you manage yourself, `activate()` / `deactivate()` are no-ops.
|
|
49
49
|
>
|
|
50
50
|
> **Conflict detection:** In standalone mode, `activate()` checks whether `globalThis.fetch` is already patched by MSW. If so, it throws an error guiding you to pass your existing server via `new FetchMock(server)` instead.
|
|
51
51
|
|
|
52
|
+
#### `ActivateOptions`
|
|
53
|
+
|
|
54
|
+
| Property | Type | Default | Description |
|
|
55
|
+
| -------------------- | -------------------- | --------- | --------------------------------------------------- |
|
|
56
|
+
| `onUnhandledRequest` | `OnUnhandledRequest` | `'error'` | How to handle requests with no matching interceptor |
|
|
57
|
+
|
|
58
|
+
#### `OnUnhandledRequest`
|
|
59
|
+
|
|
60
|
+
| Value | Behavior |
|
|
61
|
+
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
62
|
+
| `'error'` | MSW prints an error and `fetch()` rejects with an `InternalError` |
|
|
63
|
+
| `'warn'` | MSW prints a warning; the request passes through to the real network |
|
|
64
|
+
| `'bypass'` | Silently passes through to the real network |
|
|
65
|
+
| `(request, print) => void` | Custom callback. Call `print.error()` to block or `print.warning()` to warn. Return without calling either to silently bypass. |
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// Default — reject unmatched requests
|
|
69
|
+
fetchMock.activate();
|
|
70
|
+
fetchMock.activate({ onUnhandledRequest: 'error' });
|
|
71
|
+
|
|
72
|
+
// Custom callback
|
|
73
|
+
fetchMock.activate({
|
|
74
|
+
onUnhandledRequest: (request, print) => {
|
|
75
|
+
if (new URL(request.url).pathname === '/health') return;
|
|
76
|
+
print.error();
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
> **Consumed interceptors:** Once a one-shot interceptor has been fully consumed, its MSW handler is removed. Subsequent requests to that URL are treated as unhandled and go through `onUnhandledRequest`. This prevents consumed interceptors from silently passing through.
|
|
82
|
+
>
|
|
83
|
+
> **Priority:** `enableNetConnect()` takes priority over `onUnhandledRequest` — allowed hosts always pass through regardless of the unhandled request mode.
|
|
84
|
+
|
|
52
85
|
### `fetchMock.calls`
|
|
53
86
|
|
|
54
87
|
Returns the `MockCallHistory` instance for inspecting and managing recorded requests.
|
|
@@ -63,13 +63,13 @@ it('calls API', async () => {
|
|
|
63
63
|
|
|
64
64
|
## Key Differences
|
|
65
65
|
|
|
66
|
-
| Aspect | cloudflare:test | msw-fetch-mock
|
|
67
|
-
| -------------------- | --------------------------------------------- |
|
|
68
|
-
| Import | `import { fetchMock } from 'cloudflare:test'` | `import { fetchMock } from 'msw-fetch-mock'`
|
|
69
|
-
| Server lifecycle | Implicit (managed by test framework) | Explicit (`activate()` / `deactivate()`)
|
|
70
|
-
| Call history access | `fetchMock.getCallHistory()` | `fetchMock.getCallHistory()` or `fetchMock.calls`
|
|
71
|
-
| Call history cleanup | Automatic per test | Automatic via `assertNoPendingInterceptors()`
|
|
72
|
-
|
|
|
73
|
-
| Runtime | Cloudflare Workers (workerd) | Node.js
|
|
66
|
+
| Aspect | cloudflare:test | msw-fetch-mock |
|
|
67
|
+
| -------------------- | --------------------------------------------- | -------------------------------------------------- |
|
|
68
|
+
| Import | `import { fetchMock } from 'cloudflare:test'` | `import { fetchMock } from 'msw-fetch-mock'` |
|
|
69
|
+
| Server lifecycle | Implicit (managed by test framework) | Explicit (`activate()` / `deactivate()`) |
|
|
70
|
+
| Call history access | `fetchMock.getCallHistory()` | `fetchMock.getCallHistory()` or `fetchMock.calls` |
|
|
71
|
+
| Call history cleanup | Automatic per test | Automatic via `assertNoPendingInterceptors()` |
|
|
72
|
+
| Unhandled requests | Must call `disableNetConnect()` | `onUnhandledRequest: 'error'` by default (rejects) |
|
|
73
|
+
| Runtime | Cloudflare Workers (workerd) | Node.js |
|
|
74
74
|
|
|
75
75
|
> **Note:** `getCallHistory()` and `clearCallHistory()` are provided as Cloudflare-compatible aliases. You can use either the Cloudflare-style methods or the `fetchMock.calls` getter — they are equivalent.
|