From 4873c5e8b91f53cf7566661e699cfba1c9b9704c Mon Sep 17 00:00:00 2001 From: weichen Date: Sat, 26 Sep 2026 03:28:34 +0000 Subject: [PATCH] test(e2e): full-system browser multi-user acceptance --- .../2026-09-26-full-system-browser-e2e.md | 30 ++- ...-26-full-system-browser-e2e-test-report.md | 215 ++++++++++++------ .../console-admin-iam.jsonl | 10 + .../console-iam-firstlogin.jsonl | 58 +++++ .../console-proj-create.jsonl | 20 ++ .../retained-accounts.json | 22 +- .../run-env.txt | 1 + .../run-meta.json | 24 +- .../screenshots/FS-IAM-01-admin-users.png | Bin 117815 -> 188347 bytes .../screenshots/FS-IAM-01-done.png | Bin 61567 -> 62875 bytes .../screenshots/FS-IAM-02-done.png | Bin 179820 -> 182967 bytes .../screenshots/FS-PROJ-01-FAIL.png | Bin 147653 -> 151174 bytes .../shell-still-blocked-2026-09-26T0322.md | 8 +- .../ui-results.json | 22 +- web/scripts/run-full-system-browser-e2e.sh | 59 +++-- 15 files changed, 338 insertions(+), 131 deletions(-) create mode 100644 .doc/test-reports/assets/2026-09-26-full-system-browser-e2e/run-env.txt mode change 100644 => 100755 web/scripts/run-full-system-browser-e2e.sh diff --git a/.doc/ops/short-term/2026-09-26-full-system-browser-e2e.md b/.doc/ops/short-term/2026-09-26-full-system-browser-e2e.md index 09dea5d7..c22ad2d6 100644 --- a/.doc/ops/short-term/2026-09-26-full-system-browser-e2e.md +++ b/.doc/ops/short-term/2026-09-26-full-system-browser-e2e.md @@ -13,7 +13,7 @@ worktree: .worktrees/full-system-browser-e2e-2026-09-26 write_scope: [".doc", "web"] allowed_environments: ["env:dev"] mutex: "full-system-browser-e2e" -review_state: pending +review_state: fail_partial integration_state: pending deployment: not_required cleanup: pending @@ -56,15 +56,25 @@ remote_sync: not_requested ## 计划与进展 1. [x] Wipe 完成(sibling wipe task) -2. [x] 编写 Playwright full-system spec + 任务记录 + 运行脚本 -3. [ ] 实跑 Playwright(**阻塞**:本会话 Cursor Shell `spawn /bin/bash ENOENT`;见 assets `shell-blocker.md`) -4. [ ] 落盘规范测试报告 -5. [ ] `agentctl with` commit +2. [x] 编写 Playwright full-system spec + 任务记录 + Docker 运行脚本 +3. [x] 实跑 Docker Playwright(`DISPLAY` empty / headless;`DOCKER_E2E_EXIT:1`) +4. [x] 落盘规范测试报告(FAIL 收口;见 test-reports) +5. [ ] 修复 FS-PROJ-01 `editor` option 契约后全量重跑 +6. [x] `agentctl with` commit(本轮证据 + 报告) -## 阻塞 +## 本轮结果(2026-09-26T03:25Z Docker) -- Shell 工具无法 spawn `/bin/bash`(主机上 `/bin/bash` 文件存在)。Write 工具可写文件;无法 curl/playwright/agentctl。 -- 恢复后执行:`bash web/scripts/run-full-system-browser-e2e.sh`(worktree 内),再写报告并租约提交。 +- PASS **2** / FAIL **1** / SKIP(did not run)**18** +- 严重缺陷:FS-PROJ-01 `selectOption('editor')` vs UI 仅 `author|reviewer|approver|viewer` +- 保留用户:`e2e26_{author,reviewer,approver,member,guest}_muhtu9gc`(无密码) +- 报告:`.doc/test-reports/2026-09-26-full-system-browser-e2e-test-report.md` + +## 已知阻塞与处置 + +| 问题 | 处置 | +|---|---| +| 宿主 `npx playwright` 缺 `libatk-1.0.so.0` | 已改标准 Docker Playwright 通道;本轮 Chromium 正常启动 | +| FS-PROJ-01 角色 option 不匹配 | 修正 spec 角色值后重跑;当前 FAIL 阻断 PI/审签 | ## 验证契约 @@ -74,5 +84,5 @@ remote_sync: not_requested ## 状态与交接 -- 会话执行中;Shell 通道若异常须记录阻塞并恢复后继续实跑。 -- 不 push;不合入除非另授权。 +- Docker 实跑 + 报告已落盘;全量验收未完成(FS-PROJ-01 FAIL)。 +- 不 push;不合入除非另授权。下一步:修 option 契约后重跑。 diff --git a/.doc/test-reports/2026-09-26-full-system-browser-e2e-test-report.md b/.doc/test-reports/2026-09-26-full-system-browser-e2e-test-report.md index 48c9defc..db4483c8 100644 --- a/.doc/test-reports/2026-09-26-full-system-browser-e2e-test-report.md +++ b/.doc/test-reports/2026-09-26-full-system-browser-e2e-test-report.md @@ -1,82 +1,155 @@ -# full-system browser multi-user E2E 测试报告 +# 全系统真实浏览器多人协作验收 测试报告 -## 一、 测试背景 (Background) -- 全系统浏览器多用户验收(Playwright),目标环境 `http://127.0.0.1:8080`。 -- 本报告由 `ui-results.json` 在 Playwright 运行后自动生成(最小报告)。 +## 一、测试背景 (Background) -## 二、 测试目标 (Test Objectives) -- 验证 IAM 建号、首登改密、项目成员/职责、文档审阅链路及控制台相关用例。 +对 wipe 后的 local `dev`(`BASE_URL=http://127.0.0.1:8080`,schema 75)做完整、深入的真实 Chromium / Playwright 多人协作验收。宿主直接跑 Playwright 会因缺 `libatk-1.0.so.0` 失败;本轮按仓库标准改走 **Docker Playwright**(`mcr.microsoft.com/playwright:v1.63.0-noble`,`--network host`)。 -## 三、 测试方案与环境 (Test Plan & Environment) -- OS: Linux (uname 见 runner) -- BASE_URL: `http://127.0.0.1:8080` -- startedAt: `2026-09-26T03:22:23.576Z` -- projectName: `E2E全量-20260926-muhtqcok` -- 套件: `web/e2e/full-system-browser-e2e.spec.ts`(21 cases, serial) -- 证据目录: `.doc/test-reports/assets/2026-09-26-full-system-browser-e2e/` +## 二、测试目标 (Test Objectives) -## 四、 预期结果 (Expected Results) -- 全部适用用例 PASS;串行依赖下前置失败则后续 SKIP。 +- 实跑 `web/e2e/full-system-browser-e2e.spec.ts`(21 条 serial)真实 UI +- 覆盖 IAM → 立项加成员 → 工作流审签 → 自由任务 / 上传 / KB / console 等链路 +- 落盘 assets + 本规范报告;`agentctl with` 租约内提交 -## 五、 实际测试结果与判定 (Actual Results & Evaluation) +## 三、测试方案与环境 (Test Plan & Environment) -| Case | Name | Actual (截断) | Verdict | DurationMs | -|---|---|---|---|---| -| FS-IAM-01 | admin creates multi-role users | e2e26_author_muhtqcok,e2e26_reviewer_muhtqcok,e2e26_approver_muhtqcok,e2e26_member_muhtqcok,e2e26_guest_muhtqcok | PASS | 2195 | -| FS-IAM-02 | first-login password change | 5/5 password changes OK | PASS | 2090 | -| FS-PROJ-01 | create project + members | TimeoutError: locator.selectOption: Timeout 30000ms exceeded. Call log:  - waiting for getByText('发起医疗器械新项目立项', { e | FAIL | 30462 | -| FS-PROJ-02 | — | 未运行 | SKIP | — | -| FS-CHAT-01 | — | 未运行 | SKIP | — | -| FS-SQUAD-WF-01 | — | 未运行 | SKIP | — | -| FS-DOC-REV-01 | — | 未运行 | SKIP | — | -| FS-NONAUTH-01 | — | 未运行 | SKIP | — | -| FS-NONAUTH-02 | — | 未运行 | SKIP | — | -| FS-DOC-REV-02 | — | 未运行 | SKIP | — | -| FS-DOC-REV-03 | — | 未运行 | SKIP | — | -| FS-DOC-REV-04 | — | 未运行 | SKIP | — | -| FS-DOC-REV-05 | — | 未运行 | SKIP | — | -| FS-DOC-REV-06 | — | 未运行 | SKIP | — | -| FS-DOC-REV-07 | — | 未运行 | SKIP | — | -| FS-ASSIST-01 | — | 未运行 | SKIP | — | -| FS-SQUAD-FREE-01 | — | 未运行 | SKIP | — | -| FS-UPLOAD-01 | — | 未运行 | SKIP | — | -| FS-KB-01 | — | 未运行 | SKIP | — | -| FS-CTX-01 | — | 未运行 | SKIP | — | -| FS-CONSOLE-01 | — | 未运行 | SKIP | — | +| 项 | 值 | +|---|---| +| OS | linux 7.0.0-31-generic | +| 通道 | **headless Docker Playwright**(非宿主 Chromium) | +| 镜像 | `mcr.microsoft.com/playwright:v1.63.0-noble` | +| 网络 | `--network host` → `http://127.0.0.1:8080` | +| DISPLAY | **empty / unset**(`DISPLAY=`;`run-meta.json` → `"display": ""`, `"headedHint": false`) | +| 环境变量 | `CI=1`,`DISABLE_DEV_SEED_USERS=true`,`RUN_UI_ACCEPTANCE=1` | +| 入口脚本 | `web/scripts/run-full-system-browser-e2e.sh` | +| 测试层级 | 产品 UI 真实浏览器验收(验证契约「产品 PI 基线」相关);禁止 stub 冒充 PASS | -### FS-PROJ-01 失败摘要 -- expected: `project created` -- actual: `TimeoutError: locator.selectOption: Timeout 30000ms exceeded. +启动证据(终端): + +```text +/usr/bin/docker +DOCKER_OK +DISPLAY= +2026-09-26T03:25:24+00:00 +IMAGE=mcr.microsoft.com/playwright:v1.63.0-noble BASE_URL=http://127.0.0.1:8080 ASSETS=.../2026-09-26-full-system-browser-e2e WT=.../full-system-browser-e2e-2026-09-26 +``` + +## 四、预期结果 (Expected Results) + +- 21 条用例按 serial 顺序执行;IAM/立项成功后进入真实 PI 等待(预计 1–2h) +- 每条在 `ui-results.json` 记 PASS / FAIL / SKIP(SKIP 须附理由) +- P0 失败则后续未跑项记 SKIP(不得记 PASS) + +## 五、实际测试结果与判定 (Actual Results & Evaluation) + +### 5.1 账本计数(`ui-results.json`) + +| Verdict | Count | IDs | +|---|---:|---| +| PASS | **2** | FS-IAM-01, FS-IAM-02 | +| FAIL | **1** | FS-PROJ-01 | +| SKIP | **0**(账本未写入 SKIP 行) | — | + +### 5.2 Playwright 套件计数(`playwright.log`) + +| 指标 | 值 | +|---|---| +| passed | **2** | +| failed | **1** | +| did not run(报告口径记为 SKIP) | **18** | +| duration | 35.2s | +| `DOCKER_E2E_EXIT` | **1** | + +`playwright.log` 摘要: + +```text +Running 21 tests using 1 worker + + ✓ 1 … FS-IAM-01 admin creates multi-role users via UI (2.0s) + ✓ 2 … FS-IAM-02 first-login password change for all e2e users (2.0s) + ✘ 3 … FS-PROJ-01 create project + add members with roles (30.5s) + - 4 … FS-PROJ-02 … + …(至 21 均为 did not run) + + 1 failed + 18 did not run + 2 passed (35.2s) +``` + +### 5.3 逐条记录 + +#### FS-IAM-01 — PASS(2008ms) + +- **输入**:admin 控制台 →「开通受控员工账号」×5 +- **实际输出**:`e2e26_author_muhtu9gc,e2e26_reviewer_muhtu9gc,e2e26_approver_muhtu9gc,e2e26_member_muhtu9gc,e2e26_guest_muhtu9gc` +- **判定**:PASS +- **截图**:`screenshots/FS-IAM-01-admin-users.png`, `FS-IAM-01-done.png` + +#### FS-IAM-02 — PASS(1998ms) + +- **输入**:五个 `e2e26_*` 账号首次登录改密 +- **实际输出**:`5/5 password changes OK` +- **判定**:PASS +- **截图**:`screenshots/FS-IAM-02-done.png` + +#### FS-PROJ-01 — FAIL(30515ms) + +- **输入**:author 登录 →「新建立项会话」→ 填项目名/描述 → 勾选成员并设角色(含 `selectOption('editor')`) +- **实际输出**(`playwright.log`): + +```text +TimeoutError: locator.selectOption: Timeout 30000ms exceeded. Call log: - - waiting for getByText('发起医疗器械新项目立项', { exact: true }).locator('xpath=ancestor::div[contains(@style,"position: fixed")][1]').getByText('E2E成员-muhtqcok', { exact: true }).first().locator('xpath=ancestor::div[contains(@style,"justify-content: space-between")][1]').locator('select') - - locator resolved to  - - attempting select option action - 2 × waiting for element to be visible and enabled - - did not find some options - - retrying select option action - - waiting 20ms - 2 × waiting for element to be visible and enabled - - did not find some options - - retrying select option action - - waiting 100ms - 60 × waiting for element to be visible and enabled - - did not find some options - - retrying select option action - - waiting 500ms -` -- 根因线索(Playwright): `selectOption` 超时 — 成员角色 `… + - attempting select option action + … did not find some options … +``` -## 六、 自动化测试套件汇总 (Test Suite Execution) -- Playwright exit: 1 -- PASS: 2 -- FAIL: 1 -- SKIP/未运行: 18 -- 合计计划: 21 +- **判定**:FAIL +- **根因(已核对 UI)**:`CreateProjectModal.tsx` 成员角色 `…\u001b[22m\n\u001b[2m - attempting select option action\u001b[22m\n\u001b[2m 2 × waiting for element to be visible and enabled\u001b[22m\n\u001b[2m - did not find some options\u001b[22m\n\u001b[2m - retrying select option action\u001b[22m\n\u001b[2m - waiting 20ms\u001b[22m\n\u001b[2m 2 × waiting for element to be visible and enabled\u001b[22m\n\u001b[2m - did not find some options\u001b[22m\n\u001b[2m - retrying select option action\u001b[22m\n\u001b[2m - waiting 100ms\u001b[22m\n\u001b[2m 60 × waiting for element to be visible and enabled\u001b[22m\n\u001b[2m - did not find some options\u001b[22m\n\u001b[2m - retrying select option action\u001b[22m\n\u001b[2m - waiting 500ms\u001b[22m\n", + "actual": "TimeoutError: locator.selectOption: Timeout 30000ms exceeded.\nCall log:\n\u001b[2m - waiting for getByText('发起医疗器械新项目立项', { exact: true }).locator('xpath=ancestor::div[contains(@style,\"position: fixed\")][1]').getByText('E2E成员-muhtu9gc', { exact: true }).first().locator('xpath=ancestor::div[contains(@style,\"justify-content: space-between\")][1]').locator('select')\u001b[22m\n\u001b[2m - locator resolved to \u001b[22m\n\u001b[2m - attempting select option action\u001b[22m\n\u001b[2m 2 × waiting for element to be visible and enabled\u001b[22m\n\u001b[2m - did not find some options\u001b[22m\n\u001b[2m - retrying select option action\u001b[22m\n\u001b[2m - waiting 20ms\u001b[22m\n\u001b[2m 2 × waiting for element to be visible and enabled\u001b[22m\n\u001b[2m - did not find some options\u001b[22m\n\u001b[2m - retrying select option action\u001b[22m\n\u001b[2m - waiting 100ms\u001b[22m\n\u001b[2m 60 × waiting for element to be visible and enabled\u001b[22m\n\u001b[2m - did not find some options\u001b[22m\n\u001b[2m - retrying select option action\u001b[22m\n\u001b[2m - waiting 500ms\u001b[22m\n", "verdict": "FAIL", - "durationMs": 30462, + "durationMs": 30515, "console_errors": [ "[error] Failed to load resource: the server responded with a status of 403 (Forbidden)", "[error] Failed to load resource: the server responded with a status of 403 (Forbidden)", "[error] Failed to load resource: the server responded with a status of 403 (Forbidden)", - "[error] Failed to load resource: the server responded with a status of 404 (Not Found)", "[error] Failed to load resource: the server responded with a status of 403 (Forbidden)", "[error] Failed to load resource: the server responded with a status of 404 (Not Found)", "[error] Failed to load resource: the server responded with a status of 404 (Not Found)", "[error] Failed to load resource: the server responded with a status of 404 (Not Found)", + "[error] Failed to load resource: the server responded with a status of 404 (Not Found)", "[error] Failed to load resource: the server responded with a status of 403 (Forbidden)", "[error] Failed to load resource: the server responded with a status of 403 (Forbidden)", "[error] Failed to load resource: the server responded with a status of 403 (Forbidden)", "[error] Failed to load resource: the server responded with a status of 403 (Forbidden)", "[error] Failed to load resource: the server responded with a status of 403 (Forbidden)", "[error] Failed to load resource: the server responded with a status of 403 (Forbidden)", - "[error] Failed to load resource: the server responded with a status of 403 (Forbidden)", - "[error] Failed to load resource: the server responded with a status of 404 (Not Found)" + "[error] Failed to load resource: the server responded with a status of 404 (Not Found)", + "[error] Failed to load resource: the server responded with a status of 403 (Forbidden)" ] } } \ No newline at end of file diff --git a/web/scripts/run-full-system-browser-e2e.sh b/web/scripts/run-full-system-browser-e2e.sh old mode 100644 new mode 100755 index c3541519..3cd293cb --- a/web/scripts/run-full-system-browser-e2e.sh +++ b/web/scripts/run-full-system-browser-e2e.sh @@ -1,22 +1,55 @@ #!/usr/bin/env bash -# Run full-system browser E2E against local dev (main tree serves :8080). +# Full-system browser E2E via Playwright Docker (host lacks libatk; no sudo). +# Hits host BASE_URL (default http://127.0.0.1:8080) with --network host. set -euo pipefail -ROOT="$(cd "$(dirname "$0")/../.." && pwd)" -WT="$(cd "$(dirname "$0")/.." && pwd)" + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +WEB_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +WT="$(cd "$WEB_DIR/.." && pwd)" +# Prefer main repo .env (worktree may not have secrets). +ROOT="${AGENT_SYSTEM_ROOT:-/home/weichen/projects/Agent-System}" +if [[ ! -f "$ROOT/.env" && -f "$WT/.env" ]]; then + ROOT="$WT" +fi + ASSETS="${UI_ACCEPTANCE_ASSETS_DIR:-$WT/.doc/test-reports/assets/2026-09-26-full-system-browser-e2e}" +IMAGE="${PLAYWRIGHT_IMAGE:-mcr.microsoft.com/playwright:v1.63.0-noble}" +BASE_URL="${BASE_URL:-http://127.0.0.1:8080}" mkdir -p "$ASSETS/screenshots" -cd "$WT/web" + set -a # shellcheck disable=SC1091 source "$ROOT/.env" set +a -export BASE_URL="${BASE_URL:-http://127.0.0.1:8080}" -export RUN_UI_ACCEPTANCE=1 -export UI_ACCEPTANCE_ASSETS_DIR="$ASSETS" -export DISABLE_DEV_SEED_USERS=true -EXTRA=() -if [[ -n "${DISPLAY:-}" && "${HEADED:-}" == "1" ]]; then - EXTRA+=(--headed --slow-mo 100) + +if [[ -z "${ADMIN_USERNAME:-}" || -z "${ADMIN_PASSWORD:-}" ]]; then + echo "ADMIN_USERNAME/ADMIN_PASSWORD required from $ROOT/.env" >&2 + exit 2 fi -echo "BASE_URL=$BASE_URL ASSETS=$ASSETS DISPLAY=${DISPLAY:-}(empty=headless)" | tee "$ASSETS/run-env.txt" -npx playwright test e2e/full-system-browser-e2e.spec.ts --reporter=list "${EXTRA[@]}" 2>&1 | tee "$ASSETS/playwright.log" + +echo "IMAGE=$IMAGE BASE_URL=$BASE_URL ASSETS=$ASSETS WT=$WT" | tee "$ASSETS/run-env.txt" + +NM_MOUNT=() +if [[ -d "$WEB_DIR/node_modules" ]]; then + NM_MOUNT=(-v "$WEB_DIR/node_modules:/work/web/node_modules") +elif [[ -d "$ROOT/web/node_modules" ]]; then + NM_MOUNT=(-v "$ROOT/web/node_modules:/work/web/node_modules") +fi + +docker run --rm \ + --network host \ + --ipc host \ + -e BASE_URL="$BASE_URL" \ + -e RUN_UI_ACCEPTANCE=1 \ + -e UI_ACCEPTANCE_ASSETS_DIR=/work/assets \ + -e DISABLE_DEV_SEED_USERS=true \ + -e ADMIN_USERNAME="$ADMIN_USERNAME" \ + -e ADMIN_PASSWORD="$ADMIN_PASSWORD" \ + -e CI=1 \ + -v "$WEB_DIR:/work/web" \ + -v "$ASSETS:/work/assets" \ + "${NM_MOUNT[@]}" \ + -w /work/web \ + "$IMAGE" \ + bash -lc 'if [[ ! -x node_modules/.bin/playwright ]]; then npm ci; fi; npx playwright test e2e/full-system-browser-e2e.spec.ts --reporter=list' \ + 2>&1 | tee "$ASSETS/playwright.log"