msw-fetch-mock 0.3.3 → 0.4.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.
@@ -0,0 +1,80 @@
1
+ # Cloudflare Workers 遷移指南
2
+
3
+ 如果你正在將測試從 Cloudflare Workers 的 `cloudflare:test` 遷移到標準的 Node.js 測試環境,`msw-fetch-mock` 提供了你已經熟悉的相同 `fetchMock` API。
4
+
5
+ ## API 對照
6
+
7
+ | cloudflare:test | msw-fetch-mock |
8
+ | -------------------------------------------------- | ----------------------------------------------------------- |
9
+ | `import { fetchMock } from 'cloudflare:test'` | `import { fetchMock } from 'msw-fetch-mock'` |
10
+ | `fetchMock.activate()` | `await fetchMock.activate()` |
11
+ | `fetchMock.disableNetConnect()` | `fetchMock.disableNetConnect()` |
12
+ | `fetchMock.enableNetConnect(matcher?)` | `fetchMock.enableNetConnect(matcher?)` |
13
+ | `fetchMock.deactivate()` | `fetchMock.deactivate()` |
14
+ | `fetchMock.get(origin).intercept(opts).reply(...)` | `fetchMock.get(origin).intercept(opts).reply(...)` |
15
+ | `.replyWithError(error)` | `.replyWithError(error)` |
16
+ | `.reply(...).delay(ms)` | `.reply(...).delay(ms)` |
17
+ | `fetchMock.getCallHistory()` | `fetchMock.getCallHistory()` 或 `fetchMock.calls` |
18
+ | `fetchMock.clearCallHistory()` | `fetchMock.clearCallHistory()` 或 `fetchMock.calls.clear()` |
19
+ | `fetchMock.assertNoPendingInterceptors()` | `fetchMock.assertNoPendingInterceptors()` |
20
+
21
+ ## 遷移前(cloudflare:test)
22
+
23
+ ```typescript
24
+ import { fetchMock } from 'cloudflare:test';
25
+
26
+ beforeEach(() => {
27
+ fetchMock.activate();
28
+ fetchMock.disableNetConnect();
29
+ });
30
+
31
+ afterEach(() => fetchMock.assertNoPendingInterceptors());
32
+
33
+ it('呼叫 API', async () => {
34
+ fetchMock
35
+ .get('https://api.example.com')
36
+ .intercept({ path: '/data', method: 'GET' })
37
+ .reply(200, { result: 'ok' });
38
+
39
+ const res = await fetch('https://api.example.com/data');
40
+ expect(await res.json()).toEqual({ result: 'ok' });
41
+ });
42
+ ```
43
+
44
+ ## 遷移後(msw-fetch-mock)
45
+
46
+ ```typescript
47
+ import { fetchMock } from 'msw-fetch-mock';
48
+
49
+ beforeAll(async () => {
50
+ await fetchMock.activate();
51
+ });
52
+ afterAll(() => fetchMock.deactivate());
53
+ afterEach(() => {
54
+ fetchMock.assertNoPendingInterceptors();
55
+ fetchMock.reset();
56
+ });
57
+
58
+ it('呼叫 API', async () => {
59
+ fetchMock
60
+ .get('https://api.example.com')
61
+ .intercept({ path: '/data', method: 'GET' })
62
+ .reply(200, { result: 'ok' });
63
+
64
+ const res = await fetch('https://api.example.com/data');
65
+ expect(await res.json()).toEqual({ result: 'ok' });
66
+ });
67
+ ```
68
+
69
+ ## 主要差異
70
+
71
+ | 面向 | cloudflare:test | msw-fetch-mock |
72
+ | --------------- | --------------------------------------------- | ------------------------------------------------- |
73
+ | 匯入 | `import { fetchMock } from 'cloudflare:test'` | `import { fetchMock } from 'msw-fetch-mock'` |
74
+ | Server 生命週期 | 隱式(由測試框架管理) | 顯式(`activate()` / `deactivate()`) |
75
+ | 呼叫歷史存取 | `fetchMock.getCallHistory()` | `fetchMock.getCallHistory()` 或 `fetchMock.calls` |
76
+ | 呼叫歷史清理 | 每次測試自動清理 | 在 `afterEach` 中呼叫 `reset()` |
77
+ | 未處理的請求 | 必須呼叫 `disableNetConnect()` | 預設 `onUnhandledRequest: 'error'`(直接拒絕) |
78
+ | 執行環境 | Cloudflare Workers (workerd) | Node.js |
79
+
80
+ > **注意:** `getCallHistory()` 和 `clearCallHistory()` 是為了 Cloudflare 相容性而提供的別名。你可以使用 Cloudflare 風格的方法或 `fetchMock.calls` getter — 兩者是等價的。
@@ -0,0 +1,94 @@
1
+ # MSW v1 Legacy 指南
2
+
3
+ 如果你正在使用 MSW v1(`msw@^1.x`),請使用 `msw-fetch-mock/legacy` 子路徑匯出。API 與 v2 版本相同 — 只有設定方式不同。
4
+
5
+ ## 安裝
6
+
7
+ ```bash
8
+ npm install -D msw-fetch-mock msw@^1
9
+ ```
10
+
11
+ ## 設定
12
+
13
+ ```typescript
14
+ import { rest } from 'msw';
15
+ import { setupServer } from 'msw/node';
16
+ import { createFetchMock } from 'msw-fetch-mock/legacy';
17
+
18
+ const server = setupServer();
19
+ const fetchMock = createFetchMock(rest, server);
20
+
21
+ beforeAll(() => fetchMock.activate());
22
+ afterAll(() => fetchMock.deactivate());
23
+ afterEach(() => {
24
+ fetchMock.assertNoPendingInterceptors();
25
+ fetchMock.reset();
26
+ });
27
+
28
+ it('模擬 GET 請求', async () => {
29
+ fetchMock
30
+ .get('https://api.example.com')
31
+ .intercept({ path: '/users', method: 'GET' })
32
+ .reply(200, { users: [{ id: '1', name: 'Alice' }] });
33
+
34
+ const res = await fetch('https://api.example.com/users');
35
+ const data = await res.json();
36
+
37
+ expect(data.users).toHaveLength(1);
38
+ });
39
+ ```
40
+
41
+ ## API 對照
42
+
43
+ | MSW v2(`msw-fetch-mock`) | MSW v1(`msw-fetch-mock/legacy`) |
44
+ | -------------------------------------------- | ---------------------------------------------- |
45
+ | `import { fetchMock } from 'msw-fetch-mock'` | 無單例 — 必須使用 `createFetchMock` |
46
+ | `import { createFetchMock } from '.../node'` | `import { createFetchMock } from '.../legacy'` |
47
+ | `createFetchMock(server?)` | `createFetchMock(rest, server?)` |
48
+ | `import { http } from 'msw'` | `import { rest } from 'msw'` |
49
+
50
+ ## 主要差異
51
+
52
+ | 面向 | MSW v2 | MSW v1(Legacy) |
53
+ | ---------------- | ----------------------------------------- | --------------------------------- |
54
+ | 匯入 | `msw-fetch-mock` 或 `msw-fetch-mock/node` | `msw-fetch-mock/legacy` |
55
+ | 工廠函式 | `createFetchMock(server?)` | `createFetchMock(rest, server?)` |
56
+ | 單例 | `fetchMock` 預建實例 | 不提供 — 使用 `createFetchMock` |
57
+ | Handler 內部實作 | 使用 `http.*` + `HttpResponse` | 使用 `rest.*` + `(req, res, ctx)` |
58
+ | MSW 版本 | `msw@^2.12.7` | `msw@^1.0.0` |
59
+
60
+ ## 匯出項目
61
+
62
+ `msw-fetch-mock/legacy` 子路徑匯出:
63
+
64
+ | 匯出 | 類型 | 說明 |
65
+ | -------------------------------- | ---- | ----------------------------------- |
66
+ | `createFetchMock(rest, server?)` | 函式 | 建立適用於 MSW v1 的 FetchMock 實例 |
67
+ | `FetchMock` | 類別 | 核心模擬類別(與 v2 相同) |
68
+ | `createLegacyHandlerFactory` | 函式 | 低階:建立 v1 相容的 handler 工廠 |
69
+ | `LegacyRestApi` | 型別 | MSW v1 的 `rest` 物件型別 |
70
+
71
+ ## 從 MSW v1 遷移到 v2
72
+
73
+ 當你將 MSW 從 v1 升級到 v2 時,更新你的匯入:
74
+
75
+ ```diff
76
+ - import { rest } from 'msw';
77
+ - import { createFetchMock } from 'msw-fetch-mock/legacy';
78
+ - const fetchMock = createFetchMock(rest, server);
79
+ + import { createFetchMock } from 'msw-fetch-mock/node';
80
+ + const fetchMock = createFetchMock(server);
81
+ ```
82
+
83
+ 或使用單例進行獨立模式:
84
+
85
+ ```diff
86
+ - import { rest } from 'msw';
87
+ - import { setupServer } from 'msw/node';
88
+ - import { createFetchMock } from 'msw-fetch-mock/legacy';
89
+ - const server = setupServer();
90
+ - const fetchMock = createFetchMock(rest, server);
91
+ + import { fetchMock } from 'msw-fetch-mock';
92
+ ```
93
+
94
+ 其餘 API(`get()`、`intercept()`、`reply()`、`calls` 等)維持不變。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "msw-fetch-mock",
3
- "version": "0.3.3",
3
+ "version": "0.4.0",
4
4
  "description": "Undici-style fetch mock API built on MSW (Mock Service Worker)",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -57,6 +57,15 @@
57
57
  },
58
58
  "import": "./dist/legacy.js",
59
59
  "require": "./dist/legacy.cjs"
60
+ },
61
+ "./native": {
62
+ "source": "./src/native.ts",
63
+ "types": {
64
+ "import": "./dist/native.d.ts",
65
+ "require": "./dist/native.d.cts"
66
+ },
67
+ "import": "./dist/native.js",
68
+ "require": "./dist/native.cjs"
60
69
  }
61
70
  },
62
71
  "files": [
@@ -81,6 +90,11 @@
81
90
  "peerDependencies": {
82
91
  "msw": "^1.0.0 || ^2.12.7"
83
92
  },
93
+ "peerDependenciesMeta": {
94
+ "msw": {
95
+ "optional": true
96
+ }
97
+ },
84
98
  "devDependencies": {
85
99
  "@eslint/js": "^9.39.2",
86
100
  "eslint": "^9.39.2",