# Instructions

- Following Playwright test failed.
- Explain why, be concise, respect Playwright best practices.
- Provide a snippet of code with the fix, if possible.

# Test info

- Name: ws-kill-reconnect.e2e.test.ts >> WS-kill: login → kill WS → SDK reconnects within grace → canvas still truthy + chat round-trips
- Location: test/e2e/ws-kill-reconnect.e2e.test.ts:16:1

# Error details

```
Error: expect(received).toBe(expected) // Object.is equality

Expected: "mvp-room"
Received: undefined
```

# Page snapshot

```yaml
- generic [active] [ref=e1]:
  - generic:
    - generic [ref=e4]: Reconnected.
    - generic [ref=e6]: Press T or Enter to chat
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_b
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_b
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
    - generic: uat_a
```

# Test source

```ts
  1  | // apps/client/test/e2e/ws-kill-reconnect.e2e.test.ts
  2  | // [int->REQ-CLI-09] [int->REQ-CLI-04]
  3  | //
  4  | // Plan 06-15 Task 3 — WS-kill within-grace reconnect regression test.
  5  | // UAT Test 5 reproducer: login, force-close the WS socket, wait for SDK
  6  | // auto-reconnect within the Phase 4 D-22 grace window (10s), then assert
  7  | // GameScene is still ready and chat round-trips.
  8  | //
  9  | // Assertions use window.__rebno deterministic test hook (D-35, exposed by
  10 | // 06-14 Task 3 in dev/test mode only). Room slug asserted as 'mvp-room' per D-30.
  11 | // Secondary defect (06-12 §5): InputDispatcher.setRoom() is called on every
  12 | // reconnect so movement commands reach the new room object after reauth.
  13 | 
  14 | import { test, expect, loginAs, waitForGameReady } from './fixtures.js';
  15 | 
  16 | test('WS-kill: login → kill WS → SDK reconnects within grace → canvas still truthy + chat round-trips', async ({
  17 |   page,
  18 |   accountA,
  19 |   inviteSuffix,
  20 | }) => {
  21 |   // 1. Login and confirm initial game-ready state.
  22 |   await loginAs(page, accountA, inviteSuffix);
  23 |   await waitForGameReady(page);
  24 | 
  25 |   // 2. Force-close the WebSocket connection to trigger the reconnect path.
  26 |   //    Tries the Colyseus SDK transport first, falls back to connection.close().
  27 |   await page.evaluate(() => {
  28 |     const w = window as unknown as {
  29 |       __rebno?: {
  30 |         room?: {
  31 |           connection?: {
  32 |             transport?: { ws?: { close?: () => void } };
  33 |             close?: () => void;
  34 |           };
  35 |         };
  36 |       };
  37 |     };
  38 |     const conn = w.__rebno?.room?.connection;
  39 |     if (conn?.transport?.ws?.close) {
  40 |       conn.transport.ws.close();
  41 |     } else if (conn?.close) {
  42 |       conn.close();
  43 |     }
  44 |   });
  45 | 
  46 |   // 3. Brief pause to let the disconnect surface (banner may appear).
  47 |   await page.waitForTimeout(2_000);
  48 | 
  49 |   // 4. Wait for SDK auto-reconnect within the Phase 4 D-22 grace window (12s total).
  50 |   //    data-game-ready should still be truthy after reconnect completes.
  51 |   await expect(page.locator('canvas[data-game-ready="true"]')).toBeVisible({
  52 |     timeout: 12_000,
  53 |   });
  54 | 
  55 |   // 5. Confirm room ID is still correct via __rebno hook (D-35 + D-30).
  56 |   const postReconnectRoomId = await page.evaluate(
  57 |     () => (window as unknown as { __rebno?: { roomId?: string } }).__rebno?.roomId,
  58 |   );
> 59 |   expect(postReconnectRoomId).toBe('mvp-room');
     |                               ^ Error: expect(received).toBe(expected) // Object.is equality
  60 | 
  61 |   // 6. Chat round-trip post-reconnect — confirms message dispatch goes through
  62 |   //    the new room object (InputDispatcher.setRoom fix, 06-12 §5).
  63 |   await page.keyboard.press('Enter');
  64 |   await page.locator('[data-chat-input]').waitFor({ timeout: 5_000 });
  65 |   await page.fill('[data-chat-input]', 'hello-after-reconnect');
  66 |   await page.locator('[data-chat-input]').press('Enter');
  67 |   await expect(
  68 |     page.locator('[data-chat-line]').filter({ hasText: 'hello-after-reconnect' }),
  69 |   ).toBeVisible({ timeout: 5_000 });
  70 | });
  71 | 
```