feat: 解码 worker 化、Playwright E2E 测试体系与文件夹对比(0.6.0)

This commit is contained in:
2026-08-18 14:40:44 +08:00
parent 2b43b5e676
commit be619c2377
24 changed files with 2030 additions and 151 deletions
+50 -12
View File
@@ -18,11 +18,11 @@
| 层级 | 覆盖对象 | 工具 |
| --- | --- | --- |
| 单元测试(UT) | 纯逻辑:diff 引擎、报告生成器 | Vitest |
| 组件测试 | React 组件:应用空态、工具栏交互 | Vitest + Testing Library |
| 集成(演进中) | Electron IPC / 多进程协作 | 预留 Playwright 或 Electron 测试 |
| 单元测试(UT) | 纯逻辑:diff 引擎、报告生成器、解码探测、文件夹扫描 | Vitest |
| 组件测试 | React 组件:应用空态、工具栏交互、文件夹视图 | Vitest + Testing Library |
| E2E0.6.0 起) | 构建产物真实 Electron:主进程解码/写盘/文件夹扫描/偏好重启 | Playwright |
> 现阶段以**单元 + 组件**为主,覆盖核心、最易回归的部分
> 单元 + 组件覆盖核心逻辑与交互;E2E 覆盖 jsdom 无法触达的主进程真实链路(mock `window.api` 测不到的部分),发布前必跑
---
@@ -34,7 +34,7 @@
| 环境 | jsdom |
| React 测试 | @testing-library/react |
| 断言扩展 | @testing-library/jest-dom |
| 未来 E2E | Playwright预留,暂不引入 |
| E2E | Playwright`_electron` 模式,复用项目自带 Electron,无需下载浏览器 |
---
@@ -42,8 +42,17 @@
```
vitest.config.ts # Vitest 配置(jsdom + 测试范围 + 覆盖率 80% 硬门禁)
playwright.config.ts # Playwright E2E 配置(对 out/ 产物启动真实 Electron,发布前必跑)
e2e/
├── helpers.ts # E2E 辅助(启动应用/对话框 stub/临时 fixture/粘贴入口)
└── app.spec.ts # E2E 用例(启动/粘贴/编码链路/选项/导航/导出写盘/文件夹对比/偏好重启)
src/main/
├── index.ts # 主进程入口(依赖 electron 运行时,覆盖率排除,随发布人工自测
├── index.ts # 主进程入口(依赖 electron 运行时,覆盖率排除,真实链路由 E2E 覆盖
├── decode.ts # 解码与编码探测纯逻辑(Uint8Array 入参,同步与 worker 路径共用)
├── decode.test.ts # 解码单元测试(BOM 三种/严格 UTF-8/GBK 回退/二进制启发式)
├── decodeWorker.ts # 解码 worker_threads 入口(覆盖率排除,逻辑由 decode 测试覆盖)
├── folderScan.ts # 文件夹对比纯逻辑(递归枚举/对齐/字节判定/采样近似)
├── folderScan.test.ts # 文件夹扫描单元测试(真实临时目录:状态判定/递归/symlink/截断/近似)
├── windowState.ts # 应用状态持久化纯逻辑(bounds 校验/钳制,无 electron 依赖)
└── windowState.test.ts # 应用状态单元测试(解析回退/工作区钳制/最小尺寸)
src/renderer/src/
@@ -63,10 +72,11 @@ src/renderer/src/
├── components/
│ ├── ContextMenu.test.tsx # 右键菜单(含边缘防溢出)
│ ├── DiffView.test.tsx # 对比视图(渲染/滚动同步/右键/拖放)
│ ├── FolderView.test.tsx # 文件夹视图(统计/过滤/双击/虚拟滚动/截断与空态提示)
│ ├── TextInputModal.test.tsx # 粘贴文本弹窗
│ └── Toolbar.test.tsx # 工具栏(选项/导航/导出菜单向上弹出/计算中禁用/字符级开关与空白选项联动灰显勾选+已包含徽标+点击解释+已降级标记)
└── __tests__/
├── App.test.tsx # 应用集成级测试(加载/拖拽/粘贴/导出/容错/toast 队列/清空确认/状态栏行数/大输入回退)
├── App.test.tsx # 应用集成级测试(加载/拖拽/粘贴/导出/容错/toast 队列/清空确认/状态栏行数/大输入回退/文件夹模式进出与双击
└── main.test.ts # 入口挂载冒烟测试
```
@@ -120,6 +130,7 @@ src/renderer/src/
- 字符级对比:跨行重组开启后判为完全一致;开启时三个空白选项灰显勾选并带"已包含"徽标,点击弹出解释提示,关闭后恢复用户原勾选状态;内容超限自动降级并 toast 提示(开关旁常显"已降级"标记);导出报告携带字符级说明;降级后报告按实际生效的行级语义描述选项
- 忽略所有空白:仅行内空白不同的两侧文本开启后判为完全一致;导出报告携带比较选项说明
- 大输入(超快路径阈值)在无 Worker 环境去抖到期后回退同步计算,完成后无计算中遮罩
- 文件夹模式:依次选择两侧目录进入(路径卡片/统计徽章/状态栏切换/默认仅看差异过滤 same) · 任一次选择取消不进入 · 扫描失败 toast 且不进入 · 双击差异条目加载两侧进入单文件对比并可返回文件夹(返回清空两侧面板) · 双击单侧条目加载存在侧并清空另一侧 · 「返回文件对比」清空文件夹状态回单文件空态
### 5.6 diff 计算 worker 化(`useDiff.ts` / `createDiffWorker.ts`
- 快路径:两侧总行数不超过 2000 时同步计算,不创建 worker,结果与 computeDiff 一致
@@ -134,15 +145,42 @@ src/renderer/src/
### 5.7 应用状态持久化(`src/main/windowState.ts`
- parseState:空输入/非法 JSON 回退空状态;合法 bounds 与 lastDir 保留;字段类型异常(非矩形/非字符串/空串/非有限数值)防御性忽略
- clampBounds:工作区内合法 bounds 原样保留;小于最小尺寸钳到最小值;超出工作区封顶;移出屏幕四向拉回(至少 60px 进入工作区);多显示器偏移工作区同样钳制;非整数取整;工作区小于最小尺寸时尺寸仍保持最小值
- 磁盘读写与窗口事件绑定在主进程入口(覆盖率排除,随发布人工自测
- 磁盘读写与窗口事件绑定在主进程入口(覆盖率排除,真实链路由 E2E 覆盖
### 5.8 解码与编码探测(`src/main/decode.ts`
- looksBinary:空输入 / NUL 立即判定 / 纯可见 ASCII / 控制字符占比超 5% / 常见空白不计入
- decodeTextUTF-8 BOM(剥离 BOM + 标注)/ UTF-16 LE 与 BE BOM / 仅 BOM 无内容 / 短于 BOM 长度走严格 UTF-8 路径 / 无 BOM 合法 UTF-8 与纯 ASCII / GBK 中文回退解码正确 / 空输入 / 含 NUL 非法 UTF-8 的 GBK 回退 + 二进制判定 / 替换符占比超 5% 判二进制
- worker 调度(阈值分流/崩溃回退)在主进程入口(覆盖率排除,大文件 worker 链路由 E2E 覆盖)
### 5.9 文件夹扫描(`src/main/folderScan.ts`,真实临时目录)
- 状态判定:内容一致 same / 同大小内容不同 different / 大小不同 different / 单侧缺失 only(另一侧大小 null)
- 递归子目录按相对路径对齐(统一 / 分隔);二进制内容字节级判定;symlink 跳过;条目字典序排序;total 取两侧较大值
- 边界与选项:两个空目录 / 目录不存在抛异常(IPC 层转错误结果) / maxFiles 截断(truncated + total + 条目数受限) / 超 maxContentBytes 同大小文件头部采样一致判 same 带 approximate / 采样头部不同直接 different
### 5.10 文件夹视图(`FolderView.tsx`
- 渲染:目录路径卡片 / 重新选择与返回按钮 / 统计徽章(相同/不同/仅左/仅右/总数)
- 过滤:仅看差异隐藏 same、关闭展示全部;双击回调携带原始条目;大小格式化(B/KB 与缺失占位);approximate 渲染 ≈ 标注;截断提示;空态提示(无文件 / 全部一致)
- 虚拟滚动:大列表仅渲染可见窗口、容器总高度按全部条目撑满
### 5.11 E2E 端到端(`e2e/app.spec.ts`,对 build 产物启动真实 Electron
- 启动冒烟:标题与双空态面板、空态无导出入口
- 粘贴两侧:差异渲染 + 统计徽章(主进程剪贴板链路)
- 编码链路:GBK 与 UTF-8 BOM 文件打开(编码标注 + 内容渲染)、大体积 GBK 文件经解码 worker 后台解码完整渲染(状态栏总行数断言)
- 比较选项:忽略大小写与忽略所有空白组合、字符级跨行重组判一致
- 导航与视图:F7 / Shift+F7、仅看差异折叠、交换左右后面板互换
- 报告导出:stub 保存对话框 → 文件真实落盘且含结论与统计
- 文件夹对比:真实临时目录扫描(状态判定 / 默认过滤)→ 双击进入单文件对比 → 返回文件夹(扫描结果保留)
- 偏好持久化:跨实例重启恢复比较选项与视图开关(同一 userData)
- 隔离:每用例启动清空 localStorage + 重载,避免偏好跨用例污染(偏好用例验证实例显式跳过清理)
---
## 6. 运行命令
```bash
npm test # 运行全部测试(CI / 提交前)
npm test # 运行全部单元 + 组件测试(CI / 提交前)
npm run test:watch # 监听模式,开发中用
npm run test:e2e # E2E 验收(先 build 再对产物启动真实 Electron;发布前必跑)
```
---
@@ -174,9 +212,9 @@ npm run build
## 9. 演进方向(后续迭代)
- 接入 Playwright 对打包后的 Electron 应用做端到端验收
- 对 IPC 层(open / decode / save-report)补充集成测试
- 大文件性能基准测试(虚拟滚动落地后
- 文件夹对比增强(0.7.0 候选):子目录树形展示 / 按扩展名过滤 / 文件夹对比报告导出 / 语义判定(套用忽略空白等选项)
- E2E 覆盖扩展:拖拽导入链路 / 大文件性能基准
- 主进程 IPC 层补充集成测试(folder:scan 并发场景
---