14 — QA Checklist (WS / Realtime Module)
- Q1 — Reconnect storms (client + server)
- Q2 — Auth on reconnect
- Q3 — Event fan-out leaks (tenant isolation)
- Q4 — Heartbeat loss (silent half-open connection)
- Q5 — Event fan-out leaks (client side)
- Q6 — Subscribe / unsubscribe semantics
- Q7 — Reconnect resubscription
- Q8 — Malformed payloads & unknown events
- Q9 — Payload integrity
- Q10 — Scale (planned, per plan)
- Q11 — Broadcast correctness after redeploy
- Q12 — Logging hygiene
- Test surface summary
Test cases for the realtime layer. Server side (Jest) + client side (widget/unit). Shared baseline: 00-shared/10. Every case lists pass criteria. Source anchors included; a "source" gap means the behavior is defined by us, not the server.
Q1 — Reconnect storms (client + server)
- Scenario: 100 clients behind the same NAT lose connectivity simultaneously and all retry in lockstep.
- Pass: reconnects spread over time (client backoff jitter, 13 §3, 15 §4); server accepts them without CPU/connection spikes; no tenant event lost after each reconnect.
- Server evidence:
handleConnectionlogs connect (ws.gateway.ts:51-53); verify log rate stays linear, not bursty. - Client: no two consecutive retries with identical delay; cap 30 s (13).
Q2 — Auth on reconnect
- Scenario: session token expires mid-connection; socket drops; client reconnects with the stale token.
- Pass: server closes the socket (
ws.gateway.ts:42-44,54-56); client entersAuthError(never infinite loop), refreshes token via REST, reopens socket, resumes in tenant room (ws.gateway.ts:50). - Negative: refresh fails → sign-out path with snackbar (06 §1.2), no retry loop.
- Regression: missing token (neither
authnorquery) → clean disconnect (ws.gateway.ts:37-40).
Q3 — Event fan-out leaks (tenant isolation)
- Scenario: tenant A emits
payment.completed; tenant B is connected concurrently. - Pass: only sockets in
tenant:{A}receive it (ws-bridge.service.ts:16-22,ws.gateway.ts:76-78); B receives nothing. - Multi-socket: same user with 2 tabs in A receives exactly 2 copies (client dedups).
- This is the highest-severity test on the list — isolation is the module's core security boundary (04 §2).
Q4 — Heartbeat loss (silent half-open connection)
- Scenario: device sleeps; TCP stays half-open; no data flows.
- Pass: server pings time out (socket.io heartbeat defaults — **untuned in source,
G6 12); server cleans the dead socket (visible in disconnect log,
ws.gateway.ts:59-61); client detects loss and entersReconnecting, notOfflineforever. - Tune check:
pingInterval/pingTimeoutexplicitly set once proxy timeouts are known (pending decision, G6).
Q5 — Event fan-out leaks (client side)
- Scenario: user navigates between 10 screens in a session.
- Pass: no duplicate Bloc subscriptions after navigation; bloc
close()cancels stream subs (13 §2); memory flat over 15 min of navigation; single toast per event (dedup window, 10 §3).
Q6 — Subscribe / unsubscribe semantics
- Scenario: user subscribes to
class:10-A, then unsubscribes, then resubscribes. - Pass:
broadcastToRoomreaches exactly the subscribed sockets (ws.gateway.ts:80-82); unsubscribe stops delivery (ws.gateway.ts:70-74); double-subscribe is idempotent; non-string payload ignored (ws.gateway.ts:65,71). - Security negative:
subscribeto arbitrary roomtenant:otheror__admin— no server rejection today (G2); document as known-risk until allow-list lands.
Q7 — Reconnect resubscription
- Scenario: connected with extra rooms → network flap → reconnect.
- Pass: client re-
subscribes all extra rooms after handshake (rooms die with socket,ws.gateway.ts:63-68; client replay 13 §4); tenant room auto-restored (ws.gateway.ts:50); one reconcile refetch per visible live screen (06 §3.1).
Q8 — Malformed payloads & unknown events
- Scenario: server sends envelope with wrong shape, or an unknown eventType.
- Pass: client ignores + logs eventType only (06 §6); app never crashes; unknown
eventTyperouted to no bloc; payload size cap (e.g. 1 MB) prevents memory blowup.
Q9 — Payload integrity
- Scenario: event carries entityId; REST fetch of that entity.
- Pass: live row update matches REST data after reconcile; insert/refetch-bound logic per 06 §3.1; aggregate tiles recompute without refetch.
Q10 — Scale (planned, per plan)
- Scenario: 10k concurrent connections (plan flags this as a risk —
docs/IMPLEMENTATION_PLAN.md:842). - Pass (when executed): single-instance target met OR Redis pub/sub adapter added (currently absent — G5 12); broadcast latency p95 < 1 s; reconnect storm Q1 holds.
Q11 — Broadcast correctness after redeploy
- Scenario: server restarts with new bridge; clients reconnect.
- Pass: bridge re-activates on
onModuleInit(ws-bridge.service.ts:15-23); no double registration (EventBusonAnynot stacked — verify listener count after N restarts).
Q12 — Logging hygiene
- Pass: no token, payload content, or PII in gateway/bridge logs; only userId/tenantId
- eventType (
ws.gateway.ts:51-53,59-61; 10 §8). Grep CI check.
- eventType (
Test surface summary
| Layer | Tooling | Cases |
|---|---|---|
| Server (gateway) | Jest + @nestjs/websockets mock | handshake ok/fail, room join, subscribe validation, broadcast target |
| Server (bridge) | Jest | onAny wiring, envelope shape, single registration |
| Server (e2e) | socket.io-client against test server | Q1, Q3, Q6, Q11 (requires Mongo+Redis, npm run test:e2e) |
| Client | widget tests + fake client | Q2, Q5, Q7, Q8 |