---
name: test-frontend
description: 当前端 E2E 测试需要执行/修复/验证或输出报告时使用。E2E 必须通过 AI + MCP（Playwright MCP）执行，不编写测试代码；依据前端测试文档与用户场景文档。
---

# 前端测试技能（test-frontend）

## 项目概览入口
- 项目定位、技术栈与目录入口请阅读：`../references/project-overview.md`

## 定位
- **验证前后端连通性**：点按钮→调 API→数据正确回显。
- **验证前端逻辑**：多角色权限差异、组织切换后数据刷新、空数据/loading 状态处理。
- 不测视觉/布局（用户手动验收）。
- 不写测试代码（Playwright MCP 执行）。

## 适用范围
- 完整业务流程验证（如：创建周期→填 KPI→提交→审批→出结果）
- 多角色验证（admin 看到管理菜单、employee 只看到个人菜单）
- 组织切换验证（切换后数据是否刷新）
- 空数据/异常状态验证（无周期时页面不转圈、API 报错时显示友好提示）

## 工作流（顺序）
1) **前置条件**：确认后端集成测试已通过（test-backend）。不通过则本层无意义。
2) **读取业务流程编排**：读取 `10-e2e-test-spec.md` 中的业务流程剧本（不是独立用例列表）。
   - 每个流程定义了：角色、前置条件、步骤序列、每步断言
   - 流程之间有依赖关系（如流程 2 依赖流程 1 的输出）
3) **准备鉴权**：首次登录后保存 storageState，后续流程复用。
4) **按流程顺序执行**（调用时传入的流程清单全部执行，不跳过任何流程）：
   - 按流程编号顺序执行，不跳步
   - 每个流程步骤的输出作为下一步的输入（有状态连续性）
   - 每步执行后做断言，断言失败记录但继续执行后续步骤
   - 需要切换角色时，用对应账号重新登录
5) **操作后状态验证**（每个写操作后必须检查）：
   - 提交后：表单/输入框是否变为 disabled/readonly，提交按钮是否消失或变为已提交状态
   - 删除后：列表是否更新，关联数据状态是否正确（如删除已提交 KPI 后其他 KPI 是否撤回）
   - 修改后：状态标签是否正确更新（如从"待审批"变回"草稿"）
   - 切换组织后：数据是否刷新，不应该看到其他组织的数据
   - **跨页面状态联动**：模块 A 操作后，检查模块 B 的页面是否正确更新（如：员工自评完成后，切换到"待我评估"页确认评估人能看到任务）
   - 这些都可以通过 accessibility tree 验证（检查 disabled 属性、文本内容变化、元素是否存在）
6) **输出报告**：`testing/reports/{module}-{YYYY-MM-DD}-e2e-report.md`。
   - 按流程→步骤的层级结构记录结果
   - 包含每步的断言结果（通过/失败/跳过）

## MCP 元素定位规范（必须）
Playwright MCP 使用 accessibility tree snapshot 定位元素，**不使用 DOM selector**。

优先级：
1. **role + name**（如 `button "保存"`、`textbox "输入 KPI 名称"`）— 最可靠
2. **aria-label**（如 `combobox` with aria-label）
3. **文本内容**（如 heading、paragraph 中的文字）
4. **ref 引用**（snapshot 中的临时 ref=eXXX）

**不使用**：
- ~~data-testid~~（不出现在 accessibility tree 中）
- ~~CSS class / DOM 层级~~（MCP 不使用 DOM）

## 交互模式库（必须掌握）

执行 `10-e2e-test-spec.md` 中的每个步骤时，根据操作类型使用对应的交互模式。

### 模式 A：填写表单并提交

```
1. 点击触发按钮（如"创建周期"、"新增 KPI"）
2. 等待对话框/表单出现（snapshot 中出现 dialog 或新的 form 区域）
3. 逐字段填写：
   - textbox → fill（通过 label 或 placeholder 定位）
   - combobox/select → 点击触发下拉 → 等待 option 出现 → 点击目标 option
   - number input → fill 或 clear + type
   - date picker → fill 日期字符串，或点击日历选择
   - textarea → fill
4. 点击提交按钮（"保存"、"创建"、"确认"）
5. 等待成功提示（toast notification）或对话框关闭
6. 断言：新记录出现在列表中（通过文本匹配）
```

### 模式 B：切换角色

```
1. 执行 evaluate：清除 localStorage 和 sessionStorage
2. 导航到 /login
3. 等待登录表单出现
4. 填写目标角色的账号密码
5. 点击登录按钮
6. 等待跳转离开 /login（url 不再包含 /login）
7. 导航到目标页面
```

### 模式 C：状态推进（周期管理）

```
1. 导航到 /performance/cycles
2. 找到目标周期行（通过周期名称文本匹配）
3. 点击该行的操作按钮（三点菜单 / "推进" / "发布"）
4. 如果弹出菜单，点击目标操作项
5. 如果弹出确认对话框，点击"确认"/"确定"
6. 等待对话框关闭
7. 断言：该行的状态标签文本已更新
```

### 模式 D：下拉选择（combobox / select）

```
1. 点击 combobox 触发下拉面板
2. 等待 option 列表出现（listbox / option role）
3. 找到并点击目标 option（通过文本匹配）
4. 等待下拉面板关闭
5. 断言：combobox 显示值为已选文本
```

### 模式 E：列表中操作特定行

```
1. 通过文本内容定位目标行（如包含特定名称的区域）
2. 在该行中找到操作按钮（button with specific name）
3. 如果有多个同名按钮，用 nth() 或父容器范围缩小
4. 点击操作按钮
5. 处理后续交互（确认对话框、表单等）
```

### 模式 F：断言验证

```
页面级断言：
- 检查 heading / paragraph 文本内容
- 检查特定 role 元素是否存在
- 检查 button 是否 disabled

结果级断言：
- 操作后刷新页面，重新获取 snapshot
- 检查目标行的文本/状态变化
- 检查 toast notification 文本
```

## 执行约束（必须遵守）

1. ⛔ **页面级检查不算通过**：仅验证"页面能打开、数据能加载"不满足 L2 通过标准。每个步骤必须执行 spec 中定义的**具体操作**（填写表单、点击按钮、切换状态）并验证**具体断言**（状态标签变化、列表新增/更新、按钮状态变化）。
2. **10-e2e-test-spec.md 中的「输入数据」列是必须使用的**：不能跳过填表步骤，不能仅靠种子数据验证。需要创建的数据必须创建，需要提交的表单必须提交。
3. **每步 snapshot 验证**：每个写操作后，必须 take snapshot 或 evaluate 验证状态变化，不能假设操作成功。
4. **失败不跳过**：某步失败时记录失败详情但继续执行后续步骤。但如果失败导致后续步骤的前置条件不满足（如周期创建失败导致无法填 KPI），则标记后续步骤为"因前置失败跳过"。
5. **流程间状态传递**：流程 1 创建的周期名称、流程 2 创建的 KPI 数量等，需要在后续流程中引用。使用 spec 中定义的 `输出状态` 字段的变量名。

## 执行规范补充（必须）
- **前置清理**：MCP 测试前先检查前端是否有高频 console.log（如权限检查 hook 的逐项日志），必要时先清理或改为 console.debug，否则每次 MCP 交互会消耗大量 context。
- **测试数据质量**：测试前用 API 或 SQL 检查依赖的种子数据是否完整有效（如 360 模板的 dimensions 必须是有效的对象数组，不能是 `[[], []]`）。数据不合格的先修复再测试。
- 数据准备：每条用例必须写明前置数据与生成方式（种子数据/接口创建/导入），包含关键标识。
- 等待策略：使用 `waitFor` 等待特定文本出现，不使用固定时间等待。
- 被遮挡元素：如遇到元素被其他组件遮挡无法点击，使用 `evaluate` 直接调用 `element.click()`。
- React 受控输入：如遇 `fill` 无法触发 React state 更新，使用 `evaluate` + `nativeInputValueSetter` 方式填值。
- **远程 MCP / 开发机操作要点**：起 dev server（不加 `&` + `run_in_background`）、`python -m http.server` 必 `--bind 0.0.0.0`、杀 server 不用 `pkill -f`（自杀）、本地 HTML 测试走 Caddy 公网域名——完整规则见 [`references/mcp-remote-execution.md`](./references/mcp-remote-execution.md)。

## 测试报告要求（必须）

报告路径：`testing/reports/{module}-{YYYY-MM-DD}-e2e-report.md`

### 报告结构（按此顺序）

```markdown
# {模块名} MCP 连通性测试报告

## 概要
- 日期 / 分支 / 环境（前端+后端 URL）
- 流程总数 / 通过 / 失败 / 跳过

## 流程执行结果
每个流程一个表格：
| 步骤 | 操作 | 断言 | 结果 |
|------|------|------|------|
| 1.1 | 登录 itadmin | 跳转到 overview | ✅ |
| 1.2 | ... | ... | ❌ 实际显示: xxx |

## 发现的 Bug（最重要的部分）
每个 bug：
- 编号 + 严重度（High/Medium/Low）
- 复现步骤（哪个流程哪个步骤）
- 期望 vs 实际
- 是否阻断后续流程

## 未执行的流程
- 列出因阻断或时间限制未执行的流程

## 环境信息
- 前端/后端版本、数据库状态、测试账号
```

**不需要写的**：
- 不需要贴完整的 accessibility tree snapshot
- 不需要列出所有 console log
- 不需要重复 10-e2e-test-spec.md 中的流程定义

## 参考（按需加载）
- `references/frontend-e2e-core.md`
- `references/frontend-e2e-checklist.md`
- `references/e2e-test-spec-template.md`（E2E 测试规范模板）
