# 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: canvas-mount.spec.js >> Canvas mount >> login and show lesson canvas within 5s
- Location: src/__tests__/e2e/canvas-mount.spec.js:37:3

# Error details

```
TimeoutError: page.waitForURL: Timeout 15000ms exceeded.
=========================== logs ===========================
waiting for navigation until "load"
============================================================
```

# Page snapshot

```yaml
- generic [ref=e3]:
  - banner [ref=e4]:
    - generic [ref=e5]:
      - generic [ref=e6] [cursor=pointer]:
        - img [ref=e7]
        - text: Classroom Copilot
      - button "menu" [ref=e10] [cursor=pointer]:
        - img [ref=e11]
  - main [ref=e13]:
    - generic [ref=e14]:
      - heading "ClassroomCopilot.ai" [level=1] [ref=e15]
      - heading "Login" [level=4] [ref=e16]
      - generic [ref=e18]:
        - generic [ref=e19]:
          - generic:
            - text: Email
            - generic: "*"
          - generic [ref=e20]:
            - textbox "Email" [ref=e21]
            - group:
              - generic: Email *
        - generic [ref=e22]:
          - generic:
            - text: Password
            - generic: "*"
          - generic [ref=e23]:
            - textbox "Password" [ref=e24]
            - group:
              - generic: Password *
        - button "Login" [ref=e25] [cursor=pointer]: Login
```

# Test source

```ts
  1  | import { test, expect, request } from '@playwright/test';
  2  | 
  3  | const BASE = process.env.PLAYWRIGHT_BASE_URL || 'http://192.168.0.251:13000';
  4  | const TEST_EMAIL = process.env.VITE_TEST_TEACHER_EMAIL;
  5  | const TEST_PASSWORD = process.env.VITE_TEST_TEACHER_PASSWORD;
  6  | 
  7  | async function serverReachable() {
  8  |   try {
  9  |     const ctx = await request.newContext();
  10 |     const res = await ctx.get(BASE, { timeout: 3000 }).catch(() => null);
  11 |     await ctx.dispose();
  12 |     return Boolean(res);
  13 |   } catch {
  14 |     return false;
  15 |   }
  16 | }
  17 | 
  18 | async function login(page) {
  19 |   await page.goto(`${BASE}/login`);
  20 |   await page.getByLabel('Email').fill(TEST_EMAIL);
  21 |   await page.getByLabel('Password').fill(TEST_PASSWORD);
  22 |   await page.getByRole('button', { name: 'Login' }).click();
> 23 |   await page.waitForURL((url) => /\/dashboard|\/node\//.test(url.pathname), { timeout: 15000 });
     |              ^ TimeoutError: page.waitForURL: Timeout 15000ms exceeded.
  24 | }
  25 | 
  26 | function skipIfUnconfigured() {
  27 |   if (!TEST_EMAIL || !TEST_PASSWORD) test.skip(true, 'VITE_TEST_TEACHER_EMAIL / VITE_TEST_TEACHER_PASSWORD not set');
  28 | }
  29 | 
  30 | test.describe('Canvas mount', () => {
  31 |   test.beforeAll(async () => {
  32 |     skipIfUnconfigured();
  33 |     const reachable = await serverReachable();
  34 |     test.skip(!reachable, `Dev server not reachable at ${BASE}`);
  35 |   });
  36 | 
  37 |   test('login and show lesson canvas within 5s', async ({ page }) => {
  38 |     await login(page);
  39 |     const canvasVisible = await page
  40 |       .locator('[data-testid="tldraw-canvas"], .tl-container')
  41 |       .waitFor({ timeout: 10000 })
  42 |       .then(() => true)
  43 |       .catch(() => false);
  44 |     expect(canvasVisible).toBe(true);
  45 |     await expect(page.locator('[class*="error-state"], [data-testid="error"]').first()).toBeHidden({ timeout: 2000 }).catch(() => {});
  46 |   });
  47 | });
  48 | 
```