# Test Plan — CDP 自动化全链路测试 (Round 5) **日期:** 2026-07-09 **环境:** backend (:3000) + frontend Vite (:3036) + FakeMessagePlatform (:9100) + CDP browser (:9222) **登录:** admin@gochat.local / changeme **前置条件:** FakeMessagePlatform 已实现(Plan 文档 Task 1-13 全部完成),Round 4 的 28 页功能测试已通过,WebSocket 认证修复已验证。 --- ## 背景 Round 4 验证了 28 页功能页面 + WebSocket 认证修复 + 实时消息推送。但以下场景因未对接消息收发平台而未被实际验证: - 外部渠道 → GoChat:客户通过外部平台发消息,webhook 接收并创建会话 - GoChat → 外部渠道:客服回复后消息通过 provider 发回外部平台 - 多客服同时在线的消息分配 - 客服上下线状态切换对消息路由的影响 - 聊天窗口关闭/重开的对话连续性 - 打字状态指示跨渠道传递 本轮引入 FakeMessagePlatform 作为可编程的假消息平台,覆盖上述全部场景。同时保留 Round 4 的 28 页回归测试。 --- ## 测试规则(继承 Round 4,无放松) ### Rule 1: Console warnings ARE errors - `console.warn` / Vue warnings / i18n fallback / deprecation notices 全部记录为 finding - 允许的 pre-existing warnings(不变):onClose deprecated、WootInput deprecated、Lit dev mode、Vue Router "Discarded invalid param(s)"、SW registration SecurityError - 任何不在 allowlist 中的新 warning IS a bug ### Rule 2: Network infinite request loop detection - 每页加载并 settle 后,监控网络 10 秒 - 标记任何在无用户交互下被调用超过 3 次的端点 - 特别关注 /cable 重连循环、轮询模式、4xx/5xx 端点重试 - `cache_keys` 端点多次调用是 false-positive(各组件独立获取,settle 后停止) ### Rule 3: Click-only navigation — NO URL input - 所有页面切换通过 UI 点击(sidebar links、sub-menus、tabs、buttons) - 唯一例外:初始登录页 `/app/login` - 折叠的 Settings sub-links 用 JS `.click()` on `` 元素(算 UI click) - `window.location.href = '...'` 禁止用于页面导航 ### Rule 4: Transition error capture - 离开页面前 capture console buffer,到达下一页后 capture - 过渡期间出现的 error/warning 是 transition-error finding ### Rule 5: CRUD interaction where applicable - 不只是"页面加载"——在支持 CRUD 的页面至少执行一次 create/edit 操作 - 验证操作成功 + 无新 console errors + 无 infinite refetch loop --- ## Pre-Test Setup ### Step 0a: 启动全部服务 ```bash # Terminal 1: GoChat 后端 (:3000) cd /home/yanghao05/Projects/gochat && pnpm dev:backend # Terminal 2: Frontend Vite (:3036) cd /home/yanghao05/Projects/gochat && pnpm dev:frontend # Terminal 3: FakeMessagePlatform (:9100) cd /home/yanghao05/Projects/gochat && pnpm fake:start ``` - [ ] `curl http://127.0.0.1:3000/health` → 200 - [ ] `curl http://127.0.0.1:3036/` → 200 - [ ] `curl http://127.0.0.1:9100/health` → `{"status":"ok","service":"fake-message-platform"}` ### Step 0b: DB schema integrity check(Round 2 BUG-7 教训) ```bash for ep in conversations/unread_counts notifications custom_attribute_definitions/ agent_bots "custom_filters/?filter_type=conversation" "custom_filters/?filter_type=contact"; do code=$(curl -s -o /dev/null -w '%{http_code}' -H 'X-Account-Id: 1' "http://127.0.0.1:3000/api/v1/accounts/1/$ep") echo "$ep → $code" done ``` 全部返回 200(或 401 未认证),不可 500。任何 500 = 停下修 schema。 ### Step 0c: CDP browser + console hooks - [ ] Chrome :9222 alive — `curl http://127.0.0.1:9222/json/version` - [ ] 打开 `http://127.0.0.1:3036/app/login` - [ ] 注入 console hooks(`window.__consoleErrors` / `__consoleWarnings` / `__resetConsole`) - [ ] 验证返回 `'ok'` ### Step 0d: Login - [ ] 填写 admin@gochat.local / changeme,点击登录 - [ ] 验证重定向到 dashboard - [ ] Capture console — post-login 干净 - [ ] 验证 cookie `cw_d_session_info` 包含 `access-token` ### Step 0e: 创建 Fake 渠道 Inbox 通过前端 UI 创建(验证 Task 7-9 的前端兼容性): - [ ] Sidebar → 设置 → 收件箱 → 点击"创建新收件箱" - [ ] 渠道选择列表中找到"Fake 测试平台"卡片,点击 - [ ] 填写表单: - 频道名称:`Fake Test Inbox` - Identifier:`fake_test_1` - Webhook URL:`http://127.0.0.1:9100/receive` - Token:`fake_test_token` - [ ] 点击"创建 Fake 频道" - [ ] 验证跳转到 agent 分配页面 - [ ] 添加 admin 到此 inbox - [ ] 验证 inbox 出现在收件箱列表中 通过 API 验证: ```bash curl -s -H "X-Account-Id: 1" -H "Authorization: Bearer " \ http://127.0.0.1:3000/api/v1/accounts/1/inboxes | jq '.[] | select(.channel_type=="fake")' ``` ### Step 0f: 验证 FakeMessagePlatform ↔ GoChat 连通性 ```bash # 从 FakeMessagePlatform 发一条测试消息到 GoChat curl -X POST http://127.0.0.1:9100/api/send \ -H 'Content-Type: application/json' \ -d '{"inbox_identifier":"fake_test_1","sender_id":"smoke_test","sender_name":"连通性测试","content":"ping"}' # 预期:GoChat 收到 webhook,创建 contact + conversation + message # 验证 GoChat 日志中出现 "Fake webhook received" + "message persisted" # 验证 FakeMessagePlatform 状态 curl http://127.0.0.1:9100/api/status # 预期:sent >= 1 ``` 如果连通性测试失败,停下排查——后续所有测试依赖这条链路。 --- ## Phase 1: WebSocket /cable 验证(回归 Round 4) - [ ] 登录后等 5s,检查后端日志 `ws: connection established` - [ ] 后端日志无 `ws: authentication failed` - [ ] 浏览器 console 无 WebSocket errors、无 /cable 401 - [ ] 网络 15s:/cable 连接一次并保持,不重复重连 - [ ] Presence indicator 显示状态(online/busy/offline) - [ ] 直接 WS 测试:连 `ws://127.0.0.1:3036/cable?access-token=`,收到 `{"type":"welcome"}` + 5s ping --- ## Phase 2: 28 页功能回归测试(click navigation) 继承 Round 4 的 28 页矩阵。本轮重点验证回归——Round 4 发现的 bug 是否修复、是否回退。每页执行完整 per-page checklist(reset buffer → click → settle → console → network 10s → CRUD → backend logs → transition capture)。 | # | 页面 | 点击路径 | CRUD 测试 | 回归关注 | |---|------|----------|-----------|----------| | 1 | Dashboard | (post-login) | 验证会话列表 + 在线状态 | — | | 2 | 会话详情 | 点击会话 | 发消息,验证即时送达 | — | | 3 | 联系人 | Sidebar: 联系人 | 编辑联系人,保存 | — | | 4 | 报告 Overview | Sidebar: 报告 → Overview | 日期选择器变化 | — | | 5 | 报告 会话 | 报告 sub-tab: 会话 | 筛选变化 | — | | 6 | 报告 客服 | 报告 sub-tab: 客服 | 验证表格 | — | | 7 | 报告 标签 | 报告 sub-tab: 标签 | 验证加载 | — | | 8 | 报告 收件箱 | 报告 sub-tab: 收件箱 | 验证加载 | — | | 9 | 报告 团队 | 报告 sub-tab: 团队 | 验证加载 | — | | 10 | 报告 CSAT | 报告 sub-tab: 客户满意度 | 验证加载 | — | | 11 | 报告 SLA | 报告 sub-tab: SLA | 验证 SLA 指标 | — | | 12 | 报告 机器人 | 报告 sub-tab: 机器人 | 验证加载 | **BUG-A** 回归:从 Reports 页面内点"机器人" sidebar link 是否跳转 | | 13 | 活动 | Sidebar: 活动 | 验证页面加载 | **BUG-1** 回归:路由是否正常 | | 14 | 帮助中心 | Sidebar: 帮助中心 | 点击 portal,验证文章 | — | | 15 | 设置 账户设置 | Settings → 账户设置 | 更新字段,保存 | — | | 16 | 设置 客服代理 | Settings sub: 客服代理 | 验证列表 + 搜索 | — | | 17 | 设置 团队 | Settings sub: 团队 | 打开创建团队向导 | — | | 18 | 设置 收件箱 | Settings sub: 收件箱 | 点击 inbox config,加载全部 tab | **BUG-C** 回归:预聊天表单 tab | | 19 | 设置 标签 | Settings sub: 标签 | 创建标签 | **BUG-3** 回归:intlify empty key warning | | 20 | 设置 自定义属性 | Settings sub: 自定义属性 | 切换 tab | — | | 21 | 设置 自动化 | Settings sub: 自动化 | 验证列表 | — | | 22 | 设置 机器人 | Settings sub: 机器人 | 验证列表 | **BUG-2** 回归:sidebar click nav | | 23 | 设置 宏 | Settings sub: 宏 | 验证列表 | — | | 24 | 设置 预设回复 | Settings sub: 预设回复 | 创建预设回复 | — | | 25 | 设置 集成方式 | Settings sub: 集成方式 | 点击配置一个 | — | | 26 | 设置 会话工作流 | Settings sub: 会话工作流 | Toggle switch | — | | 27 | 设置 客服分配 | Settings sub: 客服分配 | 验证表单 | — | | 28 | 个人资料 | Avatar dropdown → profile | 更新资料,保存 | — | ### 回归判定标准 | Bug | Round 4 状态 | Round 5 判定 | |-----|-------------|-------------| | BUG-1 (P2) Activity 路由缺失 | FIXED | 点击"活动" → campaigns 页面加载 → FIXED | | BUG-2 (P3) Bots sidebar 导航 | FIXED | Settings → 机器人 → 导航到 agent-bots → FIXED | | BUG-3 (P4) intlify empty key | PERSISTING | 创建标签时无 `[intlify] Not found ''` → FIXED;仍有 → PERSISTING | | BUG-A (P3) Bot Reports 侧栏导航 | NEW | 从 Reports 页面点"机器人" → 跳转到 /reports/bot → FIXED;不跳转 → PERSISTING | | BUG-C (P2) 预聊天表单 null | FIXED | inbox settings → 预聊天表单 tab → 无 Vue warn → FIXED | --- ## Phase 3: FakeMessagePlatform 全链路消息测试(本轮新增核心) 这是 Round 5 的核心差异——通过 FakeMessagePlatform 驱动真实的外部渠道消息流。 ### 3.1 客户发消息 → GoChat 创建会话 - [ ] 通过 FakeMessagePlatform 发送消息: ```bash curl -X POST http://127.0.0.1:9100/api/send \ -H 'Content-Type: application/json' \ -d '{"inbox_identifier":"fake_test_1","sender_id":"customer_001","sender_name":"测试客户A","content":"你好,我需要帮助"}' ``` - [ ] 前端 Dashboard 看到新会话出现(Fake Test Inbox 渠道) - [ ] 会话列表显示客户名"测试客户A"和消息预览"你好,我需要帮助" - [ ] 点击会话,消息出现在聊天窗口 - [ ] 后端日志:`Fake webhook received` + `message persisted` - [ ] Console 无新错误 ### 3.2 客服回复 → FakeMessagePlatform 收到出站消息 - [ ] 在前端会话详情页,客服输入回复"您好,有什么可以帮您?",Ctrl+Enter 发送 - [ ] 消息即时出现在聊天窗口(WS 实时推送) - [ ] FakeMessagePlatform 收到出站消息: ```bash curl http://127.0.0.1:9100/api/messages?inbox_identifier=fake_test_1 ``` 预期:返回包含 `"content":"您好,有什么可以帮您?"` 的消息 - [ ] 消息 sender.type 为 "agent" - [ ] Console 无新错误 ### 3.3 客户回复 → 消息追加到同一会话 - [ ] 通过 FakeMessagePlatform 回复: ```bash curl -X POST http://127.0.0.1:9100/api/reply \ -H 'Content-Type: application/json' \ -d '{"inbox_identifier":"fake_test_1","sender_id":"customer_001","content":"我的订单有问题","reply_to_id":""}' ``` - [ ] 前端会话详情页:新消息追加到聊天窗口底部(不创建新会话) - [ ] 消息 sender 为客户"测试客户A" - [ ] Console 无新错误 ### 3.4 多客户并发会话 - [ ] 同时发送两个不同客户的消息: ```bash curl -X POST http://127.0.0.1:9100/api/send \ -H 'Content-Type: application/json' \ -d '{"inbox_identifier":"fake_test_1","sender_id":"customer_002","sender_name":"测试客户B","content":"退款咨询"}' & curl -X POST http://127.0.0.1:9100/api/send \ -H 'Content-Type: application/json' \ -d '{"inbox_identifier":"fake_test_1","sender_id":"customer_003","sender_name":"测试客户C","content":"技术支持"}' & ``` - [ ] 前端会话列表出现 3 个独立会话(A/B/C) - [ ] 每个会话的消息内容正确对应 - [ ] Console 无新错误 ### 3.5 打字状态指示 - [ ] 触发客户打字状态: ```bash curl -X POST http://127.0.0.1:9100/api/typing \ -H 'Content-Type: application/json' \ -d '{"inbox_identifier":"fake_test_1","sender_id":"customer_001","typing":true}' ``` - [ ] 前端会话详情页显示"正在输入..."指示器(如果 UI 支持) - [ ] 停止打字: ```bash curl -X POST http://127.0.0.1:9100/api/typing \ -H 'Content-Type: application/json' \ -d '{"inbox_identifier":"fake_test_1","sender_id":"customer_001","typing":false}' ``` - [ ] 指示器消失 - [ ] Console 无新错误 ### 3.6 聊天窗口关闭(session end) - [ ] 关闭客户会话: ```bash curl -X POST http://127.0.0.1:9100/api/close \ -H 'Content-Type: application/json' \ -d '{"inbox_identifier":"fake_test_1","conversation_id":"","sender_id":"customer_001"}' ``` - [ ] GoChat 收到 session.end 事件,创建 "[session ended]" 消息 - [ ] 前端会话显示系统消息或状态变化 - [ ] Console 无新错误 - [ ] 同一客户再次发消息 → 创建新会话(如果 inbox 配置 lock_to_single_conversation=false) ### 3.7 消息附件 - [ ] 发送带附件的消息: ```bash curl -X POST http://127.0.0.1:9100/api/send \ -H 'Content-Type: application/json' \ -d '{"inbox_identifier":"fake_test_1","sender_id":"customer_001","sender_name":"测试客户A","content":"请看这张截图","content_type":"image","attachments":[{"url":"http://example.com/screenshot.png","content_type":"image/png","filename":"screenshot.png","file_size":102400}]}' ``` - [ ] 前端会话详情页显示附件预览(图片缩略图或文件链接) - [ ] Console 无新错误 --- ## Phase 4: 多客服消息分配测试(本轮新增) ### 4.1 单客服在线 — 所有消息分配给该客服 - [ ] 确保 Fake Test Inbox 启用 auto_assignment - [ ] 确保只有一个客服(admin)在线 - [ ] FakeMessagePlatform 模拟客服上线: ```bash curl -X POST http://127.0.0.1:9100/api/agent/online \ -H 'Content-Type: application/json' \ -d '{"agent_id":"1","agent_name":"Admin"}' ``` - [ ] 发送新客户消息 → 验证会话自动分配给 admin - [ ] 前端会话列表中该会话 assignee 为 admin ### 4.2 多客服在线 — 轮询分配 - [ ] 创建第二个客服用户(通过 Settings → 客服代理) - [ ] 将第二个客服添加到 Fake Test Inbox - [ ] 两个客服同时在线 - [ ] 连续发送 3 条不同客户的消息 - [ ] 验证会话按 round-robin 或 least_busy 策略分配给不同客服 - [ ] 前端各客服的会话列表显示分配给自己的会话 ### 4.3 客服下线 — 消息不分配给离线客服 - [ ] 第二个客服下线: ```bash curl -X POST http://127.0.0.1:9100/api/agent/offline \ -H 'Content-Type: application/json' \ -d '{"agent_id":"2"}' ``` - [ ] 发送新客户消息 → 验证会话只分配给在线的 admin - [ ] 不分配给已下线的客服 ### 4.4 全部客服下线 — 消息进入未分配队列 - [ ] admin 也下线 - [ ] 发送新客户消息 → 验证会话创建但 assignee 为空(未分配) - [ ] 客服上线后 → 验证是否自动补分配(取决于 assignment policy 配置) --- ## Phase 5: 实时 WebSocket 功能验证(含跨渠道) ### 5.1 基础实时推送(回归 Round 4) - [ ] 打开会话,发消息 → 即时出现 - [ ] 后端日志:`message.created` event dispatched - [ ] Presence indicator 显示正确状态 - [ ] 网络 30s:/cable 稳定,无 401,无重连风暴 - [ ] 直接 WS 测试:welcome + 5s ping ### 5.2 跨标签页实时推送(回归 Round 4) - [ ] Tab 2 同账号登录,reload dashboard - [ ] Tab 1 发消息 → Tab 2 会话列表预览更新 + 会话详情消息出现 - [ ] 无需手动刷新 ### 5.3 FakeMessagePlatform 触发的实时推送(新增) - [ ] Tab 1 打开 customer_001 的会话 - [ ] 通过 FakeMessagePlatform 发送 customer_001 的新消息 - [ ] Tab 1 聊天窗口即时显示新消息(WS 推送,非轮询) - [ ] Tab 2 如果也打开同一会话 → 同样即时显示 - [ ] 后端日志:`Fake webhook received` → `message persisted` → `ws: message command`(WS 推送) --- ## Phase 6: 收集与报告 ### Issue severity(继承 Round 4) | Sev | 定义 | |-----|------| | P0 | 功能损坏,阻断核心工作流,或无限循环导致资源耗尽 | | P1 | 核心功能损坏但有 workaround;或重复 console errors 降低 UX | | P2 | 非核心功能损坏,或 warnings 指向真实代码问题 | | P3 | 轻微 cosmetic/edge-case,无功能影响 | | P4 | 纯噪声(dev-mode warnings、deprecation 无用户影响) | ### 报告文件 写入 `docs/qa/2026-07-09-qa-report-round5.md`。 必须包含的章节: 1. **Summary** — 总页数/通过/失败数 + FakeMessagePlatform 集成测试结果概要 2. **服务启动验证** — backend/frontend/fake-platform 三个服务的健康检查结果 3. **Fake Inbox 创建验证** — 前端 UI 创建 fake 渠道 inbox 的过程和结果 4. **WebSocket 验证** — /cable 状态、welcome/ping、无 401 5. **28 页回归测试结果表** — 页面、点击路径、通过/失败、findings 6. **FakeMessagePlatform 全链路测试结果**(Phase 3 每个子项) 7. **多客服消息分配测试结果**(Phase 4 每个子项) 8. **实时 WebSocket 功能验证**(Phase 5 每个子项) 9. **Findings** — 每个 issue:severity、复现步骤(click path + curl command)、预期 vs 实际、console errors、screenshot path、根因方向、影响文件 10. **Known issues 回归验证** — BUG-1/2/3/A/C 的 Round 5 状态 11. **后端错误观察** — 500s、panics、WS auth failures 12. **测试备注** — 测试了什么、跳过了什么、blockers ### 截图 每个 finding 截图: ``` browser_vision(question="Capture the issue: ", annotate=false) ``` 在 CLI 模式下陈述截图的绝对路径(不使用 MEDIA: tag)。 ### 文档清理 按 known-bugs.md 的 cleanup policy: - [ ] 将 Round 4 的 `docs/qa/2026-07-09-qa-report-round4.md` 和 `docs/qa/2026-07-09-test-plan-round4.md` 删除 - [ ] 将 Round 5 报告中的新发现合并到 `references/known-bugs.md` - [ ] 更新 known-bugs.md 的 "Consolidated from QA rounds 1–5" 行 - [ ] 保留 Round 5 的报告和测试计划作为当前版本 --- ## 验证 Checklist - [ ] 三个服务(backend :3000 + frontend :3036 + fake :9100)全部启动并健康 - [ ] DB schema integrity check:6 个历史端点全部 200(非 500) - [ ] Console hooks 注入成功 - [ ] Login 成功,cookie 包含 access-token - [ ] Fake 渠道 Inbox 通过前端 UI 成功创建 - [ ] FakeMessagePlatform → GoChat 连通性测试通过 - [ ] /cable WebSocket 连接稳定(welcome + ping + 无 401) - [ ] 28 页全部通过 click navigation 测试(或标注 exception) - [ ] 每页:reset buffer → navigate → settle → console → network 10s → CRUD → logs → transition - [ ] Phase 3 全链路消息测试:发消息/回复/多客户/打字/关窗口/附件 全部验证 - [ ] Phase 4 多客服分配:单客服/多客服轮询/下线/全下线 全部验证 - [ ] Phase 5 实时推送:基础/跨标签页/FakePlatform 触发 全部验证 - [ ] 报告写入 `docs/qa/2026-07-09-qa-report-round5.md` - [ ] 每个 finding 有:severity、复现步骤(click path + curl)、console errors、screenshot path、根因 - [ ] Known bugs 回归验证:BUG-1/2/3/A/C 状态更新 - [ ] 旧轮报告清理(Round 4 report + test plan 删除) - [ ] known-bugs.md 更新(新发现 + 状态变更 + "rounds 1–5")