{ "title": "接口错误 Message 回归报告", "status": "PASS_WITH_LEGACY_BLOCKERS", "generatedAt": "2026-09-05T17:36:20.720Z", "startedAt": "2026-09-05T17:32:19.650Z", "durationMs": 84090.698, "passed": 9, "total": 9, "screenshotCount": 17, "requestCount": 58, "pageErrorCount": 0, "validation": { "commands": [ { "command": "pnpm run build", "scope": "unreal_tran_web", "status": "PASS", "details": "最终 vue-tsc、Vite 与 legacy iframe public/dist 哈希校验通过;仍有既有 chunk 体积提示。", "log": "validation/build.log" }, { "command": "node --test tools/scene-cover-api.test.mjs tools/guide-error-message.test.mjs", "scope": "ute2e", "status": "PASS", "details": "20/20 通过,包含保存失败只提示一次、阻断发布与离开,以及指导书/场景错误提示回归。", "log": "validation/runtime-tests.log" }, { "command": "pnpm exec tsc --noEmit --target ES2022 --module ESNext --moduleResolution Bundler --strict --types 'node,@playwright/test' tests/api-error-messages.spec.ts api-error-messages.config.ts", "scope": "ute2e", "status": "PASS", "details": "本轮新增浏览器测试与配置类型检查通过。" }, { "command": "git diff --check", "scope": "unreal_tran_web、ute2e", "status": "PASS", "details": "主任务检查通过;报告生成后再次核验本轮文件。" } ] }, "authentication": { "title": "认证提示附加回归", "status": "PASS_WITH_LEGACY_BLOCKERS", "result": "共实际运行 5 项:3 项通过;2 项旧强制改密用例受当前路由契约阻断,未验证到原断言。主报告 9 项结果单独统计。", "screenshotPathBase": "api-error-messages-20260906", "environment": "Edge headless,http://127.0.0.1:6180,认证 API 全部由 Playwright 拦截模拟;trace/video 关闭。", "counts": { "executed": 5, "passed": 3, "legacyBlocked": 2, "skipped": 0 }, "runs": [ { "command": "pnpm exec playwright test --config E:\\work\\edit_3d\\.codex-tmp\\auth-message-regression.config.ts", "result": "首轮运行当时文件中的 4 项旧回归,2 passed / 2 failed(均为输入定位超时),用时 45.4 秒;原始结果保留。", "json": "authentication/results.json", "html": "authentication/html/index.html", "log": "authentication/run.log" }, { "command": "pnpm exec playwright test --config E:\\work\\edit_3d\\.codex-tmp\\auth-login-message.config.ts", "result": "新增当前登录 API 错误回归独立执行,1 passed,用时 10.8 秒。", "json": "authentication/login-message/results.json", "html": "authentication/login-message/html/index.html", "log": "authentication/login-message/run.log" } ], "checks": [ { "title": "859:无可登录教员时账号选择器禁用", "status": "PASS", "result": "保留业务空态,选择器不可展开。", "screenshots": [ { "title": "无教员业务空态", "path": "authentication/screenshots/859-passed.png" } ] }, { "title": "861:旧强制改密不一致校验", "status": "BLOCKED", "rawStatus": "failed", "result": "当前 /change-password 对已认证用户重定向 /dashboard;旧 fixture 只有强制改密标记而无工作台权限,后续导航取消,停留在启动页,未进入改密表单。该旧用例不适用于当前路由契约,本次未改路由、未跳过或记为通过。", "screenshots": [ { "title": "旧改密入口阻断", "path": "authentication/screenshots/861-failed.png" } ] }, { "title": "864:旧强制改密停用账号提示", "status": "BLOCKED", "rawStatus": "failed", "result": "与 861 相同的既有路由契约阻断,未能提交初始改密接口,也未验证一次性登录提示。原始失败证据保留。", "screenshots": [ { "title": "旧停用账号流程阻断", "path": "authentication/screenshots/864-failed.png" } ] }, { "title": "普通会话过期不泄露后端内部详情", "status": "PASS", "result": "跳转登录页,登录错误栏为空,不显示内部会话或刷新令牌详情,仅发起一次刷新请求。", "screenshots": [] }, { "title": "当前管理员登录 API 401 错误使用自动消失的 Message", "status": "PASS", "result": "实际点击登录;mock POST /auth/login 返回 401。只出现一条 .el-message--error,#login-error 始终为空;未点击关闭,Message 自动消失。登录请求 1 次,刷新请求 0 次。", "screenshots": [ { "title": "登录失败 Message", "path": "authentication/login-message/screenshots/login-api-error-message.png" }, { "title": "Message 自动消失后", "path": "authentication/login-message/screenshots/login-api-error-message-dismissed.png" } ] } ], "limitations": [ "仅模拟认证接口与浏览器交互,不使用真实账号,不验证后端认证规则或真实密码修改。", "未运行依赖真实账号的 auth.spec.ts 全量;仅更新其中接口错误提示的断言选择器。", "两条旧强制改密用例没有通过,不能作为当前改密功能验证证据;既有路由策略不在本轮提示展示调整范围。" ] }, "stages": [ { "title": "资料", "text": "按本轮“接口错误使用 Message,不保留常驻错误横条”的要求检查。沿用已确认的教学业务边界:离线识别回放、观察模式、步骤反馈和表单校验仍需可见。" }, { "title": "原型", "text": "错误发生时顶部短暂提示;可以手动关闭,约 4.5 秒自动消失。同一错误合并展示;失败后仍可重新加载,已成功取得的数据不因后续刷新失败消失。" }, { "title": "设计", "text": "共享 Message 处理负责统一展示与缓存页面生命周期;请求层保留业务错误码、HTTP 状态和 requestId,静默请求不会自行弹窗。未取得数据与空结果保持区分。" }, { "title": "开发", "text": "代表性覆盖内容制作、系统用户与教学实施,包括训练编辑器加载失败的重试入口。接口异常详情仅在 Message 中展示;表单必填错误、项目编码说明和离线运行模式继续保留。" }, { "title": "测试", "text": "使用真实 Vue / Element Plus 页面、Edge 无头浏览器和浏览器级 API mock。覆盖本机与局域网入口。身份及接口数据均为合成测试数据;不登录真实账号、不写业务库,不将本轮测试称为真实服务端或设备联调。" } ], "checks": [ { "title": "内容列表:错误自动消失、重试恢复、再次失败保留旧数据", "status": "PASS", "durationMs": 12754, "screenshots": [ { "title": "01-content-error-message", "path": "screenshots/01-content-error-message.png" }, { "title": "02-content-old-data-retained", "path": "screenshots/02-content-old-data-retained.png" } ], "isolation": { "requests": [ { "method": "GET", "path": "/api/auth/v1/system-config/public" }, { "method": "GET", "path": "/api/auth/v1/auth/me" }, { "method": "GET", "path": "/api/auth/v1/menus/navigation" }, { "method": "GET", "path": "/api/tran/v1/content/projects/summary" }, { "method": "GET", "path": "/api/tran/v1/content/projects" }, { "method": "GET", "path": "/api/tran/v1/content/projects" }, { "method": "GET", "path": "/api/tran/v1/content/projects/summary" }, { "method": "GET", "path": "/api/tran/v1/content/projects" } ], "unexpected": [], "writes": [], "pageErrors": [] } }, { "title": "系统用户:并行同错合并一条,重复搜索可再次提示", "status": "PASS", "durationMs": 12705, "screenshots": [ { "title": "03-users-grouped-message", "path": "screenshots/03-users-grouped-message.png" }, { "title": "04-users-retry-without-banner", "path": "screenshots/04-users-retry-without-banner.png" } ], "isolation": { "requests": [ { "method": "GET", "path": "/api/auth/v1/system-config/public" }, { "method": "GET", "path": "/api/auth/v1/auth/me" }, { "method": "GET", "path": "/api/auth/v1/menus/navigation" }, { "method": "GET", "path": "/api/auth/v1/roles/all" }, { "method": "GET", "path": "/api/auth/v1/departments/tree" }, { "method": "GET", "path": "/api/auth/v1/users" }, { "method": "GET", "path": "/api/auth/v1/users/stats" }, { "method": "GET", "path": "/api/auth/v1/users" }, { "method": "GET", "path": "/api/auth/v1/users/stats" } ], "unexpected": [], "writes": [], "pageErrors": [] } }, { "title": "训练编辑器:加载失败提示消失后保留重新加载按钮", "status": "PASS", "durationMs": 6385, "screenshots": [ { "title": "05-legacy-training-message", "path": "screenshots/05-legacy-training-message.png" }, { "title": "06-legacy-training-retry", "path": "screenshots/06-legacy-training-retry.png" } ], "isolation": { "requests": [ { "method": "GET", "path": "/api/auth/v1/system-config/public" }, { "method": "GET", "path": "/api/auth/v1/auth/me" }, { "method": "GET", "path": "/api/auth/v1/menus/navigation" }, { "method": "GET", "path": "/api/tran/v1/content/projects/message-training-901" } ], "unexpected": [], "writes": [], "pageErrors": [] } }, { "title": "实装预览:任务上下文错误用 Message,离线与教员模式持续可见", "status": "PASS", "durationMs": 6450, "screenshots": [ { "title": "07-physical-context-message", "path": "screenshots/07-physical-context-message.png" }, { "title": "08-physical-mode-preserved", "path": "screenshots/08-physical-mode-preserved.png" } ], "isolation": { "requests": [ { "method": "GET", "path": "/api/auth/v1/system-config/public" }, { "method": "GET", "path": "/api/auth/v1/auth/me" }, { "method": "GET", "path": "/api/auth/v1/menus/navigation" }, { "method": "GET", "path": "/api/tran/v1/teaching/assignments/mock-physical" } ], "unexpected": [], "writes": [], "pageErrors": [] } }, { "title": "新建训练:业务说明与必填校验保留,不发起创建请求", "status": "PASS", "durationMs": 2485, "screenshots": [ { "title": "09-create-validation-preserved", "path": "screenshots/09-create-validation-preserved.png" } ], "isolation": { "requests": [ { "method": "GET", "path": "/api/auth/v1/system-config/public" }, { "method": "GET", "path": "/api/auth/v1/auth/me" }, { "method": "GET", "path": "/api/auth/v1/menus/navigation" }, { "method": "GET", "path": "/api/tran/v1/content/projects/summary" }, { "method": "GET", "path": "/api/tran/v1/content/projects" } ], "unexpected": [], "writes": [], "pageErrors": [] } }, { "title": "缓存列表:失活时晚到错误不弹出,返回不重放旧错误", "status": "PASS", "durationMs": 1947, "screenshots": [ { "title": "10-inactive-page-no-message", "path": "screenshots/10-inactive-page-no-message.png" }, { "title": "11-reactivated-no-stale-message", "path": "screenshots/11-reactivated-no-stale-message.png" } ], "isolation": { "requests": [ { "method": "GET", "path": "/api/auth/v1/system-config/public" }, { "method": "GET", "path": "/api/auth/v1/auth/me" }, { "method": "GET", "path": "/api/auth/v1/menus/navigation" }, { "method": "GET", "path": "/api/tran/v1/content/projects/summary" }, { "method": "GET", "path": "/api/tran/v1/content/projects" }, { "method": "GET", "path": "/api/tran/v1/content/projects/summary" }, { "method": "GET", "path": "/api/tran/v1/content/projects" }, { "method": "GET", "path": "/api/auth/v1/roles/all" }, { "method": "GET", "path": "/api/auth/v1/departments/tree" }, { "method": "GET", "path": "/api/auth/v1/users" }, { "method": "GET", "path": "/api/auth/v1/users/stats" }, { "method": "GET", "path": "/api/tran/v1/content/projects/summary" }, { "method": "GET", "path": "/api/tran/v1/content/projects" } ], "unexpected": [], "writes": [], "pageErrors": [] } }, { "title": "HTTP 合同:真实 Axios 超时中文化,403/409 元数据保留,静默请求不自动弹窗", "status": "PASS", "durationMs": 1942, "screenshots": [ { "title": "12-http-silent-errors", "path": "screenshots/12-http-silent-errors.png" }, { "title": "15-business-message-keeps-original-text", "path": "screenshots/15-business-message-keeps-original-text.png" } ], "isolation": { "requests": [ { "method": "GET", "path": "/api/auth/v1/system-config/public" }, { "method": "GET", "path": "/api/auth/v1/auth/me" }, { "method": "GET", "path": "/api/auth/v1/menus/navigation" }, { "method": "GET", "path": "/api/tran/v1/content/projects/summary" }, { "method": "GET", "path": "/api/tran/v1/content/projects" }, { "method": "GET", "path": "/api/auth/v1/__message_e2e/timeout" }, { "method": "GET", "path": "/api/auth/v1/__message_e2e/forbidden" }, { "method": "GET", "path": "/api/auth/v1/__message_e2e/conflict" }, { "method": "GET", "path": "/api/auth/v1/__message_e2e/timeout" }, { "method": "GET", "path": "/api/auth/v1/__message_e2e/business-text" } ], "unexpected": [], "writes": [], "pageErrors": [] }, "http": [ { "endpoint": "timeout", "message": "请求超时,请稍后重试", "code": "NETWORK_ERROR", "status": null, "requestId": "" }, { "endpoint": "forbidden", "message": "无权访问测试数据", "code": "ACCESS_DENIED", "status": 403, "requestId": "mock-403" }, { "endpoint": "conflict", "message": "版本已变化,请重新加载", "code": "VERSION_CONFLICT", "status": 409, "requestId": "mock-409" } ], "httpBoundaries": { "cancellation": { "name": "CanceledError", "code": "ERR_CANCELED" }, "businessError": { "message": "Network Error", "code": "ASSET_VALIDATION", "requestId": "mock-business", "status": 400 } } }, { "title": "局域网教学列表:既有 ElMessage.error 使用全局关闭和自动消失配置", "status": "PASS", "durationMs": 6935, "screenshots": [ { "title": "13-lan-teaching-message", "path": "screenshots/13-lan-teaching-message.png" }, { "title": "14-lan-teaching-after-dismiss", "path": "screenshots/14-lan-teaching-after-dismiss.png" } ], "isolation": { "requests": [ { "method": "GET", "path": "/api/auth/v1/system-config/public" }, { "method": "GET", "path": "/api/auth/v1/auth/me" }, { "method": "GET", "path": "/api/auth/v1/menus/navigation" }, { "method": "GET", "path": "/api/tran/v1/teaching/assignments" }, { "method": "GET", "path": "/api/tran/v1/teaching/assignments/summary" } ], "unexpected": [], "writes": [], "pageErrors": [] } }, { "title": "模型桥接 DOM 合同:初次错误与晚写详情转为重试说明,ready 恢复交互", "status": "PASS", "durationMs": 791, "screenshots": [ { "title": "16-model-bridge-neutral-retry", "path": "screenshots/16-model-bridge-neutral-retry.png" }, { "title": "17-model-bridge-ready", "path": "screenshots/17-model-bridge-ready.png" } ], "isolation": { "requests": [], "unexpected": [], "writes": [], "pageErrors": [] } } ], "limitations": [ "这是接口失败展示的聚焦浏览器回归,未逐一遍历所有业务页面。", "页面渲染、Element Plus Message、缓存路由和 Axios 超时均运行于真实浏览器;服务端响应由测试模拟。", "模型 iframe 项为真实宿主桥接的 DOM 合同测试,使用空画布夹具,不代表完整 GLB 模型加载测试。", "保留训练业务状态、表单校验与重试入口。未扩大教学流程、权限或接口合同。" ], "reproduction": "pnpm exec playwright test -c api-error-messages.config.ts" }