Files
gochat/docs/qa/2026-07-09-test-plan-round5.md
T
2026-07-09 18:14:45 +08:00

436 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 `<a>` 元素(算 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 <JWT>" \
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=<JWT>`,收到 `{"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":"<agent_msg_source_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":"<external_conv_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: <description>", 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")