11 KiB
Test Plan — CDP Full-Page Functional Testing
Date: 2026-07-08 Environment: backend (:3000) + frontend Vite (:3036), CDP browser at :9222 Login: admin@gochat.local / changeme
Background
You reported a persistent WebSocket auth error in the backend logs:
{"level":"ERROR","caller":"ws/handler.go:62",
"msg":"ws: authentication failed: authentication required: provide 'token' (JWT) or 'pubsub_token' + 'user_id' params"}
HTTP GET /cable 401
Root Cause Analysis
The frontend ActionCable connector (BaseActionCableConnector.js) builds its
WebSocket URL like this:
let websocketURL = websocketHost ? `${websocketHost}/cable` : undefined;
if (websocketURL && accessToken) {
websocketURL += `?access-token=${encodeURIComponent(accessToken)}`;
}
this.consumer = createConsumer(websocketURL);
websocketHost comes from window.chatwootConfig.websocketURL, which is not
set in frontend/index.html (the static config injected after Rails
decoupling). So websocketHost is '' (empty string), which is falsy, so
websocketURL stays undefined.
When createConsumer(undefined) is called, ActionCable falls back to its
internal INTERNAL.default_mount_path = "/cable". This produces a relative
WebSocket URL that the browser resolves against the frontend origin
(ws://127.0.0.1:3036/cable), not the backend.
The Vite dev proxy does forward /cable to the backend with ws: true, so the
upgrade request reaches the Go backend. However, because websocketURL was
undefined, the ?access-token=... query param was never appended. The
backend's extractWSToken() checks c.Query("token"), c.Query("access-token"),
and the Authorization header — all empty — so it falls through to the
pubsub_token path, which also fails because no pubsub_token or user_id query
params are present either.
Result: Every WebSocket connection attempt to /cable returns HTTP 401.
Fix Direction
In BaseActionCableConnector.js, when websocketHost is empty, default to the
current page origin so the URL is never undefined. This ensures:
- The
?access-token=query param is appended. - The WebSocket URL resolves against the correct origin.
// If no explicit websocketURL configured, use same origin as the page
const origin = websocketHost || window.location.origin;
let websocketURL = `${origin}/cable`;
if (accessToken) {
websocketURL += `?access-token=${encodeURIComponent(accessToken)}`;
}
Testing Principles (Must Follow)
These rules apply to every page and every transition throughout the entire test run. They are not optional checks — they define how navigation and observation must be performed.
Rule 1: Console is a first-class failure signal
- Warnings count as errors.
console.warn, Vue warnings, deprecation notices, i18n fallback warnings — all are recorded as issues, not ignored. - The only acceptable console state is completely clean (zero errors, zero warnings) unless the issue is already documented as a known pre-existing bug.
- Before navigating away from any page, capture the full console log. Any new warning or error that appeared during the page's lifetime is a finding.
- Use
agent-browser evalor CDPLog.enable+Runtime.consoleAPICalledto capture console output programmatically. Do not rely on visual inspection.
Rule 2: Watch for infinite network request loops
- Some pages have polling/retry logic that can enter infinite refresh loops (repeatedly calling the same API endpoint every few seconds, or hammering a failing endpoint with exponential retry storms).
- After each page loads and settles, monitor network activity for 5-10 seconds. If the same endpoint is being called repeatedly without user interaction, that is a bug — record the endpoint, frequency, and response status.
- Use
agent-browser network requeststo inspect what fired, and watch the backend logs for repeated request patterns. - A page that "loads fine" but silently generates 50+ API calls per minute is a failing page.
Rule 3: Navigate by clicking, never by URL input
- All page transitions must be performed via UI clicks — sidebar links,
buttons, breadcrumbs, tabs, card clicks. Never type a URL into the address bar
or use
agent-browser open <url>to jump directly to a page (except for the initial login page). - Direct URL navigation bypasses the Vue router's navigation guards,
beforeEnterhooks, store preloading, and transition lifecycle. Bugs that only surface during real navigation (missing data preload, stale state, broken transition animations, orphaned event listeners) will be missed. - The test flow must mirror a real user's click path: login → dashboard → sidebar → each settings page → sub-tabs within settings → back navigation.
- If a page is only reachable by URL (no UI link exists), note it as a navigation gap finding, then navigate to it directly as an exception with explicit annotation.
Test Plan
Phase 1: Fix the WebSocket auth error
- Patch
BaseActionCableConnector.jsto defaultwebsocketHosttowindow.location.originwhen empty. - Verify the
access-tokencookie read works (cookie namecw_d_session_info). - Confirm the backend
extractWSToken()acceptsaccess-tokenquery param.
Phase 2: Start dev services
- Start
pnpm dev:backend(air hot-reload, port 3000). - Start
pnpm dev:frontend(Vite dev server, port 3036). - Health check:
curl http://127.0.0.1:3000/health.
Phase 3: CDP browser login
- Connect agent-browser to CDP at :9222.
- Navigate to
http://127.0.0.1:3036/app/login(only direct URL allowed). - Login with admin@gochat.local / changeme.
- Verify redirect to dashboard.
- Capture console state — must be clean post-login.
Phase 4: WebSocket connection verification (the primary fix)
- After login, check backend logs for
ws: connection established. - Check no more
ws: authentication failederrors in backend. - Check browser console: no 401 on /cable, no WebSocket connection errors.
- Check no infinite /cable reconnect loop (ActionCable retries should stop after successful connection, not loop forever).
- Verify the NetworkNotification component shows "online" status.
- Monitor network for 10s — confirm /cable is not being repeatedly hit.
Phase 5: Full page-by-page functional testing (click-based navigation)
Navigation method: Start from dashboard. Use sidebar links, settings sub-menus, tabs, and buttons to reach every page. Never type URLs.
Per-page checklist (applies to every page below):
- Click to navigate to the page (record the click path).
- Wait for page to settle (networkidle or specific content appears).
- Capture full console log — any error OR warning is a finding.
- Monitor network for 5-10s — flag any infinite/repeated request loops.
- Verify core content renders (not a blank page, not an error boundary).
- Attempt at least one CRUD interaction where applicable.
- Capture backend logs for any errors during the page's lifetime.
- Navigate away via sidebar/back — verify no errors on transition.
| # | Page | Click Path (from dashboard) | Key Checks |
|---|---|---|---|
| 1 | Dashboard | (already here after login) | Conversation list loads, sidebar renders, online status |
| 2 | Conversation detail | Click a conversation in list | Message history, reply box, send a message, real-time delivery |
| 3 | Contacts | Sidebar: 联系人 | Contact list, edit contact, save, search |
| 4 | Reports — Overview | Sidebar: 报告 → Overview | Stats cards, charts render, date picker |
| 5 | Reports — Conversations | Reports sub-tab: 会话 | Table loads, filters work |
| 6 | Reports — Agents | Reports sub-tab: 客服 | Agent table loads |
| 7 | Reports — SLA | Reports sub-tab: SLA | SLA metrics render |
| 8 | Activity | Sidebar: 活动 | Known issue BUG-1: route missing — verify if fixed or still broken |
| 9 | Help Center | Sidebar: 帮助中心 | Portal list, articles, tabs |
| 10 | Settings — General | Sidebar: 设置 → 账户设置 | Form fields, update settings |
| 11 | Settings — Agents | Settings sub-menu: 客服代理 | Agent list, search |
| 12 | Settings — Teams | Settings sub-menu: 团队 | Team list, create team wizard |
| 13 | Settings — Inboxes | Settings sub-menu: 收件箱 | Inbox list, click config → all tabs load |
| 14 | Settings — Labels | Settings sub-menu: 标签 | Label list, create label |
| 15 | Settings — Custom Attributes | Settings sub-menu: 自定义属性 | List loads, tabs (会话/联系人) |
| 16 | Settings — Automation | Settings sub-menu: 自动化 | List loads |
| 17 | Settings — Agent Bots | Settings sub-menu: 机器人 | Known BUG-2: sidebar click may not navigate — verify |
| 18 | Settings — Macros | Settings sub-menu: 宏 | List loads |
| 19 | Settings — Canned Responses | Settings sub-menu: 预设回复 | List, create canned response |
| 20 | Settings — Integrations | Settings sub-menu: 集成方式 | Integration cards, click configure |
| 21 | Settings — Conversation Workflow | Settings sub-menu: Conversation Workflows | Toggle loads |
| 22 | Settings — Assignment Policy | Settings sub-menu: Agent Assignment | Policy forms, add buttons |
| 23 | Profile | Click avatar / profile link | Profile form, update, password change |
Phase 6: Real-time WebSocket feature verification
These tests verify the WebSocket fix is actually working end-to-end:
- Open a conversation, send a message — verify it appears instantly.
- Check backend logs for
ws: connection established (user=X, account=Y). - Verify presence/availability indicator shows correct status.
- Monitor network: confirm /cable WebSocket is stable (connected, not reconnect-looping), and no 401s on /cable after the initial connection.
- If possible, open a second browser session and verify real-time message delivery (message sent from session A appears in session B without refresh).
Phase 7: Collect and report
- For each page: compile console errors/warnings, network issues, CRUD results.
- Compile all backend errors (ws auth, 500s, panics) observed during testing.
- Document any new bugs found with: reproduction steps (click path), root cause analysis, affected files, severity.
- Re-verify known issues (BUG-1, BUG-2, BUG-3) — note if fixed or persisting.
- Write final QA report to
docs/QA_REPORT_2026-07-08_cdp_round2.md.
Known Issues from Prior QA (docs/QA_REPORT_2026-07-08_full_page_testing.md)
- BUG-1 (P2): Activity page route missing — sidebar link dead.
- BUG-2 (P3): Bots sidebar link not navigating.
- BUG-3 (P4): intlify empty key warnings.
These will be re-verified via click navigation (not URL). If still present, they will be documented with their click-path reproduction. The WebSocket auth fix is the primary focus of this round.
Issue Severity Definitions
| Severity | Definition |
|---|---|
| P0 Critical | Feature completely broken, blocks core workflow, or infinite loop causing resource exhaustion |
| P1 High | Core feature broken but workaround exists; or repeated console errors degrading UX |
| P2 Medium | Non-core feature broken, or warnings that indicate a real code issue |
| P3 Low | Minor cosmetic or edge-case issue, no functional impact |
| P4 Cosmetic | Pure noise (dev-mode warnings, deprecation notices with no user impact) |