chore(08-07-e2e-fixture-repair): 归档任务

这个提交包含在:
2026-08-07 09:06:37 +08:00
父节点 88b97b40af
当前提交 969b426e64
共修改 6 个文件,包含 2 行新增和 2 行删除
@@ -0,0 +1 @@
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
@@ -0,0 +1,55 @@
# 技术设计
## 1. 修改边界
本任务只修改两份 Playwright spec 与已归档浏览器回归记录:
- `client/tests/e2e/r6-mobile-responsive-system-hotfix.spec.ts`
- `client/tests/e2e/r111-invoice-reimbursement-guard.spec.ts`
- `.trellis/tasks/archive/2026-08/08-07-interaction-pattern-browser-regression/implement.md`
- `.trellis/tasks/archive/2026-08/08-07-interaction-pattern-browser-regression/openclaw-test-prompt.md`
- `.trellis/tasks/08-05-product-interaction-consistency/prd.md`
- `.trellis/tasks/08-05-product-interaction-consistency/design.md`
- `.trellis/tasks/08-05-product-interaction-consistency/implement.md`
`client/src`、`server/`、权限映射、路由和产品行为只作为只读事实源,不在修改范围。
## 2. R6 fixture 权限链
R6 登录夹具通过 `/api/me` 返回合成用户,但 `AuthContext` 不消费响应中的任意 `permissions` 字段,而是在 `client/src/auth/AuthContext.tsx:260` 使用 `resolvePermissionsForRoles(me.roleCodes)` 生成权限。
当前合成用户角色为 `manager`、`employee`,不能获得 `leave.manage`。`MobileLeavePage` 因此把 `?view=form` 回落为 `records`,导致仍存在的 `mobile-leave-form` 不渲染。
设计选择:给该 spec 的合成用户增加 `hr` 角色。`hr` 是当前角色表中最小的非通配选择,可通过真实角色解析链产生 `leave.manage`;不使用 `admin` 的 `*`,也不添加不会被消费的 mock 字段。
兼容检查:R6 的七个设备上下文共享该 fixture,必须完整运行 7/7,确认新增合成角色没有改变其他导航、审批、报销或移动布局断言。
## 3. R111 语义定位
R111 上传附件后,页面可能同时出现待上传摘要和已上传附件行。页面级 `getByText("付款截图.png")` 对 DOM 数量敏感,不能证明用户可打开已上传附件。
设计选择:PC 与移动两处都改为按可访问名称定位已上传附件按钮:
```ts
getByRole("button", { name: "查看补充附件:付款截图.png" })
```
该断言唯一、面向用户动作,并与 PC/移动运行时已有 `aria-label` 一致;不使用 `.first()` 或索引规避 strict mode。
## 4. 归档记录勘误
归档记录不删除当时的执行事实:原始 committed R6 spec 失败,临时 runner 跳过该断言后其余移动矩阵通过。只纠正因果诊断:失败来自 fixture 角色不能解析出 `leave.manage`,不是表单取消或企微/OA 边界要求删除覆盖。
证据文件名 `r6-stale-leave-readonly-320.png` 作为历史产物不改名;文字记录注明文件名不代表最终诊断。
## 5. 回滚
本任务没有数据迁移或运行时代码回滚。若测试修复引入意外回归,回滚范围仅为:
- 移除 R6 fixture 新增的 `hr` 角色;
- 恢复 R111 两处原定位器;
- 恢复归档文字勘误。
父任务规划只增加质量支撑任务登记和顺序,不改变三个业务交付物;若登记需回滚,只撤销该任务行与顺序说明。
回滚后会重新暴露两条已知红灯,因此优先修正断言/fixture 并 roll-forward,不以删除覆盖作为回滚手段。
@@ -0,0 +1 @@
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
@@ -0,0 +1,53 @@
# 执行计划
## 1. 实施前
- [x] 读取 `.trellis/workflow.md`、本 task PRD/design、前端 spec 与测试规约。
- [x] 记录 `git status --short`,保护其他任务变更。
- [x] 用户批准最新规划摘要后运行 `task.py start 08-07-e2e-fixture-repair`。
- [x] 启动 loopback Vite;只使用合成 mock,不访问公网或真实账号。
## 2. 测试修复
- [x] 在 R6 fixture 的 `employee.roleCodes` 增加 `hr`;不修改产品角色映射或添加伪权限字段。
- [x] 保留 `/mobile/leave?view=form` 与 `mobile-leave-form` 断言。
- [x] 将 R111 PC、移动两处附件上传后断言改为语义化“查看补充附件”按钮定位。
- [x] 搜索确认不存在本任务遗漏的同类 `getByText("付款截图.png")`。
## 3. 归档勘误
- [x] 修正归档 `implement.md` 中三处 R6 原因描述,保留临时 runner 历史事实。
- [x] 修正归档 `openclaw-test-prompt.md` 中两处错误诊断。
- [x] 搜索确认归档目录不再把该失败描述为错误的产品/断言诊断。
- [x] 更新父任务 PRD/design/implement:登记两个质量支撑子任务,并固定 fixture 修复先于采购/资产路由化。
## 4. 验证
- [x] committed R6 spec 聚焦运行:7 passed,退出码 0。
- [x] committed R111 spec 完整运行:2 passed,退出码 0。
- [x] `cd client && npm run typecheck && npm run build`。
- [x] task validate、process contract、Trellis governance、`git diff --check`。
- [x] `git diff --name-only -- client/src server` 为空。
## 5. 收尾
- [x] 只读复核确认没有降低测试口径、删除断言或扩大真实权限。
- [x] 使用中文 commit message 并引用 `08-07-e2e-fixture-repair`。
- [ ] 归档任务;不宣称部署、公网或企业微信真机已验证。
## 验证记录
- R6:7 个视口全部通过;`mobile-leave-form` 断言在 committed spec 中执行并通过。
- R111:PC 与企业微信 UA 用例均通过;两处附件断言均使用唯一语义按钮定位。
- 静态门禁:typecheck、build、task validate、process contract、Trellis governance、`git diff --check` 均通过;docs audit 0 errors,保留既有 22 个 warning。
- 边界:本地 Chromium/UA 模拟和合成 mock;未执行部署、公网、真实账号、企业微信真机或生产数据验证。
## 只读复核
- 未改产品运行时代码;没有删除或跳过 `mobile-leave-form`,没有使用 `.first()` 掩盖 R111 的重复定位。
- 当前 task 与父任务规划仍保留,提交和归档在最终门禁后执行。
## 回滚点
- 测试文件改动均为单行/小范围 fixture 与定位器调整,可独立回退。
- 归档勘误属于事实修正;除非新证据推翻权限链,不应回退为“表单已取消”的错误诊断。
@@ -0,0 +1,124 @@
# 交互回归 E2E 夹具修复
## Goal
修复 `08-07-interaction-pattern-browser-regression` 已确认但未落入仓库测试文件的两条 Playwright 红灯,使 R6 移动响应式矩阵和 R111 报销附件双端用例可以直接从 committed spec 运行通过;同时勘误已归档任务对 R6 失败原因的错误描述,防止后续人员误删仍有效的 OA 应急请假表单覆盖。
本任务只修测试夹具、断言和审计记录,不改变产品权限模型、请假行为、报销附件行为或运行时代码。
## Background
### R6:权限门控导致表单不可见
- `client/src/pages/MobileLeavePage.tsx:238` 仅在当前权限包含 `leave.manage` 时令 `canUseOaEmergencyLeave=true`;`:253` 会把无该权限用户的 `?view=form` 强制回落到 `records`。
- `mobile-leave-form` 仍存在于 `client/src/pages/MobileLeavePage.tsx:498`,不是已取消能力,原断言覆盖的是仍有效的 OA 应急请假表单。
- `client/tests/e2e/r6-mobile-responsive-system-hotfix.spec.ts:25-47` 的 fixture 用户只有 `manager`、`employee` 两个角色。`client/src/auth/AuthContext.tsx` 通过 `resolvePermissionsForRoles(me.roleCodes)` 生成前端权限,不读取 fixture 自造的 `permissions` 字段;上述两角色均不产生 `leave.manage`。
- 当前角色表中最小可产生 `leave.manage` 的非通配角色是 `hr`。本任务应给 R6 合成用户增加 `hr` 角色,从角色解析链真实获得该权限,而不是删除 `mobile-leave-form` 断言或修改产品门控。
### R111:宽泛文本定位触发 strict mode
- `client/tests/e2e/r111-invoice-reimbursement-guard.spec.ts:680` 与 `:812` 上传 `付款截图.png` 后都使用页面级 `getByText("付款截图.png")`。
- 移动端上传后,待上传摘要会渲染 `付款截图.png · 1 KB`,已上传附件操作入口又渲染 `付款截图.png`,页面级文本定位命中两个元素并触发 Playwright strict mode;产品 DOM 和上传行为本身正确。
- PC、移动附件行均有稳定的语义化按钮名 `查看补充附件:付款截图.png`。本任务统一改用该 role/name 断言,证明附件已成为可操作材料,同时避免 `.first()` 的顺序依赖。
### 归档勘误
- 已归档任务的 `implement.md` 与 `openclaw-test-prompt.md` 把 R6 失败描述为“过期请假表单断言”或与“企微主办、OA 只读”边界冲突,这一诊断不正确。
- 勘误必须保留当时“临时 runner 跳过该断言后其余矩阵通过”的历史事实,同时明确后续复核结论:fixture 缺少能解析出 `leave.manage` 的角色,导致 `effectiveView` 回落到 `records`。
## Scope
- 修复 R6 spec 的合成用户角色,使既有 `mobile-leave-form` 断言在七个视口继续执行并通过。
- 将 R111 PC 与移动端两处附件上传后断言收窄到语义化“查看补充附件”按钮。
- 勘误归档浏览器回归任务中所有错误的 R6 原因描述,保留历史执行事实与证据边界。
- 在父任务 PRD/design/implement 中登记浏览器回归补跑与本任务为质量支撑子任务,明确本任务先于采购/资产路由化执行,不改变三项产品交付范围。
- 直接运行仓库 committed spec 验证,不再依赖 `/tmp` 临时副本或删除断言的 runner。
## Requirements
- R1:R6 fixture 用户的 `roleCodes` 增加 `hr`,通过现有 `resolvePermissionsForRoles` 获得 `leave.manage`;不得向 `/api/me` mock 添加不会被消费的伪 `permissions` 字段。
- R2:保留 `/mobile/leave?view=form`、`mobile-leave-form` 和移动稳定性断言;不得删除、跳过或降级该页面覆盖。
- R3:R111 的 PC 与移动附件断言均改为 `getByRole("button", { name: "查看补充附件:付款截图.png" })` 或等价的唯一语义定位;不得使用页面级宽泛 `getByText` 或依赖 DOM 顺序的 `.first()`。
- R4:归档记录明确写出 `leave.manage` 权限门控、`effectiveView` 回落和 fixture 角色缺口;删除“表单已取消”“过期断言”“企微主办所以不应覆盖该表单”等误导性结论。
- R5:不修改 `client/src`、`server/`、角色权限映射、路由、API、数据库、依赖或产品功能;只允许改两份 E2E spec、归档勘误、父任务的质量子任务登记和当前 Trellis task。
- R6:截图仍写入各自 spec 的既有证据目录,不覆盖其他任务归档证据;测试数据继续使用合成内容。
- R7:父任务继续以低风险统一、采购/资产路由化、合同详情为三个产品交付物;浏览器补跑与 fixture 修复只作为质量支撑和执行前置,不增加产品能力。
## Acceptance Criteria
- [x] A1:直接运行 committed `r6-mobile-responsive-system-hotfix.spec.ts` 聚焦用例,七个视口全部通过,报告为 `7 passed`、退出码 0,且每个视口实际执行 `mobile-leave-form` 可见性与移动稳定性断言。
- [x] A2:直接运行 committed `r111-invoice-reimbursement-guard.spec.ts`,PC 与企业微信 UA 两个用例全部通过,报告为 `2 passed`、退出码 0,不再出现 `付款截图.png` strict mode violation。
- [x] A3:归档 `implement.md` 与 `openclaw-test-prompt.md` 的 R6 描述已改为权限 fixture 诊断,并保留临时 runner 历史事实;目标错误诊断搜索无命中。
- [x] A4:变更文件仅包含两份 E2E spec、两份归档记录、父任务四份规划文件和当前 task 文件;`client/src`、`server/` 无改动。
- [x] A5:`cd client && npm run typecheck && npm run build`、任务 validate、流程合同、Trellis governance 与 `git diff --check` 全部通过。
- [x] A6:父任务明确记录本质量修复先于 `08-05-business-detail-routing`,合同迁移任务仍最后实施;父任务的三个产品交付边界不变。
## Out of Scope
- 不删除或隐藏 OA 应急请假表单,不调整 `leave.manage` 产品门控,不扩大真实角色权限。
- 不修改报销材料 DOM、附件上传/预览逻辑或可访问名称。
- 不重构全仓 E2E fixture/角色体系,不清理其他历史测试。
- 不承诺本任务运行全仓全部 Playwright spec;验收对象是两份已知红灯的 committed spec 及其完整用例。
- 不执行部署、公网、真实账号、企业微信真机或生产数据验证。
## Test Plan
### 1. 基线与修复验证
在本地 loopback Vite 与合成 API mock 下单 worker 执行:
```bash
cd client
E2E_MODE=local E2E_BASE_URL=http://127.0.0.1:5178 npx playwright test \
tests/e2e/r6-mobile-responsive-system-hotfix.spec.ts \
--grep '关键移动页面跨视口自适应且首页宫格不挤压' \
--workers=1 --reporter=list
E2E_MODE=local E2E_BASE_URL=http://127.0.0.1:5178 npx playwright test \
tests/e2e/r111-invoice-reimbursement-guard.spec.ts \
--workers=1 --reporter=list
```
R6 必须报告 7/7;R111 必须报告 2/2。不得使用临时副本、临时删除断言或重定向到当前任务之外的证据目录来替代 committed spec 结果。
### 2. 静态与流程门禁
```bash
cd client && npm run typecheck && npm run build
python3 ./.trellis/scripts/task.py validate 08-07-e2e-fixture-repair
node scripts/qa/check-process-contract.mjs --baseline --json
node scripts/qa/check-trellis-governance.mjs --json
git diff --check
```
收尾时额外确认:
- `rg -n '过期请假|企微主办.*OA 只读' .trellis/tasks/archive/2026-08/08-07-interaction-pattern-browser-regression` 不再命中本次错误诊断。
- `git diff --name-only -- client/src server` 为空。
## 验证记录
- `task.py start 08-07-e2e-fixture-repair`:退出码 0,任务状态为 `in_progress`。
- R6 committed spec:`E2E_MODE=local E2E_BASE_URL=http://127.0.0.1:5178 npx playwright test tests/e2e/r6-mobile-responsive-system-hotfix.spec.ts --grep '关键移动页面跨视口自适应且首页宫格不挤压' --workers=1 --reporter=list`,退出码 0,`7 passed`;七个视口均执行 `mobile-leave-form` 可见性断言。
- R111 committed spec:`E2E_MODE=local E2E_BASE_URL=http://127.0.0.1:5178 npx playwright test tests/e2e/r111-invoice-reimbursement-guard.spec.ts --workers=1 --reporter=list`,退出码 0,`2 passed`。
- `cd client && npm run typecheck`:退出码 0;`npm run build`:退出码 0(仅有既有 Browserslist 数据过期提示)。
- `python3 ./.trellis/scripts/task.py validate 08-07-e2e-fixture-repair`:退出码 0。
- `node scripts/qa/check-process-contract.mjs --baseline --json`:`PASS`,0 errors / 0 warnings。
- `node scripts/qa/audit-docs.mjs --check-registry`:0 errors,保留既有 22 个未注册 docs warning。
- `node scripts/qa/check-trellis-governance.mjs --json`:`PASS`,0 errors / 0 warnings。
- `git diff --check`:退出码 0;`git diff --name-only -- client/src server` 为空;归档错误诊断搜索无命中。
## 只读复核
- 仅修改两份 committed E2E spec、两份归档记录、父任务规划登记和当前 Trellis task;未修改 `client/src`、`server/`、权限映射、API、数据库、依赖或生产配置。
- `mobile-leave-form` 断言仍在 committed spec 中,未删除、跳过或降级;R111 未使用宽泛文本定位或 `.first()`。
- `hr` 只加入 R6 合成 fixture,不改变真实角色权限;测试使用 loopback 与合成 API mock,未执行公网、部署或真机验证。
## Risks and Deferred Items
- `hr` 角色还会带来其他 HR 权限,但只存在于该 spec 的合成用户中;必须以 R6 全部七个视口回归确认没有改变页面可达性断言。相比 `admin` 通配角色,`hr` 是当前角色表中更小的有效选择。
- R111 的语义化按钮名来自当前产品可访问名称;若未来文案调整,应同步按用户可感知动作更新测试,不应退回宽泛文本或 `.first()`。
- 本任务只消除两条已知 committed spec 红灯;其他全仓测试结果仍以各自任务和门禁为准。
## Open Questions
无。失败原因、最小修复、验收命令和不做范围均已由代码与用户复核确认。
@@ -0,0 +1,39 @@
{
"id": "e2e-fixture-repair",
"name": "e2e-fixture-repair",
"title": "交互回归 E2E 夹具修复",
"description": "修复交互回归中两条已知 Playwright 红灯:为 R6 合成用户补足可解析为 leave.manage 的角色,并将 R111 附件断言收窄到语义化操作入口;同步勘误已归档诊断,不改业务代码。",
"status": "completed",
"dev_type": null,
"scope": "repair-r6-r111-committed-e2e-fixtures-and-archive-diagnosis",
"package": "client",
"priority": "P2",
"creator": "shunli",
"assignee": "shunli",
"createdAt": "2026-08-07",
"completedAt": "2026-08-07",
"branch": null,
"base_branch": "main",
"worktree_path": null,
"commit": null,
"pr_url": null,
"subtasks": [],
"children": [],
"parent": "08-05-product-interaction-consistency",
"relatedFiles": [
"client/tests/e2e/r6-mobile-responsive-system-hotfix.spec.ts",
"client/tests/e2e/r111-invoice-reimbursement-guard.spec.ts",
".trellis/tasks/archive/2026-08/08-07-interaction-pattern-browser-regression/implement.md",
".trellis/tasks/archive/2026-08/08-07-interaction-pattern-browser-regression/openclaw-test-prompt.md",
".trellis/tasks/08-05-product-interaction-consistency/prd.md",
".trellis/tasks/08-05-product-interaction-consistency/design.md",
".trellis/tasks/08-05-product-interaction-consistency/implement.md",
"client/src/pages/MobileLeavePage.tsx",
"client/src/auth/permissions.ts",
"docs/测试规约与回归门禁.md"
],
"notes": "只修测试夹具、测试定位器、父任务质量子任务登记和历史诊断;禁止删除仍有效的 mobile-leave-form 覆盖,禁止修改产品权限或运行时代码。",
"meta": {
"description": "修复交互回归中两条已知 Playwright 红灯:为 R6 合成用户补足可解析为 leave.manage 的角色,并将 R111 附件断言收窄到语义化操作入口;同步勘误已归档诊断,不改业务代码。"
}
}