msw-fetch-mock 0.2.1 → 0.3.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 CHANGED
@@ -8,6 +8,8 @@ Undici-style fetch mock API built on [MSW](https://mswjs.io/) (Mock Service Work
8
8
 
9
9
  If you're familiar with Cloudflare Workers' `fetchMock` (from `cloudflare:test`) or Node.js undici's `MockAgent`, you already know this API.
10
10
 
11
+ Supports both **Node.js** (`msw/node`) and **Browser** (`msw/browser`) environments via subpath exports.
12
+
11
13
  ## Install
12
14
 
13
15
  ```bash
@@ -18,10 +20,12 @@ npm install -D msw-fetch-mock msw
18
20
 
19
21
  ## Quick Start
20
22
 
21
- ### Standalone (Cloudflare migration)
23
+ ### Node.js (Vitest, Jest)
22
24
 
23
25
  ```typescript
26
+ // Works with default import or explicit /node subpath
24
27
  import { fetchMock } from 'msw-fetch-mock';
28
+ // import { fetchMock } from 'msw-fetch-mock/node';
25
29
 
26
30
  beforeAll(() => fetchMock.activate({ onUnhandledRequest: 'error' }));
27
31
  afterAll(() => fetchMock.deactivate());
@@ -43,6 +47,25 @@ it('mocks a GET request', async () => {
43
47
  });
44
48
  ```
45
49
 
50
+ ### Browser (Storybook, Vitest Browser Mode)
51
+
52
+ ```typescript
53
+ import { setupWorker } from 'msw/browser';
54
+ import { createFetchMock } from 'msw-fetch-mock/browser';
55
+
56
+ const worker = setupWorker();
57
+ const fetchMock = createFetchMock(worker);
58
+
59
+ beforeAll(async () => {
60
+ await fetchMock.activate({ onUnhandledRequest: 'error' });
61
+ });
62
+ afterAll(() => fetchMock.deactivate());
63
+ afterEach(() => {
64
+ fetchMock.assertNoPendingInterceptors();
65
+ fetchMock.reset();
66
+ });
67
+ ```
68
+
46
69
  ### With an existing MSW server
47
70
 
48
71
  If you already use MSW, pass your server to share a single interceptor:
@@ -51,9 +74,10 @@ If you already use MSW, pass your server to share a single interceptor:
51
74
  import { setupServer } from 'msw/node';
52
75
  import { http, HttpResponse } from 'msw';
53
76
  import { FetchMock } from 'msw-fetch-mock';
77
+ import { NodeMswAdapter } from 'msw-fetch-mock/node';
54
78
 
55
79
  const server = setupServer(http.get('/api/users', () => HttpResponse.json([{ id: 1 }])));
56
- const fetchMock = new FetchMock(server);
80
+ const fetchMock = new FetchMock(new NodeMswAdapter(server));
57
81
 
58
82
  beforeAll(() => server.listen());
59
83
  afterAll(() => server.close());
@@ -63,7 +87,7 @@ afterEach(() => {
63
87
  });
64
88
  ```
65
89
 
66
- > **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.
90
+ > **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(new NodeMswAdapter(server))` instead.
67
91
 
68
92
  ## Unhandled Requests
69
93
 
@@ -93,13 +117,29 @@ fetchMock.activate({
93
117
 
94
118
  ## API Overview
95
119
 
120
+ ### Import Paths
121
+
122
+ | Path | Environment | MSW dependency |
123
+ | ------------------------ | ---------------------------- | -------------- |
124
+ | `msw-fetch-mock` | Node.js (re-exports `/node`) | `msw/node` |
125
+ | `msw-fetch-mock/node` | Node.js | `msw/node` |
126
+ | `msw-fetch-mock/browser` | Browser | `msw/browser` |
127
+
96
128
  ### `fetchMock` (singleton)
97
129
 
98
130
  A pre-built `FetchMock` instance for standalone use. Import and call `activate()` — no setup needed.
131
+ Available from `msw-fetch-mock` and `msw-fetch-mock/node`.
132
+
133
+ ### `createFetchMock(server?)` / `createFetchMock(worker)`
134
+
135
+ Factory function that creates a `FetchMock` with the appropriate adapter.
136
+
137
+ - Node: `createFetchMock(server?)` — optionally pass an existing MSW `SetupServer`
138
+ - Browser: `createFetchMock(worker)` — pass an MSW `SetupWorker` (required)
99
139
 
100
- ### `new FetchMock(server?)`
140
+ ### `new FetchMock(adapter?)`
101
141
 
102
- Creates a `FetchMock` instance. Pass an existing MSW `SetupServer` to share interceptors; omit to create one internally.
142
+ Creates a `FetchMock` instance with an explicit `MswAdapter`. Use `NodeMswAdapter` or `BrowserMswAdapter`.
103
143
 
104
144
  ### Intercepting & Replying
105
145
 
@@ -0,0 +1,10 @@
1
+ import type { MswAdapter, ResolvedActivateOptions, SetupWorkerLike } from './types';
2
+ export declare class BrowserMswAdapter implements MswAdapter {
3
+ private readonly worker;
4
+ constructor(worker: SetupWorkerLike);
5
+ use(...handlers: Array<unknown>): void;
6
+ resetHandlers(...handlers: Array<unknown>): void;
7
+ activate(options: ResolvedActivateOptions): Promise<void>;
8
+ deactivate(): void;
9
+ }
10
+ //# sourceMappingURL=browser-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-adapter.d.ts","sourceRoot":"","sources":["../src/browser-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAEpF,qBAAa,iBAAkB,YAAW,UAAU;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;gBAE7B,MAAM,EAAE,eAAe;IAInC,GAAG,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI;IAItC,aAAa,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI;IAI1C,QAAQ,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAM/D,UAAU,IAAI,IAAI;CAGnB"}
@@ -0,0 +1,20 @@
1
+ export class BrowserMswAdapter {
2
+ worker;
3
+ constructor(worker) {
4
+ this.worker = worker;
5
+ }
6
+ use(...handlers) {
7
+ this.worker.use(...handlers);
8
+ }
9
+ resetHandlers(...handlers) {
10
+ this.worker.resetHandlers(...handlers);
11
+ }
12
+ async activate(options) {
13
+ await this.worker.start({
14
+ onUnhandledRequest: options.onUnhandledRequest,
15
+ });
16
+ }
17
+ deactivate() {
18
+ this.worker.stop();
19
+ }
20
+ }
@@ -0,0 +1,9 @@
1
+ import { FetchMock } from './fetch-mock';
2
+ import type { SetupWorkerLike } from './types';
3
+ export { FetchMock } from './fetch-mock';
4
+ export { BrowserMswAdapter } from './browser-adapter';
5
+ export declare function createFetchMock(worker: SetupWorkerLike): FetchMock;
6
+ export type { ActivateOptions, OnUnhandledRequest, InterceptOptions, MockPool, MockInterceptor, MockReplyChain, ReplyOptions, PendingInterceptor, MswAdapter, SetupWorkerLike, } from './types';
7
+ export { MockCallHistory, MockCallHistoryLog } from './mock-call-history';
8
+ export type { MockCallHistoryLogData, CallHistoryFilterCriteria } from './mock-call-history';
9
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAElE;AAED,YAAY,EACV,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,EACR,eAAe,EACf,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,UAAU,EACV,eAAe,GAChB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC1E,YAAY,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { FetchMock } from './fetch-mock';
2
+ import { BrowserMswAdapter } from './browser-adapter';
3
+ export { FetchMock } from './fetch-mock';
4
+ export { BrowserMswAdapter } from './browser-adapter';
5
+ export function createFetchMock(worker) {
6
+ return new FetchMock(new BrowserMswAdapter(worker));
7
+ }
8
+ export { MockCallHistory, MockCallHistoryLog } from './mock-call-history';
@@ -0,0 +1,31 @@
1
+ import { MockCallHistory } from './mock-call-history';
2
+ import type { MockPool, PendingInterceptor, ActivateOptions, MswAdapter, SetupServerLike, SetupWorkerLike } from './types';
3
+ export type { InterceptOptions, ReplyOptions, MockReplyChain, MockInterceptor, MockPool, PendingInterceptor, OnUnhandledRequest, ActivateOptions, } from './types';
4
+ export declare class FetchMock {
5
+ /** @internal */
6
+ static _defaultAdapterFactory?: () => MswAdapter;
7
+ private readonly _calls;
8
+ private adapter;
9
+ private interceptors;
10
+ private netConnectAllowed;
11
+ private mswHandlers;
12
+ get calls(): MockCallHistory;
13
+ constructor(input?: SetupServerLike | SetupWorkerLike | MswAdapter);
14
+ activate(options?: ActivateOptions): Promise<void>;
15
+ disableNetConnect(): void;
16
+ enableNetConnect(matcher?: string | RegExp | ((host: string) => boolean)): void;
17
+ private isNetConnectAllowed;
18
+ /**
19
+ * Remove consumed MSW handlers so future requests to those URLs
20
+ * go through MSW's onUnhandledRequest instead of silently passing through.
21
+ */
22
+ private syncMswHandlers;
23
+ getCallHistory(): MockCallHistory;
24
+ clearCallHistory(): void;
25
+ deactivate(): void;
26
+ reset(): void;
27
+ assertNoPendingInterceptors(): void;
28
+ pendingInterceptors(): PendingInterceptor[];
29
+ get(origin: string): MockPool;
30
+ }
31
+ //# sourceMappingURL=fetch-mock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-mock.d.ts","sourceRoot":"","sources":["../src/fetch-mock.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAUV,QAAQ,EACR,kBAAkB,EAElB,eAAe,EACf,UAAU,EAEV,eAAe,EACf,eAAe,EAChB,MAAM,SAAS,CAAC;AAEjB,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,cAAc,EACd,eAAe,EACf,QAAQ,EACR,kBAAkB,EAClB,kBAAkB,EAClB,eAAe,GAChB,MAAM,SAAS,CAAC;AA2KjB,qBAAa,SAAS;IACpB,gBAAgB;IAChB,MAAM,CAAC,sBAAsB,CAAC,EAAE,MAAM,UAAU,CAAC;IAEjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyB;IAChD,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,iBAAiB,CAA4B;IAErD,OAAO,CAAC,WAAW,CAA2C;IAE9D,IAAI,KAAK,IAAI,eAAe,CAE3B;gBAEW,KAAK,CAAC,EAAE,eAAe,GAAG,eAAe,GAAG,UAAU;IAI5D,QAAQ,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBxD,iBAAiB,IAAI,IAAI;IAIzB,gBAAgB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,IAAI;IAI/E,OAAO,CAAC,mBAAmB;IAS3B;;;OAGG;IACH,OAAO,CAAC,eAAe;IAOvB,cAAc,IAAI,eAAe;IAIjC,gBAAgB,IAAI,IAAI;IAIxB,UAAU,IAAI,IAAI;IAOlB,KAAK,IAAI,IAAI;IAOb,2BAA2B,IAAI,IAAI;IAQnC,mBAAmB,IAAI,kBAAkB,EAAE;IAI3C,GAAG,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ;CAqH9B"}
@@ -1,5 +1,4 @@
1
1
  import { http, HttpResponse } from 'msw';
2
- import { setupServer } from 'msw/node';
3
2
  import { MockCallHistory } from './mock-call-history';
4
3
  function isPending(p) {
5
4
  if (p.persist)
@@ -93,10 +92,76 @@ function buildResponse(status, responseBody, replyOptions) {
93
92
  }
94
93
  return HttpResponse.json(responseBody, { status, headers });
95
94
  }
95
+ function isSetupServerLike(input) {
96
+ return (typeof input === 'object' &&
97
+ input !== null &&
98
+ 'listen' in input &&
99
+ typeof input.listen === 'function' &&
100
+ 'close' in input &&
101
+ typeof input.close === 'function');
102
+ }
103
+ function isSetupWorkerLike(input) {
104
+ return (typeof input === 'object' &&
105
+ input !== null &&
106
+ 'start' in input &&
107
+ typeof input.start === 'function' &&
108
+ 'stop' in input &&
109
+ typeof input.stop === 'function');
110
+ }
111
+ function isMswAdapter(input) {
112
+ return (typeof input === 'object' &&
113
+ input !== null &&
114
+ 'activate' in input &&
115
+ typeof input.activate === 'function' &&
116
+ 'deactivate' in input &&
117
+ typeof input.deactivate === 'function');
118
+ }
119
+ function createServerAdapter(server) {
120
+ return {
121
+ use: (...handlers) => server.use(...handlers),
122
+ resetHandlers: (...handlers) => server.resetHandlers(...handlers),
123
+ activate(options) {
124
+ server.listen({ onUnhandledRequest: options.onUnhandledRequest });
125
+ },
126
+ deactivate() {
127
+ server.close();
128
+ },
129
+ };
130
+ }
131
+ function createWorkerAdapter(worker) {
132
+ return {
133
+ use: (...handlers) => worker.use(...handlers),
134
+ resetHandlers: (...handlers) => worker.resetHandlers(...handlers),
135
+ async activate(options) {
136
+ await worker.start({ onUnhandledRequest: options.onUnhandledRequest });
137
+ },
138
+ deactivate() {
139
+ worker.stop();
140
+ },
141
+ };
142
+ }
143
+ function resolveAdapter(input) {
144
+ if (!input) {
145
+ if (!FetchMock._defaultAdapterFactory) {
146
+ throw new Error('FetchMock requires a server, worker, or adapter argument. ' +
147
+ 'Use createFetchMock() from msw-fetch-mock/node or msw-fetch-mock/browser, ' +
148
+ 'or pass a setupServer/setupWorker instance directly.');
149
+ }
150
+ return FetchMock._defaultAdapterFactory();
151
+ }
152
+ if (isMswAdapter(input))
153
+ return input;
154
+ if (isSetupServerLike(input))
155
+ return createServerAdapter(input);
156
+ if (isSetupWorkerLike(input))
157
+ return createWorkerAdapter(input);
158
+ throw new Error('Invalid argument: expected a setupServer, setupWorker, or MswAdapter instance.');
159
+ }
96
160
  export class FetchMock {
161
+ /** @internal */
162
+ static _defaultAdapterFactory;
97
163
  _calls = new MockCallHistory();
98
- server;
99
- ownsServer;
164
+ adapter;
100
165
  interceptors = [];
101
166
  netConnectAllowed = false;
102
167
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -104,36 +169,27 @@ export class FetchMock {
104
169
  get calls() {
105
170
  return this._calls;
106
171
  }
107
- constructor(externalServer) {
108
- this.server = externalServer ?? null;
109
- this.ownsServer = !externalServer;
172
+ constructor(input) {
173
+ this.adapter = resolveAdapter(input);
110
174
  }
111
- activate(options) {
112
- if (this.ownsServer) {
113
- const isPatched = Object.getOwnPropertySymbols(globalThis.fetch).some((s) => s.description === 'isPatchedModule');
114
- if (isPatched) {
115
- throw new Error('Another MSW server is already active. ' +
116
- 'Pass your existing server to new FetchMock(server) instead.');
117
- }
118
- const mode = options?.onUnhandledRequest ?? 'error';
119
- this.server = setupServer();
120
- this.server.listen({
121
- onUnhandledRequest: (request, print) => {
122
- if (this.isNetConnectAllowed(request))
123
- return;
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
134
- },
135
- });
136
- }
175
+ async activate(options) {
176
+ const mode = options?.onUnhandledRequest ?? 'error';
177
+ await this.adapter.activate({
178
+ onUnhandledRequest: (request, print) => {
179
+ if (this.isNetConnectAllowed(request))
180
+ return;
181
+ if (typeof mode === 'function') {
182
+ mode(request, print);
183
+ }
184
+ else if (mode === 'error') {
185
+ print.error();
186
+ }
187
+ else if (mode === 'warn') {
188
+ print.warning();
189
+ }
190
+ // 'bypass' → do nothing
191
+ },
192
+ });
137
193
  }
138
194
  disableNetConnect() {
139
195
  this.netConnectAllowed = false;
@@ -158,12 +214,10 @@ export class FetchMock {
158
214
  * go through MSW's onUnhandledRequest instead of silently passing through.
159
215
  */
160
216
  syncMswHandlers() {
161
- if (!this.server || !this.ownsServer)
162
- return;
163
217
  const activeHandlers = [...this.mswHandlers.entries()]
164
218
  .filter(([p]) => !p.consumed || p.persist)
165
219
  .map(([, handler]) => handler);
166
- this.server.resetHandlers(...activeHandlers);
220
+ this.adapter.resetHandlers(...activeHandlers);
167
221
  }
168
222
  getCallHistory() {
169
223
  return this._calls;
@@ -175,18 +229,13 @@ export class FetchMock {
175
229
  this.interceptors = [];
176
230
  this.mswHandlers.clear();
177
231
  this._calls.clear();
178
- if (this.ownsServer) {
179
- this.server?.close();
180
- this.server = null;
181
- }
232
+ this.adapter.deactivate();
182
233
  }
183
234
  reset() {
184
235
  this.interceptors = [];
185
236
  this.mswHandlers.clear();
186
237
  this._calls.clear();
187
- if (this.ownsServer) {
188
- this.server?.resetHandlers();
189
- }
238
+ this.adapter.resetHandlers();
190
239
  }
191
240
  assertNoPendingInterceptors() {
192
241
  const unconsumed = this.interceptors.filter(isPending);
@@ -242,11 +291,8 @@ export class FetchMock {
242
291
  };
243
292
  const registerHandler = (handlerFn) => {
244
293
  const handler = getHttpMethod(method)(urlPattern, async ({ request }) => handlerFn(request));
245
- if (!this.server) {
246
- throw new Error('FetchMock server is not active. Call activate() before registering interceptors.');
247
- }
248
294
  this.mswHandlers.set(pending, handler);
249
- this.server.use(handler);
295
+ this.adapter.use(handler);
250
296
  };
251
297
  const buildChain = (delayRef) => ({
252
298
  times(n) {
@@ -299,6 +345,3 @@ export class FetchMock {
299
345
  };
300
346
  }
301
347
  }
302
- export function createFetchMock(externalServer) {
303
- return new FetchMock(externalServer);
304
- }
package/dist/index.d.ts CHANGED
@@ -1,8 +1,3 @@
1
- import { FetchMock } from './mock-server';
2
- export { createFetchMock, FetchMock } from './mock-server';
3
- /** Pre-built singleton for quick standalone use (Cloudflare migration compatible). */
4
- export declare const fetchMock: FetchMock;
5
- export type { ActivateOptions, OnUnhandledRequest, InterceptOptions, MockPool, MockInterceptor, MockReplyChain, ReplyOptions, PendingInterceptor, } from './mock-server';
6
- export { MockCallHistory, MockCallHistoryLog } from './mock-call-history';
7
- export type { MockCallHistoryLogData, CallHistoryFilterCriteria } from './mock-call-history';
1
+ export { FetchMock, NodeMswAdapter, createFetchMock, fetchMock, MockCallHistory, MockCallHistoryLog, } from './node';
2
+ export type { ActivateOptions, OnUnhandledRequest, InterceptOptions, MockPool, MockInterceptor, MockReplyChain, ReplyOptions, PendingInterceptor, MswAdapter, SetupServerLike, MockCallHistoryLogData, CallHistoryFilterCriteria, } from './node';
8
3
  //# sourceMappingURL=index.d.ts.map
@@ -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,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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,cAAc,EACd,eAAe,EACf,SAAS,EACT,eAAe,EACf,kBAAkB,GACnB,MAAM,QAAQ,CAAC;AAChB,YAAY,EACV,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,EACR,eAAe,EACf,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,UAAU,EACV,eAAe,EACf,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,QAAQ,CAAC"}
package/dist/index.js CHANGED
@@ -1,5 +1 @@
1
- import { FetchMock } from './mock-server';
2
- export { createFetchMock, FetchMock } from './mock-server';
3
- /** Pre-built singleton for quick standalone use (Cloudflare migration compatible). */
4
- export const fetchMock = new FetchMock();
5
- export { MockCallHistory, MockCallHistoryLog } from './mock-call-history';
1
+ export { FetchMock, NodeMswAdapter, createFetchMock, fetchMock, MockCallHistory, MockCallHistoryLog, } from './node';
@@ -0,0 +1,11 @@
1
+ import type { MswAdapter, ResolvedActivateOptions, SetupServerLike } from './types';
2
+ export declare class NodeMswAdapter implements MswAdapter {
3
+ private server;
4
+ private readonly ownsServer;
5
+ constructor(externalServer?: SetupServerLike);
6
+ use(...handlers: Array<unknown>): void;
7
+ resetHandlers(...handlers: Array<unknown>): void;
8
+ activate(options: ResolvedActivateOptions): void;
9
+ deactivate(): void;
10
+ }
11
+ //# sourceMappingURL=node-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-adapter.d.ts","sourceRoot":"","sources":["../src/node-adapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAEpF,qBAAa,cAAe,YAAW,UAAU;IAC/C,OAAO,CAAC,MAAM,CAAyB;IACvC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAU;gBAEzB,cAAc,CAAC,EAAE,eAAe;IAK5C,GAAG,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI;IAItC,aAAa,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,IAAI;IAIhD,QAAQ,CAAC,OAAO,EAAE,uBAAuB,GAAG,IAAI;IAmBhD,UAAU,IAAI,IAAI;CAMnB"}
@@ -0,0 +1,34 @@
1
+ import { setupServer } from 'msw/node';
2
+ export class NodeMswAdapter {
3
+ server;
4
+ ownsServer;
5
+ constructor(externalServer) {
6
+ this.server = externalServer ?? null;
7
+ this.ownsServer = !externalServer;
8
+ }
9
+ use(...handlers) {
10
+ this.server.use(...handlers);
11
+ }
12
+ resetHandlers(...handlers) {
13
+ this.server.resetHandlers(...handlers);
14
+ }
15
+ activate(options) {
16
+ if (!this.ownsServer)
17
+ return;
18
+ const isPatched = Object.getOwnPropertySymbols(globalThis.fetch).some((s) => s.description === 'isPatchedModule');
19
+ if (isPatched) {
20
+ throw new Error('Another MSW server is already active. ' +
21
+ 'Pass your existing server to new FetchMock(server) instead.');
22
+ }
23
+ this.server = setupServer();
24
+ this.server.listen({
25
+ onUnhandledRequest: options.onUnhandledRequest,
26
+ });
27
+ }
28
+ deactivate() {
29
+ if (this.ownsServer) {
30
+ this.server?.close();
31
+ this.server = null;
32
+ }
33
+ }
34
+ }
package/dist/node.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import { FetchMock } from './fetch-mock';
2
+ import type { SetupServerLike } from './types';
3
+ export { FetchMock } from './fetch-mock';
4
+ export { NodeMswAdapter } from './node-adapter';
5
+ export declare function createFetchMock(server?: SetupServerLike): FetchMock;
6
+ /** Pre-built singleton for quick standalone use (Cloudflare migration compatible). */
7
+ export declare const fetchMock: FetchMock;
8
+ export type { ActivateOptions, OnUnhandledRequest, InterceptOptions, MockPool, MockInterceptor, MockReplyChain, ReplyOptions, PendingInterceptor, MswAdapter, SetupServerLike, } from './types';
9
+ export { MockCallHistory, MockCallHistoryLog } from './mock-call-history';
10
+ export type { MockCallHistoryLogData, CallHistoryFilterCriteria } from './mock-call-history';
11
+ //# sourceMappingURL=node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKhD,wBAAgB,eAAe,CAAC,MAAM,CAAC,EAAE,eAAe,GAAG,SAAS,CAEnE;AAED,sFAAsF;AACtF,eAAO,MAAM,SAAS,WAAoB,CAAC;AAE3C,YAAY,EACV,eAAe,EACf,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,EACR,eAAe,EACf,cAAc,EACd,YAAY,EACZ,kBAAkB,EAClB,UAAU,EACV,eAAe,GAChB,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC1E,YAAY,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/node.js ADDED
@@ -0,0 +1,12 @@
1
+ import { FetchMock } from './fetch-mock';
2
+ import { NodeMswAdapter } from './node-adapter';
3
+ export { FetchMock } from './fetch-mock';
4
+ export { NodeMswAdapter } from './node-adapter';
5
+ /** Register Node.js as the default adapter environment so `new FetchMock()` works. */
6
+ FetchMock._defaultAdapterFactory = () => new NodeMswAdapter();
7
+ export function createFetchMock(server) {
8
+ return new FetchMock(new NodeMswAdapter(server));
9
+ }
10
+ /** Pre-built singleton for quick standalone use (Cloudflare migration compatible). */
11
+ export const fetchMock = createFetchMock();
12
+ export { MockCallHistory, MockCallHistoryLog } from './mock-call-history';
@@ -0,0 +1,74 @@
1
+ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
2
+ export type PathMatcher = string | RegExp | ((path: string) => boolean);
3
+ export type HeaderValueMatcher = string | RegExp | ((value: string) => boolean);
4
+ export type BodyMatcher = string | RegExp | ((body: string) => boolean);
5
+ export interface InterceptOptions {
6
+ path: PathMatcher;
7
+ method?: HttpMethod;
8
+ headers?: Record<string, HeaderValueMatcher>;
9
+ body?: BodyMatcher;
10
+ query?: Record<string, string>;
11
+ }
12
+ export interface ReplyOptions {
13
+ headers?: Record<string, string>;
14
+ }
15
+ export type ReplyCallback = (req: {
16
+ body: string | null;
17
+ }) => unknown | Promise<unknown>;
18
+ export interface MockReplyChain {
19
+ times(n: number): void;
20
+ persist(): void;
21
+ delay(ms: number): void;
22
+ }
23
+ export interface MockInterceptor {
24
+ reply(status: number, body?: unknown, options?: ReplyOptions): MockReplyChain;
25
+ reply(status: number, callback: ReplyCallback): MockReplyChain;
26
+ replyWithError(error: Error): MockReplyChain;
27
+ }
28
+ export interface MockPool {
29
+ intercept(options: InterceptOptions): MockInterceptor;
30
+ }
31
+ export interface PendingInterceptor {
32
+ origin: string;
33
+ path: string;
34
+ method: string;
35
+ consumed: boolean;
36
+ times: number;
37
+ timesInvoked: number;
38
+ persist: boolean;
39
+ }
40
+ export type NetConnectMatcher = true | false | string | RegExp | ((host: string) => boolean);
41
+ export type PrintAPI = {
42
+ warning(): void;
43
+ error(): void;
44
+ };
45
+ export type OnUnhandledRequestCallback = (request: Request, print: PrintAPI) => void;
46
+ export type OnUnhandledRequest = 'bypass' | 'warn' | 'error' | OnUnhandledRequestCallback;
47
+ export interface ActivateOptions {
48
+ onUnhandledRequest?: OnUnhandledRequest;
49
+ }
50
+ export interface ResolvedActivateOptions {
51
+ onUnhandledRequest: OnUnhandledRequestCallback;
52
+ }
53
+ /** Structural type to avoid cross-package nominal type mismatch on MSW's private fields */
54
+ export interface SetupServerLike {
55
+ use(...handlers: Array<unknown>): void;
56
+ resetHandlers(...handlers: Array<unknown>): void;
57
+ listen(options?: Record<string, unknown>): void;
58
+ close(): void;
59
+ }
60
+ /** Structural type for MSW's setupWorker return type */
61
+ export interface SetupWorkerLike {
62
+ use(...handlers: Array<unknown>): void;
63
+ resetHandlers(...handlers: Array<unknown>): void;
64
+ start(options?: Record<string, unknown>): Promise<void>;
65
+ stop(): void;
66
+ }
67
+ /** Environment-agnostic adapter interface for MSW server/worker */
68
+ export interface MswAdapter {
69
+ use(...handlers: Array<unknown>): void;
70
+ resetHandlers(...handlers: Array<unknown>): void;
71
+ activate(options: ResolvedActivateOptions): void | Promise<void>;
72
+ deactivate(): void;
73
+ }
74
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;AACrE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC;AACxE,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC;AAChF,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC;AAExE,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,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEzF,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;AAED,MAAM,MAAM,iBAAiB,GAAG,IAAI,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC;AAE7F,MAAM,MAAM,QAAQ,GAAG;IAAE,OAAO,IAAI,IAAI,CAAC;IAAC,KAAK,IAAI,IAAI,CAAA;CAAE,CAAC;AAC1D,MAAM,MAAM,0BAA0B,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;AACrF,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,0BAA0B,CAAC;AAE1F,MAAM,WAAW,eAAe;IAC9B,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;CACzC;AAED,MAAM,WAAW,uBAAuB;IACtC,kBAAkB,EAAE,0BAA0B,CAAC;CAChD;AAED,2FAA2F;AAC3F,MAAM,WAAW,eAAe;IAC9B,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,wDAAwD;AACxD,MAAM,WAAW,eAAe;IAC9B,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,KAAK,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,IAAI,IAAI,IAAI,CAAC;CACd;AAED,mEAAmE;AACnE,MAAM,WAAW,UAAU;IACzB,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,QAAQ,CAAC,OAAO,EAAE,uBAAuB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,UAAU,IAAI,IAAI,CAAC;CACpB"}
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/docs/api.md CHANGED
@@ -1,13 +1,23 @@
1
1
  # API Reference
2
2
 
3
+ ## Import Paths
4
+
5
+ | Path | Environment | MSW dependency |
6
+ | ------------------------ | ---------------------------- | -------------- |
7
+ | `msw-fetch-mock` | Node.js (re-exports `/node`) | `msw/node` |
8
+ | `msw-fetch-mock/node` | Node.js | `msw/node` |
9
+ | `msw-fetch-mock/browser` | Browser | `msw/browser` |
10
+
3
11
  ## `fetchMock` (singleton)
4
12
 
5
- A pre-built `FetchMock` instance for standalone use. No setup required — just import and call `activate()`.
13
+ A pre-built `FetchMock` instance for standalone Node.js use. No setup required — just import and call `activate()`.
6
14
 
7
15
  ```typescript
8
16
  import { fetchMock } from 'msw-fetch-mock';
9
17
 
10
- beforeAll(() => fetchMock.activate({ onUnhandledRequest: 'error' }));
18
+ beforeAll(async () => {
19
+ await fetchMock.activate({ onUnhandledRequest: 'error' });
20
+ });
11
21
  afterAll(() => fetchMock.deactivate());
12
22
  afterEach(() => {
13
23
  fetchMock.assertNoPendingInterceptors();
@@ -15,27 +25,57 @@ afterEach(() => {
15
25
  });
16
26
  ```
17
27
 
18
- ## `new FetchMock(server?)`
28
+ ## `createFetchMock(server?)` (Node)
19
29
 
20
- Creates a `FetchMock` instance. Pass an existing MSW `SetupServer` to share interceptors; omit to create one internally.
30
+ Creates a `FetchMock` with `NodeMswAdapter`. Optionally pass an existing MSW server.
21
31
 
22
32
  ```typescript
23
- import { FetchMock } from 'msw-fetch-mock';
33
+ import { createFetchMock } from 'msw-fetch-mock/node';
34
+ import { setupServer } from 'msw/node';
24
35
 
25
- // Standalone (creates internal MSW server)
26
- const fetchMock = new FetchMock();
36
+ // Standalone
37
+ const fetchMock = createFetchMock();
27
38
 
28
39
  // With external MSW server
29
- import { setupServer } from 'msw/node';
30
40
  const server = setupServer();
31
- const fetchMock = new FetchMock(server);
41
+ const fetchMock = createFetchMock(server);
32
42
  ```
33
43
 
34
- | Parameter | Type | Required | Description |
35
- | --------- | ------------- | -------- | ------------------------------------------------------- |
36
- | `server` | `SetupServer` | No | Existing MSW server. Creates one internally if omitted. |
44
+ ## `createFetchMock(worker)` (Browser)
45
+
46
+ Creates a `FetchMock` with `BrowserMswAdapter`. Requires an MSW worker.
47
+
48
+ ```typescript
49
+ import { setupWorker } from 'msw/browser';
50
+ import { createFetchMock } from 'msw-fetch-mock/browser';
51
+
52
+ const worker = setupWorker();
53
+ const fetchMock = createFetchMock(worker);
54
+
55
+ beforeAll(async () => {
56
+ await fetchMock.activate({ onUnhandledRequest: 'error' });
57
+ });
58
+ ```
59
+
60
+ ## `new FetchMock(adapter?)`
61
+
62
+ Creates a `FetchMock` instance with an explicit `MswAdapter`.
63
+
64
+ ```typescript
65
+ import { FetchMock } from 'msw-fetch-mock';
66
+ import { NodeMswAdapter } from 'msw-fetch-mock/node';
67
+ import { BrowserMswAdapter } from 'msw-fetch-mock/browser';
68
+
69
+ // Node with external server
70
+ const fetchMock = new FetchMock(new NodeMswAdapter(server));
71
+
72
+ // Browser with worker
73
+ const fetchMock = new FetchMock(new BrowserMswAdapter(worker));
74
+ ```
37
75
 
38
- > `createFetchMock(server?)` is also available as a backward-compatible factory function.
76
+ | Parameter | Type | Required | Description |
77
+ | --------- | ------------ | -------- | ----------------------------------------------------- |
78
+ | `adapter` | `MswAdapter` | No | Environment adapter. Use `createFetchMock()` instead. |
39
79
 
40
80
  ---
41
81
 
@@ -44,13 +84,13 @@ const fetchMock = new FetchMock(server);
44
84
  ### Lifecycle
45
85
 
46
86
  ```typescript
47
- fetchMock.activate(options?); // start intercepting (calls server.listen())
48
- fetchMock.deactivate(); // stop intercepting (calls server.close())
87
+ await fetchMock.activate(options?); // start intercepting (async — browser needs worker.start())
88
+ fetchMock.deactivate(); // stop intercepting
49
89
  ```
50
90
 
51
- > If you pass an external server that you manage yourself, `activate()` / `deactivate()` are no-ops.
91
+ > `activate()` returns `Promise<void>`. In Node.js, the promise resolves synchronously. In the browser, it waits for the Service Worker to start. Vitest and Jest handle async `beforeAll` natively.
52
92
  >
53
- > **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.
93
+ > **Conflict detection (Node only):** In standalone mode, `activate()` checks whether `globalThis.fetch` is already patched by MSW. If so, it throws an error guiding you to use `new FetchMock(new NodeMswAdapter(server))` instead.
54
94
 
55
95
  #### `ActivateOptions`
56
96
 
@@ -69,11 +109,11 @@ fetchMock.deactivate(); // stop intercepting (calls server.close())
69
109
 
70
110
  ```typescript
71
111
  // Default — reject unmatched requests
72
- fetchMock.activate();
73
- fetchMock.activate({ onUnhandledRequest: 'error' });
112
+ await fetchMock.activate();
113
+ await fetchMock.activate({ onUnhandledRequest: 'error' });
74
114
 
75
115
  // Custom callback
76
- fetchMock.activate({
116
+ await fetchMock.activate({
77
117
  onUnhandledRequest: (request, print) => {
78
118
  if (new URL(request.url).pathname === '/health') return;
79
119
  print.error();
@@ -7,7 +7,7 @@ If you're migrating tests from Cloudflare Workers' `cloudflare:test` to a standa
7
7
  | cloudflare:test | msw-fetch-mock |
8
8
  | -------------------------------------------------- | ----------------------------------------------------------- |
9
9
  | `import { fetchMock } from 'cloudflare:test'` | `import { fetchMock } from 'msw-fetch-mock'` |
10
- | `fetchMock.activate()` | `fetchMock.activate()` |
10
+ | `fetchMock.activate()` | `await fetchMock.activate()` |
11
11
  | `fetchMock.disableNetConnect()` | `fetchMock.disableNetConnect()` |
12
12
  | `fetchMock.enableNetConnect(matcher?)` | `fetchMock.enableNetConnect(matcher?)` |
13
13
  | `fetchMock.deactivate()` | `fetchMock.deactivate()` |
@@ -46,7 +46,9 @@ it('calls API', async () => {
46
46
  ```typescript
47
47
  import { fetchMock } from 'msw-fetch-mock';
48
48
 
49
- beforeAll(() => fetchMock.activate());
49
+ beforeAll(async () => {
50
+ await fetchMock.activate();
51
+ });
50
52
  afterAll(() => fetchMock.deactivate());
51
53
  afterEach(() => {
52
54
  fetchMock.assertNoPendingInterceptors();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "msw-fetch-mock",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Undici-style fetch mock API built on MSW (Mock Service Worker)",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -9,7 +9,9 @@
9
9
  "fetch",
10
10
  "mock",
11
11
  "testing",
12
- "undici"
12
+ "undici",
13
+ "browser",
14
+ "service-worker"
13
15
  ],
14
16
  "repository": {
15
17
  "type": "git",
@@ -24,6 +26,16 @@
24
26
  "source": "./src/index.ts",
25
27
  "types": "./dist/index.d.ts",
26
28
  "import": "./dist/index.js"
29
+ },
30
+ "./node": {
31
+ "source": "./src/node.ts",
32
+ "types": "./dist/node.d.ts",
33
+ "import": "./dist/node.js"
34
+ },
35
+ "./browser": {
36
+ "source": "./src/browser.ts",
37
+ "types": "./dist/browser.d.ts",
38
+ "import": "./dist/browser.js"
27
39
  }
28
40
  },
29
41
  "files": [
@@ -1,85 +0,0 @@
1
- import { MockCallHistory } from './mock-call-history';
2
- /** Structural type to avoid cross-package nominal type mismatch on MSW's private fields */
3
- interface SetupServerLike {
4
- use(...handlers: Array<unknown>): void;
5
- resetHandlers(...handlers: Array<unknown>): void;
6
- listen(options?: Record<string, unknown>): void;
7
- close(): void;
8
- }
9
- type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
10
- type PathMatcher = string | RegExp | ((path: string) => boolean);
11
- type HeaderValueMatcher = string | RegExp | ((value: string) => boolean);
12
- type BodyMatcher = string | RegExp | ((body: string) => boolean);
13
- export interface InterceptOptions {
14
- path: PathMatcher;
15
- method?: HttpMethod;
16
- headers?: Record<string, HeaderValueMatcher>;
17
- body?: BodyMatcher;
18
- query?: Record<string, string>;
19
- }
20
- export interface ReplyOptions {
21
- headers?: Record<string, string>;
22
- }
23
- type ReplyCallback = (req: {
24
- body: string | null;
25
- }) => unknown | Promise<unknown>;
26
- export interface MockReplyChain {
27
- times(n: number): void;
28
- persist(): void;
29
- delay(ms: number): void;
30
- }
31
- export interface MockInterceptor {
32
- reply(status: number, body?: unknown, options?: ReplyOptions): MockReplyChain;
33
- reply(status: number, callback: ReplyCallback): MockReplyChain;
34
- replyWithError(error: Error): MockReplyChain;
35
- }
36
- export interface MockPool {
37
- intercept(options: InterceptOptions): MockInterceptor;
38
- }
39
- export interface PendingInterceptor {
40
- origin: string;
41
- path: string;
42
- method: string;
43
- consumed: boolean;
44
- times: number;
45
- timesInvoked: number;
46
- persist: boolean;
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
- }
57
- export declare class FetchMock {
58
- private readonly _calls;
59
- private server;
60
- private readonly ownsServer;
61
- private interceptors;
62
- private netConnectAllowed;
63
- private mswHandlers;
64
- get calls(): MockCallHistory;
65
- constructor(externalServer?: SetupServerLike);
66
- activate(options?: ActivateOptions): void;
67
- disableNetConnect(): void;
68
- enableNetConnect(matcher?: string | RegExp | ((host: string) => boolean)): void;
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;
75
- getCallHistory(): MockCallHistory;
76
- clearCallHistory(): void;
77
- deactivate(): void;
78
- reset(): void;
79
- assertNoPendingInterceptors(): void;
80
- pendingInterceptors(): PendingInterceptor[];
81
- get(origin: string): MockPool;
82
- }
83
- export declare function createFetchMock(externalServer?: SetupServerLike): FetchMock;
84
- export {};
85
- //# sourceMappingURL=mock-server.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mock-server.d.ts","sourceRoot":"","sources":["../src/mock-server.ts"],"names":[],"mappings":"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"}