# v4.3 路径启用/禁用 + E2E 测试 — 设计文档

**日期**: 2026-05-27
**分支**: v4.2（v4.3 后续创建）
**状态**: 已确认

## 概述

两项独立改进：
1. 路径启用/禁用（软开关）：`string[]` → `PathEntry[]`，禁用状态存 JSON 文件
2. E2E 测试：Playwright + Mock IPC，覆盖 4 条关键流程

---

## Part 1: 路径启用/禁用

### 数据模型

```typescript
// src/core/path-entry.ts (新增)
export interface PathEntry {
  path: string;
  enabled: boolean;
}
```

全栈从 `string[]` 迁移到 `PathEntry[]`。注册表读写时做转换。

### 禁用状态持久化

文件：`%APPDATA%/PathEditor/disabled.json`
格式：`{ "system": ["path1"], "user": ["path2"] }`

加载流程：注册表读取 → `PathEntry[]`（全部 enabled:true）→ 读取 disabled.json → 匹配到的标记 enabled:false

保存流程：只将 enabled:true 的 path join 后写入注册表

切换流程：复选框点击 → 更新内存状态 → 立即调用 `save_disabled_state` 写入 JSON

### 新增 Rust 命令

- `save_disabled_state(system: Vec<String>, user: Vec<String>) -> Result<(), String>`
- `load_disabled_state() -> Result<Vec<String>, Vec<String>, String>` 返回 `(system_disabled, user_disabled)`

### Undo 适配

- `OpRecord.oldPaths` / `newPaths` 从 `string[]` 改为 `PathEntry[]`
- 新增 `OperationType.TOGGLE = 8`：单条路径切换启用/禁用，undo 翻转回去
- 8 种已有操作类型的 switch case 适配 `PathEntry`

### UI

- 路径列表每行前加复选框，`#` 序号列与复选框合并
- 禁用行：灰色文字 + 删除线（`text-decoration: line-through`）
- 工具栏不新增按钮（复选框独立操作）

### 状态层

- `app-store.ts` 新增 `togglePath(index, target)` 方法
- `loadPaths` 加载时合并 disabled 状态
- `savePaths` 保存时过滤 disabled 路径

---

## Part 2: E2E 测试

### 技术选型

`@playwright/test`，独立于 Vitest。Mock Tauri IPC 通过 `page.addInitScript()` 注入。

### Mock IPC

页面加载前注入 `window.__TAURI_INTERNALS__.invoke` 的 mock 实现，按命令名返回假数据。

### 4 条测试场景

| 场景 | 步骤 |
|------|------|
| 启动加载 | 访问页面 → 系统 PATH 显示 2 条 → 用户 PATH 显示 1 条 |
| CRUD + 撤销 | 添加路径 → 出现在列表 → Ctrl+Z 撤销 → 路径消失 → Ctrl+Y 重做 → 路径恢复 |
| 禁用 + 保存 | 点击复选框禁用 → 路径灰显+删除线 → 点保存 → 验证 save IPC 只传了 enabled 路径 |
| 搜索 + 清理 | 输入搜索词 → 列表过滤 → 清空搜索 → 点清理 → 无效路径红色 |

### 运行方式

```bash
npx playwright test
```

需要先启动 Vite 开发服务器：`npm run dev`
