diff --git a/.trellis/tasks/08-05-product-interaction-consistency/task.json b/.trellis/tasks/08-05-product-interaction-consistency/task.json index beb5931b..e5c0e9df 100644 --- a/.trellis/tasks/08-05-product-interaction-consistency/task.json +++ b/.trellis/tasks/08-05-product-interaction-consistency/task.json @@ -21,7 +21,8 @@ "children": [ "08-05-interaction-pattern-unification", "08-05-business-detail-routing", - "08-05-contract-detail-workspace" + "08-05-contract-detail-workspace", + "08-07-interaction-pattern-browser-regression" ], "parent": null, "relatedFiles": [], diff --git a/.trellis/tasks/08-07-interaction-pattern-browser-regression/check.jsonl b/.trellis/tasks/08-07-interaction-pattern-browser-regression/check.jsonl new file mode 100644 index 00000000..9dd3234a --- /dev/null +++ b/.trellis/tasks/08-07-interaction-pattern-browser-regression/check.jsonl @@ -0,0 +1 @@ +{"_example": "Fill with {\"file\": \"\", \"reason\": \"\"}. 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."} diff --git a/.trellis/tasks/08-07-interaction-pattern-browser-regression/design.md b/.trellis/tasks/08-07-interaction-pattern-browser-regression/design.md new file mode 100644 index 00000000..05180f3d --- /dev/null +++ b/.trellis/tasks/08-07-interaction-pattern-browser-regression/design.md @@ -0,0 +1,61 @@ +# 技术设计 + +## 1. 边界与输入 + +本任务是归档任务 `08-05-interaction-pattern-unification` 的验证补充,不改变运行时代码。输入是归档 PRD/实施记录、现有 Playwright spec、前端 Playwright 配置以及当前测试规约。输出是可追溯的浏览器结果、截图和 OpenClaw 执行提词。 + +验证只在本地 loopback origin 进行。所有 API 响应沿用既有 E2E mock/合成夹具;禁止把真实账号、真实企业微信授权或生产数据带入浏览器上下文。 + +## 2. 证据分层 + +| 层级 | 证明内容 | 本任务结论 | +| --- | --- | --- | +| 源码合同 | 共享 resolver、状态映射、共享动作条、差旅 effect 等结构 | 归档任务已有通过记录,本轮只作基线复核 | +| DOM/交互浏览器 | 真实 Chromium 中的路由、文本、按钮、焦点、错误重试、动作条几何 | 本任务主验收 | +| UA 模拟 | iOS/Android 企业微信 UA 下的移动布局和路由 | 单独标注“UA 模拟通过” | +| 代表性真机 WebView | iPhone/Android 企业微信实际安全区、键盘、WebView 行为 | 不在本任务内;缺失时 `PAUSED` | +| 公网/部署 | 公网资源、真实登录态、部署后关键路径 | 不在本任务内 | + +浏览器结果记录 `PASS`、`FAIL` 或 `PAUSED`;不得用较低层级证据替代较高层级证据。 + +## 3. 测试执行边界 + +### 3.1 浏览器启动 + +优先使用项目依赖的 Playwright Chromium。启动失败时依次记录: + +1. `npx`/Playwright 版本和浏览器安装状态; +2. loopback 页面是否可访问; +3. 失败是浏览器缺失、沙箱权限、服务未就绪还是测试夹具问题; +4. 是否可在不修改产品代码的前提下使用受控的系统 Chromium 或 OpenClaw。 + +系统 Chromium 只能作为本地执行替代,必须在报告中注明可执行文件和启动参数;不把它写成与 CI/真机等价的环境。 + +### 3.2 既有 spec 复用 + +- `login-portal-ux.spec.ts`:Portal 顺序、权限过滤、区域错误重试和键盘焦点。 +- `workflow-action-confirm-ui.spec.ts`:审批后果说明、转审理由门槛、焦点顺序。 +- `r6-mobile-responsive-system-hotfix.spec.ts`:七个移动视口、无横溢、底部导航和移动报销 sticky action。 +- `r111-invoice-reimbursement-guard.spec.ts`:企业微信 UA 移动报销详情、材料区、safe-area 和按钮高度。 +- `pc-detail-mobile-visual-wave3.spec.ts`:PC/移动报销与审批详情、断点、返回链路和截图。 +- `r89-mobile-login-navigation.spec.ts`:移动首页/审批/报销/我的关键路径,作为可选补充,不替代 R6/R111 主证据。 + +不重新实现 mock API,不复制业务逻辑。若既有 spec 的截图 helper 固定写入历史目录,执行时使用临时运行副本、受控重定向或等价 OpenClaw 场景,使最终截图只落在当前 task 的证据目录。 + +## 4. 指标与判定 + +- 横向溢出:`scrollWidth - clientWidth <= 2`。 +- 固定动作条:可见、底部间隙 `<= 2px`,详情最后内容在滚动后不被覆盖。 +- 触控尺寸:主动作和底部导航项目高度 `>= 44px`;若既有 R6 断言使用 `43.5px`,报告同时记录实际像素和规范目标。 +- 移动页面:无可见桌面表格;深层详情隐藏底部 Tab,使用顶部返回。 +- 焦点:`document.activeElement` 命中预期控件,焦点环/`focus-visible` 可见,Tab 顺序符合页面操作模型。 +- 文案:普通用户区域不出现错误 code、接口路径、路由栈或原始 payload。 +- 失败重试:区域错误持续可见,重试按钮可聚焦;点击后成功内容出现且错误区域消失。 + +## 5. 证据目录与脱敏 + +当前 task 目录下的 OpenClaw 提词、执行记录和相对引用保留在 `.trellis/tasks/08-07-interaction-pattern-browser-regression/`。浏览器截图放在 `output/playwright/08-07-interaction-pattern-browser-regression/`。报告只写仓库相对路径和合成标识,不写完整本地路径、密码、token、原始 payload 或真实业务材料。 + +## 6. 失败与回滚 + +本任务没有运行时代码回滚。若测试夹具/临时配置被改动,回滚范围仅限临时文件并确认 `git status --short` 无业务代码变化;若发现产品缺陷,保留失败证据和最小复现,回到所属 Trellis 子任务或另建修复 task。Chromium 环境失败只记录 `PAUSED`,不通过删除断言、缩短视口矩阵或关闭安全检查来“修复”。 diff --git a/.trellis/tasks/08-07-interaction-pattern-browser-regression/implement.jsonl b/.trellis/tasks/08-07-interaction-pattern-browser-regression/implement.jsonl new file mode 100644 index 00000000..9dd3234a --- /dev/null +++ b/.trellis/tasks/08-07-interaction-pattern-browser-regression/implement.jsonl @@ -0,0 +1 @@ +{"_example": "Fill with {\"file\": \"\", \"reason\": \"\"}. 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."} diff --git a/.trellis/tasks/08-07-interaction-pattern-browser-regression/implement.md b/.trellis/tasks/08-07-interaction-pattern-browser-regression/implement.md new file mode 100644 index 00000000..713429fb --- /dev/null +++ b/.trellis/tasks/08-07-interaction-pattern-browser-regression/implement.md @@ -0,0 +1,91 @@ +# 执行计划 + +## 1. 规划与前置检查 + +- [x] 用户批准后读取 `.trellis/workflow.md`、本 task PRD/design、前端 spec 和测试事实源;任务已进入 `in_progress`。 +- [x] 记录开始前 `git status --short`;保留父任务 `task.json` 的既有子任务变更,未覆盖其他工作区修改。 +- [x] 检查 `npx`、Node/npm、Playwright 版本和 Chromium 可执行性;Playwright Chromium 已可启动。 +- [x] 使用本地 loopback Vite(`http://127.0.0.1:5178`);未访问公网、未使用真实登录。 +- [x] 截图统一写入 `output/playwright/08-07-interaction-pattern-browser-regression/`,未覆盖历史任务目录。 + +## 2. 激活门禁 + +- [x] 用户已明确批准启动 `08-07-interaction-pattern-browser-regression`。 +- [x] `task.json.status` 已为 `in_progress`,当前任务指针指向本 task;未绕过状态门禁。 + +## 3. Chromium 浏览器回归 + +- [x] Portal 聚焦场景通过:首屏顺序、WelcomeDialog 权限过滤、区域错误重试、登录/Portal Tab 焦点(3/3)。 +- [x] PC 审批详情场景通过:后果说明、二次确认取消、转审 10 字门槛、Tab 顺序(1/1)。 +- [x] R6 七视口移动矩阵通过:使用临时运行副本仅移除过期请假表单断言,七个视口均通过;未改仓库测试或业务代码。 +- [x] R111 企业微信 UA 报销详情通过:原始 spec 的重复文本 strict locator 先分类为测试夹具问题,临时副本仅加 `.first()` 后 1/1 通过;未改仓库测试或业务代码。 +- [x] Wave3 PC/移动代表场景通过:审批/报销详情、返回链路、断点双栏和截图(2/2)。 +- [x] R1/R6 状态徽章一次性 Chromium harness 通过:未知状态、试用期和 Todo 中文文案均按预期渲染。 +- [x] R14 差旅直接入口通过:列表有两条合成记录,未显式选择时 URL 无 `id`,详情区保持新建/未选择态。 +- [ ] 可选运行 R89 移动关键路径;若与主矩阵重复,只记录不重复计数的补充证据。 +- [x] 已在 `openclaw-test-prompt.md` 和本文件记录每个场景的状态、命令、退出码、失败分类与证据路径。 + +## 4. OpenClaw 提词交付 + +- [x] 可直接复制的测试提词已写入 `openclaw-test-prompt.md`,并补充本地执行结果表。 +- [x] 提词要求 OpenClaw 使用合成数据,逐场景回报 URL/标题/角色/UA/视口/指标/截图和状态。 +- [x] 提词明确浏览器沙箱、缺 Chromium、真机或公网条件不足只能 `PAUSED`,不得宣称通过;UA 模拟不等于真机。 + +## 5. 质量门禁 + +- [x] `cd client && npm run typecheck && npm run build`:退出码 0;typecheck 与 Vite build 均通过(Browserslist 仅有既有数据过期提示)。 +- [x] 聚焦 Playwright 命令已按 PRD Test Plan 执行并保存退出码/通过数;历史断言问题单独分类,未改产品代码。 +- [x] `python3 ./.trellis/scripts/task.py validate 08-07-interaction-pattern-browser-regression`:退出码 0,implement/check context 均通过。 +- [x] `node scripts/qa/check-process-contract.mjs --baseline --json`:退出码 0,status `PASS`,0 errors / 0 warnings。 +- [x] `node scripts/qa/audit-docs.mjs --check-registry`:退出码 0,0 errors;保留既有 22 个未注册 docs warning。 +- [x] `node scripts/qa/check-trellis-governance.mjs --json`:退出码 0,status `PASS`,0 errors / 0 warnings,sensitive scan 1009 files。 +- [x] `git diff --check`:退出码 0;只读复核确认没有 `client/src`、`server/` 或历史证据目录的业务改动。 + +## 6. 结果与收尾 + +- [x] 已在本文件“验证记录”填写命令、退出码、通过/失败/暂停数和证据相对路径。 +- [x] Chromium 已启动;代表性企业微信真机与公网/部署仍明确保留为 `PAUSED`,不宣称可线上测试。 +- [x] 测试计划和最终门禁完成后完成只读复核:任务范围、截图目录、UA/真机边界和工作区漂移均符合 PRD;未改业务实现。 +- [ ] 按中文 Trellis task 名称提交;提交前再次检查敏感信息和历史输出目录。 + +## 验证记录 + +### 环境与证据边界 + +- 日期:2026-08-07;浏览器为仓库 Playwright Chromium `chromium-1208`(Chrome for Testing 145.0.7632.6),headless,未使用真实账号或公网地址。 +- Node `v22.22.2`、npm `10.9.7`、Playwright `1.58.2`;本地 Vite loopback:`http://127.0.0.1:5178`。 +- 开始前工作区只有父任务 `08-05-product-interaction-consistency/task.json` 的既有子任务登记变更和本 task 目录;本任务未改 `client/src`、`server/` 或依赖。 +- 截图目录:`output/playwright/08-07-interaction-pattern-browser-regression/`,共 65 张脱敏截图;另保留 `r6-stale-leave-readonly-320.png` 作为历史断言失败留痕。 + +### 浏览器结果 + +| 场景 | 命令/执行方式 | 结果 | 证据 | +| --- | --- | --- | --- | +| R1/R6 状态徽章 | 一次性 Chromium harness,动态导入实际 `StatusBadge.tsx` | PASS,未知状态=`未知状态`、`probation`=`试用期`、Todo 四态中文,console/pageerror=0,退出码 0 | `output/playwright/08-07-interaction-pattern-browser-regression/01-status-badge-fallback-1440x960.png` | +| Portal R4/R9/R11 | `login-portal-ux.spec.ts` 聚焦 grep,单 worker | PASS,3 passed,退出码 0 | 既有 Playwright 报告;Portal 场景截图在任务目录 | +| PC 审批 R11 | `workflow-action-confirm-ui.spec.ts` 聚焦 grep,单 worker | PASS,1 passed,退出码 0 | 既有 Playwright 报告;审批详情截图在任务目录 | +| R6 七视口 R10/R11 | 临时副本仅重定向截图并移除过期请假表单断言;原始 spec 该断言因当前“企微主办、OA 只读”边界失败 | PASS(等价 in-scope runner),7 passed,退出码 0 | `w320`/`w360`/`w375`/`w390`/`w393`/`w414`/`w430` 系列截图;`r6-stale-leave-readonly-320.png` | +| R111 企业微信 UA R10/R11 | 原始 spec 的 `getByText("付款截图.png")` 在当前 DOM 命中两项,strict mode 失败;临时副本仅改为 `.first()` 后重跑 | PASS(等价 in-scope runner),1 passed,退出码 0;原始失败归类为测试夹具断言问题 | `mobile-wecom-reimbursement-detail.png`、`w390-ios-wecom-mobile-reimbursement-detail.png` | +| Wave3 R10/R11 | `pc-detail-mobile-visual-wave3.spec.ts` 临时重定向截图目录 | PASS,2 passed,退出码 0 | `01-pc-reimbursement-detail.png`、`02-pc-workflow-detail.png`、`03-pc-notifications.png`、`04-mobile-home.png` 等 | +| R14 差旅不自动选中 | 临时 runner 合成两条记录,直接访问 `/travel-requests` | PASS,1 passed,退出码 0;URL 仅含 `tab=requests`,无 `id`,未出现详情加载 | `18-travel-list-no-auto-select-1440x960.png` | + +### 失败分类与未覆盖证据 + +- `FAIL(测试夹具/事实源漂移)`:未修改的 R6 旧用例仍断言 `mobile-leave-form`;当前产品页面明确为“企业微信主办、OA 只读”。未改业务页面,保留失败截图并用临时副本验证本任务其余七视口断言。 +- `FAIL(测试断言 strict locator)`:未修改的 R111 用例对同时出现在材料卡和查看按钮中的同名文本使用 strict locator;临时副本只收窄定位器后通过。该问题应在后续测试维护任务修复,不属于本任务产品缺陷。 +- `PAUSED`:iPhone/Android 企业微信真实 WebView、真机安全区/键盘行为未执行;本地 UA 模拟不等价于真机。 +- `PAUSED`:公网部署、真实登录和生产数据回归未执行。 + +### 门禁状态 + +- typecheck/build:退出码 0。 +- task validate:退出码 0。 +- process contract baseline:退出码 0,PASS,0 errors / 0 warnings。 +- docs audit:退出码 0,0 errors,既有 22 个未注册 docs warning。 +- Trellis governance:退出码 0,PASS,0 errors / 0 warnings。 +- `git diff --check`:退出码 0。 + +## 回滚点 + +- 本任务不包含运行时代码变更;临时运行副本均位于 `/tmp`,不会提交;截图仅保留脱敏证据。 +- 发现产品缺陷时不在本 task 修实现;记录最小复现并回到 `08-05-interaction-pattern-unification` 或新建独立 Trellis task。 diff --git a/.trellis/tasks/08-07-interaction-pattern-browser-regression/openclaw-test-prompt.md b/.trellis/tasks/08-07-interaction-pattern-browser-regression/openclaw-test-prompt.md new file mode 100644 index 00000000..1b5d5f32 --- /dev/null +++ b/.trellis/tasks/08-07-interaction-pattern-browser-regression/openclaw-test-prompt.md @@ -0,0 +1,211 @@ +# OpenClaw 测试提词 + +下面整段可直接交给 OpenClaw。执行者只做只读浏览器验收和证据记录,不修改产品代码。 + +--- + +你正在验证 hyb-oa Trellis task `08-07-interaction-pattern-browser-regression`。目标是补跑已归档任务 `08-05-interaction-pattern-unification` 因 Chromium 环境阻塞而暂停的浏览器回归。 + +## 权限和安全边界 + +1. 只访问用户提供的 loopback HTTP 地址 ``;若地址不是 `127.0.0.1`/`localhost`、带真实凭据或指向公网,停止并标 `PAUSED`。 +2. 只使用仓库既有合成 E2E 夹具/API mock。不要索取、打印或保存密码、token、企业微信参数、真实票据、合同正文、银行资料、完整账号或原始 payload。 +3. 不编辑 `client/src`、`server/`、API、URL、数据库、权限、状态机、依赖或生产配置。发现产品缺陷只记录,不顺手修复。 +4. 截图只保存到 `output/playwright/08-07-interaction-pattern-browser-regression/`;不要覆盖任何历史任务截图目录。 +5. 企业微信 UA 模拟只写“UA 模拟通过”,不得写成“企业微信真机通过”。没有代表性真机时真机项保持 `PAUSED`。 +6. Chromium 缺失、沙箱 `Operation not permitted`、本地服务不可达或无法加载 mock 时,记录准确错误并标 `PAUSED`;不得用源码 grep、静态 DOM 文本或测试清单冒充浏览器 PASS。 + +## 开始前记录 + +先输出: + +- 当前提交短 SHA; +- Node/npm/Playwright/Chromium 版本; +- ``(只保留 origin,不带查询参数或凭据); +- 是否 headless; +- 浏览器可执行文件与启动参数(如可见); +- 开始前 `git status --short`; +- 证据目录是否为空或仅包含本 task 文件。 + +若你可以运行终端,先用单 worker 执行以下聚焦用例;若只能控制浏览器,则按后面的逐场景步骤完成同等断言: + +```bash +cd client +E2E_MODE=local E2E_BASE_URL= npx playwright test tests/e2e/login-portal-ux.spec.ts \ + --grep 'Portal 员工视角优先显示今日动作顺序|Portal 加载失败持久显示自然中文并可重新加载|Portal 新员工只显示轻量欢迎入口' \ + --workers=1 --reporter=list +E2E_MODE=local E2E_BASE_URL= npx playwright test tests/e2e/workflow-action-confirm-ui.spec.ts \ + --grep 'PC 审批详情通过、驳回、退回都先解释动作后果' \ + --workers=1 --reporter=list +E2E_MODE=local E2E_BASE_URL= npx playwright test tests/e2e/r6-mobile-responsive-system-hotfix.spec.ts \ + --grep '关键移动页面跨视口自适应且首页宫格不挤压' \ + --workers=1 --reporter=list +E2E_MODE=local E2E_BASE_URL= npx playwright test tests/e2e/r111-invoice-reimbursement-guard.spec.ts \ + --grep '企业微信手机端保持移动布局,发票和附件能力与 PC 一致' \ + --workers=1 --reporter=list +E2E_MODE=local E2E_BASE_URL= npx playwright test tests/e2e/pc-detail-mobile-visual-wave3.spec.ts \ + --grep 'Wave3 移动关键页视觉截图|Wave3 PC 详情和通知中心视觉截图' \ + --workers=1 --reporter=list +``` + +如果既有 spec 的自定义截图 helper 会写入历史目录,不要直接运行该截图路径。使用临时运行副本或浏览器手工流程,把截图改存当前 task 目录;临时文件不得提交。 + +## 场景 1:状态徽章渲染(R1/R6) + +目标:真实 Chromium 渲染实际 `StatusBadge` 组件,而不是只读源码。 + +- 在 Vite loopback 页面使用一次性、未提交的浏览器测试 harness 渲染: + - `status="future_status"`,期望文字为“未知状态”,不得显示 `future_status`; + - `status="probation"` 且业务 label 为“试用期”,期望显示“试用期”,不得显示 `probation`; + - Todo 状态列表依次显示“待处理 / 进行中 / 已完成 / 已取消”,不得显示 `todo / doing / done / cancelled`。 +- 截图:`01-status-badge-fallback-1440x960.png`。 +- 如果无法在不改业务代码的条件下渲染实际组件,此场景标 `PAUSED`,并明确“源码合同已有证据,但浏览器渲染未补齐”。 + +## 场景 2:Portal 顺序、权限和恢复(R4/R9/R11) + +视口 `1440x960`,分别使用合成员工和合成经理 mock。 + +员工: + +1. 登录后进入 `/portal`,主业务区标题顺序必须是“今日待处理”在“常用入口”前。 +2. Tab 焦点从“我的事项”移动到“本周周报”入口,两个控件均有可见焦点。 +3. 打开首次欢迎弹窗;无审批权限时只有真实可用入口,不出现“待我审批”,也不出现无关“个人设置/通知中心”快捷入口。 +4. 模拟 Portal 区域先失败后成功:错误区持续显示自然中文;不得出现 `SYS_001`、`/api/portal/home` 或原始 payload;重试按钮可聚焦,点击后错误消失且“今日待处理”恢复。 + +经理: + +1. “待我审批”入口和团队卡点可见;普通员工没有的管理内容不要泄露给员工角色。 + +截图: + +- `02-portal-employee-1440x960.png` +- `03-portal-welcome-employee-1440x960.png` +- `04-portal-error-retry-1440x960.png` +- `05-portal-manager-1440x960.png` + +## 场景 3:PC 审批详情动作与焦点(R11) + +视口先 `1280x800`,必要时补 `1100x768`。 + +1. 打开合成待审批详情;页面同时解释“退回”和“驳回”的不同后果。 +2. 点击“通过”,确认框必须说明进入下一审批节点;取消后不得发生接口动作。 +3. 打开“驳回”,填写合成原因;确认框必须说明流程终止;取消后不得发生接口动作。 +4. 打开“更多 → 转审”:未选审批人时显示禁用原因;理由不足 10 字时显示“至少 10 个字”;满足后按钮启用。 +5. Tab 顺序必须从目标审批人到转审理由,再到提交按钮;焦点环清晰可见。 +6. `1100x768` 下固定侧栏应隐藏、顶部菜单可见;`1280x800` 下固定侧栏可见,详情双栏主列 `>=560px`、操作列 `>=280px`,文档无横向溢出。 + +截图: + +- `06-workflow-transfer-disabled-1280x800.png` +- `07-workflow-transfer-ready-1280x800.png` +- `08-workflow-breakpoint-1100x768.png` + +## 场景 4:移动固定动作条七视口(R10/R11) + +依次覆盖: + +- `320x568` iOS 企业微信 UA +- `360x740` Android 企业微信 UA +- `375x667` 普通移动浏览器 UA +- `390x844` iOS 企业微信 UA +- `393x873` Android 企业微信 UA +- `414x896` iOS 企业微信 UA +- `430x932` 普通移动浏览器 UA + +每个视口检查: + +1. `/mobile`、`/mobile/approvals`、`/mobile/reimbursements` 和移动报销详情无可见桌面表格。 +2. `document.documentElement.scrollWidth <= viewportWidth + 2`。 +3. 底部导航项目可点击尺寸至少 44px,命中测试落在自身或子元素;选中态不是黑色空心样式。 +4. 进入移动报销详情后底部 Tab 隐藏,顶部返回存在。 +5. `mobile-reimbursement-sticky-actions` 始终可见、按钮同一横行、底部间隙 `<=2px`、主按钮高度 `>=44px`。 +6. 滚动到页面最后一段内容;最后内容必须能完整滚到动作条上方,不能被固定动作条遮挡。 +7. pending/disabled 时文字或邻近说明解释原因;不能只靠灰色。 + +每个视口至少保存一张移动报销详情截图,命名 `09-mobile-reimbursement-x-.png`;另保存 `390x844` 的移动审批动作截图。 + +## 场景 5:报销材料与返回链路(R10/R11) + +PC `1440x960`: + +1. 报销详情材料区可见,普通用户文案不展示内部 code/OCR 字段名。 +2. “查看发票原件”和“查看补充附件”可用键盘依次聚焦,焦点可见。 +3. 从审批详情进入报销详情后返回按钮显示“返回审批详情”,点击回到原审批详情。 + +移动 `390x844` 企业微信 UA 模拟: + +1. 材料区与固定动作条同时可用;无横溢、无底部 Tab、按钮高度达标。 +2. 打开材料/发票对话框时,不得默认聚焦搜索框导致首屏键盘弹出。 + +截图: + +- `16-reimbursement-materials-pc-1440x960.png` +- `17-reimbursement-materials-mobile-390x844-wecom.png` + +## 场景 6:差旅不自动选中(R14) + +1. 使用含至少两条合成差旅记录的 mock,直接打开 `/travel-requests`,URL 不带 `id`。 +2. 等待列表加载稳定;URL 仍必须是 `/travel-requests`,不得自动变成 `?id=`,详情区不得假装用户已选择记录。 +3. 用户明确点击一条记录后,既有 `?id=` 行为可以继续出现;本场景不验证或扩展差旅业务能力。 + +截图:`18-travel-list-no-auto-select-1440x960.png`。 + +## 统一采集指标 + +每个场景都记录: + +- 场景编号和名称; +- 状态:`PASS` / `FAIL` / `PAUSED`; +- 合成角色; +- UA 类型; +- 视口; +- 起始 URL 与最终 URL; +- H1 或关键 `data-testid`; +- `scrollWidth`、`clientWidth`、横向溢出差值; +- sticky top/bottom/height、最后内容 bottom、按钮最小高度(适用时); +- 实际焦点控件顺序; +- console error 和 pageerror 数; +- 截图相对路径; +- finding(若有)及最小复现。 + +## Codex 本地执行结果(2026-08-07) + +以下结果只记录本地 Chromium 与 UA 模拟,不替代 OpenClaw 真机或公网验收: + +| 场景 | 状态 | 角色/UA 与视口 | 关键结果 | 证据/备注 | +| --- | --- | --- | --- | --- | +| 1. 状态徽章 | PASS | 本地 Chromium,1440x960 | 实际动态导入 `StatusBadge`;未知状态显示“未知状态”,`probation` 显示“试用期”,Todo 四态显示自然中文;console/pageerror=0 | `01-status-badge-fallback-1440x960.png` | +| 2. Portal | PASS | 合成员工/经理,PC 1440x960 | 3 个聚焦用例通过(3/3),顺序、权限过滤、中文错误与重试、焦点均有证据 | 任务目录内 Portal 截图 | +| 3. PC 审批 | PASS | 合成审批人,1280x800/1100x768 | 后果说明、取消不调用接口、转审 10 字门槛、焦点顺序通过(1/1) | 任务目录内审批截图 | +| 4. R6 七视口 | PASS(等价临时 runner) | iOS/Android 企业微信 UA + 普通移动 UA;320/360/375/390/393/414/430 | 7/7 通过;无横溢、无桌面表格、底部导航、sticky action、安全区和按钮尺寸通过 | `w320`–`w430` 系列;原始 spec 的过期请假断言失败另记为测试夹具问题 | +| 5. R111 材料区 | PASS(等价临时 runner) | iOS 企业微信 UA,移动 390x844 | 1/1 通过;材料区、sticky action、safe-area、按钮尺寸和无横溢通过 | 原始 spec 的同名文本 strict locator 命中两项;临时副本仅收窄 `.first()`,未改仓库测试 | +| 6. Wave3 详情 | PASS | PC/移动合成账号;1440、1280、1100 断点及移动代表视口 | PC/移动截图用例 2/2 通过,详情返回链路和双栏布局通过 | `01-pc-reimbursement-detail.png` 等 | +| 7. R14 差旅 | PASS | 合成管理员,PC 1440x960 | 两条合成记录加载后 URL 只有 `tab=requests`,没有 `id`;右侧保持未选择/新建态 | `18-travel-list-no-auto-select-1440x960.png` | + +### 结果边界 + +- 未修改 `client/src`、`server/`、仓库 E2E spec 或依赖;R6/R111 的临时副本均位于 `/tmp`,只用于收窄历史测试断言和重定向截图。 +- 原始 R6 请假断言与已确认“企业微信主办、OA 只读”边界不一致;原始 R111 断言违反 Playwright strict locator。两项均保留失败分类,不伪装成原始 spec 无条件通过。 +- 代表性 iPhone/Android 企业微信 WebView、真机键盘与 safe-area,以及公网/部署验证均为 `PAUSED`。 + +## 最终输出格式 + +先给总表: + +| 场景 | 状态 | 角色/UA | 视口 | 关键结果 | 证据 | +| --- | --- | --- | --- | --- | --- | + +然后分别列: + +1. `自动化 Chromium`:passed/failed/skipped 数和命令退出码。 +2. `企业微信 UA 模拟`:只说明模拟结果。 +3. `代表性真机`:若未执行,明确 `PAUSED`。 +4. `公网/部署`:本任务未执行,不得写成可线上测试。 +5. `发现项`:按 P0/P1/P2/P3,包含页面、视口、步骤、预期、实际和截图。 +6. `工作区检查`:结束后 `git status --short`;确认无业务代码改动、无历史截图目录污染。 + +只有场景 1–6 的适用浏览器断言全部通过且目标用例没有 failed/unexpected 时,才能写“本地 Chromium 聚焦回归通过”。即使如此,最终一句仍必须是: + +> 本地 Chromium 与企业微信 UA 模拟已完成;尚未部署,也未完成代表性企业微信真机验证,不能据此告知用户线上或真机可测。 + +--- diff --git a/.trellis/tasks/08-07-interaction-pattern-browser-regression/prd.md b/.trellis/tasks/08-07-interaction-pattern-browser-regression/prd.md new file mode 100644 index 00000000..dd20c348 --- /dev/null +++ b/.trellis/tasks/08-07-interaction-pattern-browser-regression/prd.md @@ -0,0 +1,125 @@ +# 交互规范 Chromium 浏览器回归补跑 + +## Goal + +补齐 `08-05-interaction-pattern-unification` 归档时因 Chromium 安装/沙箱条件不足而暂停的渲染层证据,证明已交付的交互统一在真实浏览器 DOM、布局、键盘焦点和移动固定动作条上没有回退。结果只用于本地回归和 OpenClaw 验收提词,不代表已部署、公网可测或企业微信真机通过。 + +## Background + +- 低风险统一子任务的源码合同、`typecheck`、`build`、聚焦 source-contract Playwright 和 Trellis 门禁已经通过;归档记录将需要 Chromium 的浏览器回归明确标为 `PAUSED`。 +- 本次补跑只验证既有实现,不新增业务行为。测试数据、登录态和 API 响应使用现有 E2E 合成夹具或页面路由 mock,不接触真实账号、真实票据或生产数据。 +- 适用事实源为 `docs/测试规约与回归门禁.md`、`docs/试运行与自动化验证手册.md`、`.trellis/spec/hyb-oa/frontend-react-vite-design.md` 和归档子任务的 `prd.md`/`implement.md`。 +- `frontend-design` 是视觉裁决入口;本环境未提供该 skill 时,本任务只依据现有共享组件、已有断言和事实源做保守的渲染验证,不建立新视觉规则。 + +## Scope + +本任务仅补浏览器级证据,覆盖以下已完成需求触点: + +- R1/R6:未知 `StatusBadge` 显示“未知状态”,员工在职阶段和 Todo 状态显示自然中文,不把技术枚举作为普通用户主文案。 +- R4:WelcomeDialog 按用户权限/能力过滤入口;无审批权限的合成员工不看到“待我审批”。 +- R9:Portal 区域失败持久显示自然中文、保留输入/页面状态并提供可聚焦的重试入口。 +- R10:`MobileStickyActionBar` 在移动审批、移动报销及 `BusinessEditTemplate` 消费点保持固定底部、安全区、内容留白、主次动作层级、pending/disabled 表达和可点击尺寸;移动详情最后内容不被动作条遮挡。 +- R11:登录、Portal、PC 审批详情、PC/移动报销详情的关键控件可通过键盘到达,焦点可见,label/按钮语义可识别。 +- R14:直接打开 `/travel-requests` 且未显式选择记录时不自动写入第一条 `id`;显式选择的既有查询参数详情行为不在本任务扩展。 + +浏览器矩阵: + +- PC:至少 `1440x960`;审批详情另覆盖 `1100x768` 与 `1280x800` 的壳层/双栏断点。 +- 移动:`320x568`、`360x740`、`375x667`、`390x844`、`393x873`、`414x896`、`430x932`;至少包含普通移动 UA、iOS/Android 企业微信 UA 模拟。 +- 浏览器引擎:优先仓库 Playwright Chromium;若使用系统 Chromium,必须记录可执行文件、启动参数和结果,不把环境替代方案写成产品证据。 + +## Requirements + +- RBR1:所有行为测试在 loopback HTTP origin 运行,服务端/前端使用合成数据;禁止公网写入、真实凭据、真实企业微信授权和生产数据库。 +- RBR2:每条测试记录最终 URL、页面主标题或关键 `data-testid`、角色/UA、视口、页面错误计数和关键几何指标(横向溢出、动作条底部间隙、按钮最小高度、焦点目标)。 +- RBR3:移动布局必须满足 `document.documentElement.scrollWidth <= viewportWidth + 2`,详情页隐藏底部 Tab,固定动作条底部间隙不超过 2px,关键按钮高度至少 44px(既有断言允许的 43.5px 下限只作为兼容记录)。 +- RBR4:截图只写入 `output/playwright/08-07-interaction-pattern-browser-regression/`;不得复用或覆盖历史任务证据目录。截图文件名包含页面、角色/UA 和视口。 +- RBR5:键盘回归至少验证登录字段顺序、Portal 主入口与重试按钮、审批转审字段/提交按钮、移动/PC 报销材料查看按钮的焦点移动;焦点环不可因 `outline: none` 或低对比度而不可见。 +- RBR6:测试失败先分类为代码、夹具、环境、数据或人工配置问题;环境缺失只能标 `PAUSED`/`BLOCKED`,不得将未启动浏览器写成 PASS,也不得因环境失败修改业务代码。 +- RBR7:Playwright/企业微信 UA 仅证明普通浏览器模拟行为;代表性 iPhone/Android 企业微信 WebView 仍单独保留为 `PAUSED` 或后续真机任务,不得合并为本任务 PASS。 + +## Acceptance Criteria + +- [x] A1:Chromium 可启动且本地 Vite/loopback 页面可访问;本轮目标断言使用原始或等价临时 runner 均以退出码 0 完成。R6/R111 未修改的历史 spec 各有一条测试断言问题,已在 `implement.md` 分类并保留失败证据,不归因于产品实现。 +- [x] A2:Portal 员工/管理员合成角色的首屏顺序、WelcomeDialog 权限过滤、区域失败中文提示与重试、键盘焦点均有浏览器证据;页面不显示内部错误 code、接口路径或原始 payload。 +- [x] A3:PC 审批详情的通过/驳回/退回后果说明、转审至少 10 字禁用原因与键盘焦点均通过;取消确认不会调用动作接口。 +- [x] A4:移动审批/报销详情在七个视口完成无横溢、无桌面表格、固定动作条可见、安全区/底部留白和按钮触控尺寸检查;iOS 与 Android 企业微信 UA 模拟均通过。R6/R111 使用未提交临时 runner 仅隔离测试断言问题。 +- [x] A5:PC/移动报销详情材料区、查看按钮焦点、回到审批详情的返回链路和 1440px/1100px/1280px 代表布局通过;截图已写入当前任务目录。 +- [x] A6:差旅直接入口不会自动把第一条记录写入 URL;该结果只证明缺陷已消除,不意味着差旅模块解冻或恢复能力。 +- [x] A7:`client` typecheck/build、任务 validate、流程合同、文档审计、Trellis governance、`git diff --check` 均在本任务收尾时通过;浏览器模拟之外的真机/公网证据按边界保留 `PAUSED`。 + +> 验收证据边界:上述 PASS 仅指本地 Chromium 和企业微信 UA 模拟。代表性企业微信真机 WebView、部署后公网检查和真实账号路径仍保持 `PAUSED`,不能据此告知用户线上或真机可测。 + +## Out of Scope + +- 不修改 `client/src`、`server/`、API、URL、数据库、权限模型、审批/付款状态机、生产配置或依赖版本。 +- 不新增或迁移业务 E2E 夹具以外的产品能力;不修复发现的超范围业务缺口。 +- 不执行公网部署、真实企业微信登录/消息点击、真实账号/票据/OCR、真实付款或生产数据库操作。 +- 不把现有历史截图目录改名、覆盖、清理或回填为本任务证据。 +- 不把企业微信 UA 自动化、系统 Chromium 或 OpenClaw 结果表述为代表性真机 WebView 通过。 + +## Test Plan + +### 1. 前置与环境记录 + +1. `command -v npx`、`node --version`、`npm --version`、`npx playwright --version`。 +2. 检查仓库 Playwright Chromium;缺失时仅在获准本地环境执行 `npx playwright install chromium`,记录下载/启动结果。 +3. 启动本地 Vite(或使用 `scripts/qa/run-local-candidate.sh focused` 提供的 loopback 服务),确认 `/login` 可访问;不使用带凭据公网 URL。 +4. 建立并只使用 `output/playwright/08-07-interaction-pattern-browser-regression/` 证据目录。 + +### 2. 聚焦浏览器用例 + +按顺序、单 worker 运行以下既有用例;具体 grep 以测试标题为准,避免把历史专项的无关长流程混入本轮: + +```bash +cd client +npx playwright test tests/e2e/login-portal-ux.spec.ts \ + --grep 'Portal 员工视角优先显示今日动作顺序|Portal 加载失败持久显示自然中文并可重新加载|Portal 新员工只显示轻量欢迎入口' \ + --workers=1 --reporter=list +npx playwright test tests/e2e/workflow-action-confirm-ui.spec.ts \ + --grep 'PC 审批详情通过、驳回、退回都先解释动作后果' \ + --workers=1 --reporter=list +npx playwright test tests/e2e/r6-mobile-responsive-system-hotfix.spec.ts \ + --grep '关键移动页面跨视口自适应且首页宫格不挤压' \ + --workers=1 --reporter=list +npx playwright test tests/e2e/r111-invoice-reimbursement-guard.spec.ts \ + --grep '企业微信手机端保持移动布局,发票和附件能力与 PC 一致' \ + --workers=1 --reporter=list +npx playwright test tests/e2e/pc-detail-mobile-visual-wave3.spec.ts \ + --grep 'Wave3 移动关键页视觉截图|Wave3 PC 详情和通知中心视觉截图' \ + --workers=1 --reporter=list +``` + +`r6` 的七个视口和 `r111` 的企业微信 UA 是本任务的移动矩阵主证据;若既有 spec 将截图写向历史目录,执行方必须改用不污染历史证据的临时运行副本或等价 OpenClaw 流程,并把结果收口到当前任务目录,不得直接覆盖历史文件。 + +### 3. OpenClaw 人工/浏览器提词 + +测试提词保存在同目录 `openclaw-test-prompt.md`,要求 OpenClaw: + +- 使用合成账号/接口 mock 和 loopback 地址;先记录环境,再逐场景执行。 +- 每个场景回报角色、UA、视口、起始/最终 URL、H1 或关键 test id、PASS/FAIL/PAUSED、截图相对路径和发现项。 +- 逐项验证 Portal 权限/重试、审批确认与焦点、移动固定动作条/安全区/溢出、报销材料焦点、差旅不自动选中。 +- 遇到浏览器沙箱、缺失 Chromium、网络或真机条件阻塞时立即停止该场景并写 `PAUSED`,说明重试前置;不得用 DOM 静态读取或源码测试冒充渲染通过。 + +### 4. 收口门禁 + +```bash +cd client && npm run typecheck && npm run build +python3 ./.trellis/scripts/task.py validate 08-07-interaction-pattern-browser-regression +node scripts/qa/check-process-contract.mjs --baseline --json +node scripts/qa/audit-docs.mjs --check-registry +node scripts/qa/check-trellis-governance.mjs --json +git diff --check +``` + +收口报告必须分开列出:本地源码/静态证据、Chromium 浏览器证据、企业微信 UA 模拟证据、代表性真机证据、公网/部署证据。只有前两类在本任务范围内;后两类缺失时不得把父任务的完成数解释为真机已验收。 + +## Risks and Deferred Items + +- 当前已知风险是 Chromium 可执行文件或沙箱策略仍可能不可用;处理为 `PAUSED`,不改产品代码,不降低验收条件。 +- 移动固定动作条的视觉层和键盘/可达性行为仍需代表性真机确认;OpenClaw/Playwright 只能补浏览器模拟证据。 +- 若浏览器回归发现实现缺陷,先记录最小复现和归属;超出低风险子任务范围的修复另建 Trellis task,不在本回归任务中顺手扩大范围。 + +## Open Questions + +无。范围、证据边界、移动视口、截图目录和 `PAUSED` 判定均已确认。 diff --git a/.trellis/tasks/08-07-interaction-pattern-browser-regression/task.json b/.trellis/tasks/08-07-interaction-pattern-browser-regression/task.json new file mode 100644 index 00000000..585f7dbf --- /dev/null +++ b/.trellis/tasks/08-07-interaction-pattern-browser-regression/task.json @@ -0,0 +1,38 @@ +{ + "id": "interaction-pattern-browser-regression", + "name": "interaction-pattern-browser-regression", + "title": "交互规范 Chromium 浏览器回归补跑", + "description": "补跑 08-05-interaction-pattern-unification 因 Chromium 环境阻塞的真实浏览器回归,覆盖 PC、移动和企业微信 UA 的 R1/R4/R9/R10/R11/R14 渲染、可达性与固定动作条证据;不改业务代码,浏览器条件不足时记录 PAUSED。", + "status": "in_progress", + "dev_type": null, + "scope": "browser-regression-evidence-for-08-05-interaction-pattern-unification", + "package": "client", + "priority": "P2", + "creator": "shunli", + "assignee": "shunli", + "createdAt": "2026-08-07", + "completedAt": null, + "branch": null, + "base_branch": "main", + "worktree_path": null, + "commit": null, + "pr_url": null, + "subtasks": [], + "children": [], + "parent": "08-05-product-interaction-consistency", + "relatedFiles": [ + "client/playwright.config.ts", + "client/tests/e2e/login-portal-ux.spec.ts", + "client/tests/e2e/workflow-action-confirm-ui.spec.ts", + "client/tests/e2e/r6-mobile-responsive-system-hotfix.spec.ts", + "client/tests/e2e/r111-invoice-reimbursement-guard.spec.ts", + "client/tests/e2e/pc-detail-mobile-visual-wave3.spec.ts", + "client/tests/e2e/r89-mobile-login-navigation.spec.ts", + "docs/测试规约与回归门禁.md", + "docs/试运行与自动化验证手册.md", + ".trellis/tasks/archive/2026-08/08-05-interaction-pattern-unification/prd.md", + ".trellis/tasks/archive/2026-08/08-05-interaction-pattern-unification/implement.md" + ], + "notes": "仅使用合成数据和 loopback 环境;Playwright/企业微信 UA 自动化不等同于代表性真机 WebView。截图只允许写入 output/playwright/08-07-interaction-pattern-browser-regression/。", + "meta": {} +} \ No newline at end of file