Skip to content

Commit 2229fe0

Browse files
committed
test: add test
1 parent a4af39d commit 2229fe0

13 files changed

Lines changed: 2649 additions & 320 deletions

File tree

.kiro/specs/vitest-unit-testing/design.md

Lines changed: 582 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# 需求文档
2+
3+
## 简介
4+
5+
`network-debugger` 包引入 Vitest 测试框架,实现无需浏览器的单元测试环境,目标是达到主线程代码(`src/core/`)和子线程代码(`src/fork/`)100% 的单元测试覆盖率。
6+
7+
## 术语表
8+
9+
- **Vitest**: 基于 Vite 的现代化测试框架,支持 TypeScript 和 ESM
10+
- **Test_Runner**: Vitest 测试运行器,负责执行测试用例
11+
- **Coverage_Reporter**: 覆盖率报告生成器,用于统计代码覆盖率
12+
- **Mock_System**: 模拟系统,用于模拟外部依赖(如 WebSocket、HTTP、文件系统等)
13+
- **Main_Thread_Code**: 主线程代码,位于 `src/core/` 目录,包含请求代理、fetch 拦截等功能
14+
- **Fork_Thread_Code**: 子线程/fork 代码,位于 `src/fork/` 目录,包含 DevTools 服务器、请求中心等功能
15+
- **Unit_Test**: 单元测试,针对单个函数或类的独立测试
16+
- **Coverage_Threshold**: 覆盖率阈值,测试必须达到的最低覆盖率百分比
17+
- **CDP**: Chrome DevTools Protocol,Chrome 开发者工具协议,用于与 DevTools 前端通信
18+
- **CDP_Message**: CDP 消息,包含 method、params、id、result、error 等字段
19+
- **Request_Lifecycle**: 请求生命周期,从请求发起到完成的完整过程
20+
- **Message_Ordering**: 消息顺序,CDP 消息必须按照协议规定的顺序发送
21+
22+
## 需求
23+
24+
### 需求 1:Vitest 测试框架配置
25+
26+
**用户故事:** 作为开发者,我希望配置 Vitest 测试框架,以便能够运行无需浏览器的单元测试。
27+
28+
#### 验收标准
29+
30+
1. THE Test_Runner SHALL 支持 TypeScript 文件的直接测试,无需预编译
31+
2. THE Test_Runner SHALL 支持 ESM 模块格式
32+
3. THE Test_Runner SHALL 配置 Node.js 环境而非浏览器环境
33+
4. WHEN 运行 `pnpm test` 命令时,THE Test_Runner SHALL 执行所有 `.test.ts` 后缀的测试文件
34+
5. THE Coverage_Reporter SHALL 生成覆盖率报告,包含行覆盖率、分支覆盖率和函数覆盖率
35+
6. THE Coverage_Reporter SHALL 配置 100% 的覆盖率阈值
36+
37+
### 需求 2:Mock 系统配置
38+
39+
**用户故事:** 作为开发者,我希望能够模拟外部依赖,以便在不依赖真实网络和浏览器的情况下进行测试。
40+
41+
#### 验收标准
42+
43+
1. THE Mock_System SHALL 支持模拟 WebSocket 连接
44+
2. THE Mock_System SHALL 支持模拟 HTTP/HTTPS 请求
45+
3. THE Mock_System SHALL 支持模拟 Node.js 子进程(child_process.fork)
46+
4. THE Mock_System SHALL 支持模拟文件系统操作
47+
5. THE Mock_System SHALL 支持模拟 `open` 包(用于打开浏览器)
48+
6. WHEN 测试需要模拟外部依赖时,THE Mock_System SHALL 提供清晰的 mock 接口
49+
50+
### 需求 3:主线程代码单元测试
51+
52+
**用户故事:** 作为开发者,我希望为主线程代码编写单元测试,以确保请求拦截和代理功能的正确性。
53+
54+
#### 验收标准
55+
56+
1. THE Unit_Test SHALL 覆盖 `src/core/index.ts` 中的 `register` 函数
57+
2. THE Unit_Test SHALL 覆盖 `src/core/fetch.ts` 中的 `proxyFetch``fetchProxyFactory` 函数
58+
3. THE Unit_Test SHALL 覆盖 `src/core/request.ts` 中的 `requestProxyFactory` 函数
59+
4. THE Unit_Test SHALL 覆盖 `src/core/fork.ts` 中的 `MainProcess`
60+
5. THE Unit_Test SHALL 覆盖 `src/core/undici.ts` 中的 `undiciFetchProxy` 函数
61+
6. THE Unit_Test SHALL 覆盖 `src/core/hooks/` 目录下的所有 hook 函数
62+
7. THE Unit_Test SHALL 覆盖 `src/core/ws/` 目录下的 WebSocket 相关工具函数
63+
8. WHEN 测试主线程代码时,THE Unit_Test SHALL 验证请求拦截的正确性
64+
9. WHEN 测试主线程代码时,THE Unit_Test SHALL 验证请求数据的正确传递
65+
66+
### 需求 4:子线程代码单元测试
67+
68+
**用户故事:** 作为开发者,我希望为子线程代码编写单元测试,以确保 DevTools 服务和请求处理的正确性。
69+
70+
#### 验收标准
71+
72+
1. THE Unit_Test SHALL 覆盖 `src/fork/request-center.ts` 中的 `RequestCenter`
73+
2. THE Unit_Test SHALL 覆盖 `src/fork/resource-service.ts` 中的 `ResourceService``ScriptMap`
74+
3. THE Unit_Test SHALL 覆盖 `src/fork/devtool/index.ts` 中的 `DevtoolServer`
75+
4. THE Unit_Test SHALL 覆盖 `src/fork/devtool/type.ts` 中的 `BaseDevtoolServer`
76+
5. THE Unit_Test SHALL 覆盖 `src/fork/module/` 目录下的所有插件模块
77+
6. THE Unit_Test SHALL 覆盖 `src/fork/pipe/` 目录下的所有转换器
78+
7. WHEN 测试子线程代码时,THE Unit_Test SHALL 验证 DevTools 消息的正确处理
79+
8. WHEN 测试子线程代码时,THE Unit_Test SHALL 验证请求数据的正确转换
80+
81+
### 需求 5:工具函数单元测试
82+
83+
**用户故事:** 作为开发者,我希望为工具函数编写单元测试,以确保基础功能的正确性。
84+
85+
#### 验收标准
86+
87+
1. THE Unit_Test SHALL 覆盖 `src/utils/call-site.ts` 中的 `CallSite`
88+
2. THE Unit_Test SHALL 覆盖 `src/utils/stack.ts` 中的 `getStackFrames``initiatorStackPipe` 函数
89+
3. THE Unit_Test SHALL 覆盖 `src/utils/header.ts` 中的所有头部处理函数
90+
4. THE Unit_Test SHALL 覆盖 `src/utils/json.ts` 中的 `jsonParse` 函数
91+
5. THE Unit_Test SHALL 覆盖 `src/utils/map.ts` 中的 `headersToObject` 函数
92+
6. THE Unit_Test SHALL 覆盖 `src/utils/generate.ts` 中的 `generateUUID``generateHash` 函数
93+
7. THE Unit_Test SHALL 覆盖 `src/utils/file.ts` 中的 `unlinkSafe` 函数
94+
8. THE Unit_Test SHALL 覆盖 `src/utils/process.ts` 中的 `sleep``checkMainProcessAlive` 函数
95+
9. THE Unit_Test SHALL 覆盖 `src/common.ts` 中的 `RequestDetail`
96+
97+
### 需求 6:测试覆盖率要求
98+
99+
**用户故事:** 作为开发者,我希望确保测试覆盖率达到 100%,以保证代码质量。
100+
101+
#### 验收标准
102+
103+
1. THE Coverage_Reporter SHALL 报告主线程代码(`src/core/`)的覆盖率达到 100%
104+
2. THE Coverage_Reporter SHALL 报告子线程代码(`src/fork/`)的覆盖率达到 100%
105+
3. THE Coverage_Reporter SHALL 报告工具函数(`src/utils/`)的覆盖率达到 100%
106+
4. THE Coverage_Reporter SHALL 报告公共模块(`src/common.ts`)的覆盖率达到 100%
107+
5. IF 覆盖率低于 100%,THEN THE Test_Runner SHALL 报告测试失败
108+
6. THE Coverage_Reporter SHALL 生成 HTML 格式的覆盖率报告以便查看详情
109+
110+
### 需求 7:CDP 协议正确性测试
111+
112+
**用户故事:** 作为开发者,我希望验证 CDP 协议消息的顺序一致性和属性正确性,以确保与 Chrome DevTools 的兼容性。
113+
114+
#### 验收标准
115+
116+
1. THE Unit_Test SHALL 验证 HTTP 请求生命周期的 CDP 消息顺序:`Network.requestWillBeSent``Network.responseReceived``Network.dataReceived``Network.loadingFinished`
117+
2. THE Unit_Test SHALL 验证同一请求的所有 CDP 消息中 `requestId` 保持一致
118+
3. THE Unit_Test SHALL 验证 WebSocket 生命周期的 CDP 消息顺序:`Network.requestWillBeSent``Network.webSocketCreated``Network.webSocketWillSendHandshakeRequest``Network.webSocketHandshakeResponseReceived``Network.webSocketFrameSent/Received``Network.webSocketClosed`
119+
4. THE Unit_Test SHALL 验证 `requestId` 在整个会话中的全局唯一性
120+
5. THE Unit_Test SHALL 验证同一请求的 CDP 消息序列中 `timestamp` 单调递增
121+
6. THE Unit_Test SHALL 验证 `Debugger.scriptParsed` 消息包含有效的 `scriptId``url`,且可通过 `Debugger.getScriptSource` 获取源代码
122+
7. THE Unit_Test SHALL 验证带有 `id` 的请求消息的响应包含相同的 `id` 字段,以及 `result``error` 字段
123+
8. THE Unit_Test SHALL 验证 `initiator.stack.callFrames` 中的调用帧包含有效的位置信息和 `scriptId`(如果脚本已解析)
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
# 实施任务
2+
3+
## 任务 1: Vitest 测试框架配置
4+
5+
- [x] 1.1 安装 Vitest 及相关依赖
6+
7+
- 安装 `vitest``@vitest/coverage-v8``fast-check` 到 devDependencies
8+
- 更新 `package.json` 添加测试脚本命令
9+
10+
- [x] 1.2 创建 Vitest 配置文件
11+
12+
- 创建 `vitest.config.ts` 配置文件
13+
- 配置 Node.js 环境、测试文件匹配模式
14+
- 配置 100% 覆盖率阈值
15+
16+
- [x] 1.3 配置 TypeScript 支持
17+
- 确保 Vitest 可以直接运行 TypeScript 测试文件
18+
- 配置路径别名支持
19+
20+
## 任务 2: Mock 系统配置(使用第三方库)
21+
22+
- [x] 2.1 配置 Mock 策略
23+
- 使用 vitest 内置 `vi.mock()`, `vi.spyOn()`, `vi.fn()`
24+
- 安装 `memfs` 用于文件系统 mock
25+
- 创建测试辅助工具 `test-utils.ts`
26+
27+
## 任务 3: 工具函数单元测试
28+
29+
- [ ] 3.1 编写 `call-site.ts` 测试
30+
31+
- 测试 `CallSite` 类的所有方法
32+
- 迁移现有测试到新框架
33+
34+
- [ ] 3.2 编写 `stack.ts` 测试
35+
36+
- 测试 `getStackFrames` 函数
37+
- 测试 `initiatorStackPipe` 函数
38+
- 迁移现有测试到新框架
39+
40+
- [ ] 3.3 编写 `header.ts` 测试
41+
42+
- 测试所有头部处理函数
43+
- 测试边界情况
44+
45+
- [ ] 3.4 编写 `json.ts` 测试
46+
47+
- 测试 `jsonParse` 函数
48+
- 测试有效/无效 JSON 输入
49+
50+
- [ ] 3.5 编写 `map.ts` 测试
51+
52+
- 测试 `headersToObject` 函数
53+
- 测试各种 Headers 输入
54+
55+
- [ ] 3.6 编写 `generate.ts` 测试
56+
57+
- 测试 `generateUUID` 函数唯一性
58+
- 测试 `generateHash` 函数一致性
59+
60+
- [ ] 3.7 编写 `file.ts` 测试
61+
62+
- 测试 `unlinkSafe` 函数
63+
- 测试文件不存在时的静默处理
64+
65+
- [ ] 3.8 编写 `process.ts` 测试
66+
67+
- 测试 `sleep` 函数
68+
- 测试 `checkMainProcessAlive` 函数
69+
70+
- [ ] 3.9 编写 `common.ts` 测试
71+
- 测试 `RequestDetail`
72+
- 迁移现有测试到新框架
73+
74+
## 任务 4: 主线程代码单元测试
75+
76+
- [ ] 4.1 编写 `core/index.ts` 测试
77+
78+
- 测试 `register` 函数
79+
- 测试请求拦截注册流程
80+
81+
- [ ] 4.2 编写 `core/fetch.ts` 测试
82+
83+
- 测试 `proxyFetch` 函数
84+
- 测试 `fetchProxyFactory` 函数
85+
86+
- [ ] 4.3 编写 `core/request.ts` 测试
87+
88+
- 测试 `requestProxyFactory` 函数
89+
- 测试 HTTP/HTTPS 请求代理
90+
91+
- [ ] 4.4 编写 `core/fork.ts` 测试
92+
93+
- 测试 `MainProcess`
94+
- 测试子进程通信
95+
96+
- [ ] 4.5 编写 `core/undici.ts` 测试
97+
98+
- 测试 `undiciFetchProxy` 函数
99+
- 测试 undici fetch 拦截
100+
101+
- [ ] 4.6 编写 `core/hooks/` 测试
102+
103+
- 测试 `cell.ts` 中的 Cell 类
104+
- 测试 `useAbortRequest.ts`
105+
- 测试 `useRegisterRequest.ts`
106+
- 测试 `useRequestPipe.ts`
107+
108+
- [ ] 4.7 编写 `core/ws/` 测试
109+
- 测试 `buffer-util.ts`
110+
- 测试 `constants.ts`
111+
- 测试 `limiter.ts`
112+
- 测试 `permessage-deflate.ts`
113+
- 测试 `receiver.ts`
114+
- 测试 `validation.ts`
115+
116+
## 任务 5: 子线程代码单元测试
117+
118+
- [ ] 5.1 编写 `fork/request-center.ts` 测试
119+
120+
- 测试 `RequestCenter`
121+
- 测试插件加载和消息分发
122+
123+
- [ ] 5.2 编写 `fork/resource-service.ts` 测试
124+
125+
- 测试 `ResourceService`
126+
- 测试 `ScriptMap`
127+
128+
- [ ] 5.3 编写 `fork/devtool/` 测试
129+
130+
- 测试 `DevtoolServer`
131+
- 测试 `BaseDevtoolServer`
132+
133+
- [ ] 5.4 编写 `fork/module/` 测试
134+
135+
- 测试 `common.ts` 中的插件工具
136+
- 测试 `health` 插件
137+
- 测试 `network` 插件
138+
- 测试 `debugger` 插件
139+
- 测试 `websocket` 插件
140+
141+
- [ ] 5.5 编写 `fork/pipe/` 测试
142+
- 测试 `BodyTransformer`
143+
- 测试 `RequestHeaderPipe`
144+
145+
## 任务 6: CDP 协议正确性测试
146+
147+
- [ ] 6.1 编写 HTTP 请求生命周期顺序测试
148+
149+
- 验证 `Network.requestWillBeSent``Network.responseReceived``Network.dataReceived``Network.loadingFinished` 顺序
150+
- 使用属性测试验证任意请求的消息顺序
151+
152+
- [ ] 6.2 编写 WebSocket 生命周期顺序测试
153+
154+
- 验证 WebSocket 相关 CDP 消息的正确顺序
155+
- 测试握手、帧传输、关闭的完整流程
156+
157+
- [ ] 6.3 编写 requestId 一致性测试
158+
159+
- 验证同一请求的所有消息中 requestId 一致
160+
- 验证 requestId 全局唯一性
161+
162+
- [ ] 6.4 编写 timestamp 单调递增测试
163+
164+
- 验证同一请求的消息序列中 timestamp 单调递增
165+
- 使用属性测试验证任意消息序列
166+
167+
- [ ] 6.5 编写 Debugger 消息正确性测试
168+
169+
- 验证 `Debugger.scriptParsed` 消息格式
170+
- 验证 `Debugger.getScriptSource` 响应正确性
171+
172+
- [ ] 6.6 编写 CDP 响应格式测试
173+
174+
- 验证带 id 的请求响应包含相同 id
175+
- 验证 result/error 字段格式
176+
177+
- [ ] 6.7 编写 initiator 调用栈测试
178+
- 验证 callFrames 包含有效位置信息
179+
- 验证 scriptId 正确关联
180+
181+
## 任务 7: 属性测试实现
182+
183+
- [ ] 7.1 实现 Property 7: JSON 解析往返一致性
184+
185+
- 使用 fast-check 生成任意有效 JSON
186+
- 验证解析后再序列化的等价性
187+
188+
- [ ] 7.2 实现 Property 8: Headers 转换完整性
189+
190+
- 使用 fast-check 生成任意 Headers
191+
- 验证转换后包含所有原始键值对
192+
193+
- [ ] 7.3 实现 Property 9: UUID 唯一性
194+
195+
- 生成大量 UUID 验证唯一性
196+
- 使用属性测试验证
197+
198+
- [ ] 7.4 实现 Property 10: Hash 一致性
199+
200+
- 验证相同输入产生相同 hash
201+
- 验证不同输入产生不同 hash
202+
203+
- [ ] 7.5 实现 Property 11: RequestHeaderPipe 大小写不敏感
204+
205+
- 使用 fast-check 生成任意头部名称
206+
- 验证大小写不敏感查询
207+
208+
- [ ] 7.6 实现 Property 13-19: CDP 协议属性测试
209+
- 实现 HTTP 请求生命周期消息顺序属性测试
210+
- 实现 WebSocket 生命周期消息顺序属性测试
211+
- 实现 requestId 一致性属性测试
212+
- 实现 timestamp 单调递增属性测试
213+
214+
## 任务 8: 覆盖率验证和文档
215+
216+
- [ ] 8.1 运行完整测试套件
217+
218+
- 执行所有测试
219+
- 生成覆盖率报告
220+
221+
- [ ] 8.2 验证 100% 覆盖率
222+
223+
- 检查 src/core/ 覆盖率
224+
- 检查 src/fork/ 覆盖率
225+
- 检查 src/utils/ 覆盖率
226+
- 检查 src/common.ts 覆盖率
227+
228+
- [ ] 8.3 补充缺失的测试
229+
- 根据覆盖率报告补充测试
230+
- 确保所有分支都被覆盖

.kiro/steering/lang.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
inclusion: always
3+
---
4+
5+
请输出中文
6+
7+
1. 遵循 TypeScript 编写原则,禁止使用 as unknown as xxx、as any、@ts-ignore 等容易导致运行时问题的语法

packages/network-debugger/package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
},
2121
"scripts": {
2222
"test": "vitest",
23+
"test:coverage": "vitest run --coverage",
24+
"test:watch": "vitest --watch",
2325
"build": "vite build",
2426
"dev": "vite build --watch --mode development"
2527
},
@@ -50,11 +52,14 @@
5052
"@types/ws": "^8.5.10",
5153
"@typescript-eslint/eslint-plugin": "^6.14.0",
5254
"@typescript-eslint/parser": "^6.14.0",
55+
"@vitest/coverage-v8": "^4.0.18",
5356
"envinfo": "^7.14.0",
57+
"fast-check": "^4.5.3",
58+
"memfs": "^4.56.10",
5459
"tslib": "2.6.2",
5560
"vite": "^5.2.10",
5661
"vite-plugin-dts": "^3.8.3",
57-
"vitest": "^2.0.3"
62+
"vitest": "^4.0.18"
5863
},
5964
"dependencies": {
6065
"bufferutil": "^4.0.9",

0 commit comments

Comments
 (0)