# 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: auth/magic-link.spec.ts >> Magic Link Authentication >> invalid token returns error
- Location: src/tests/auth/magic-link.spec.ts:67:7

# Error details

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

Expected: 401
Received: 404
```

# Test source

```ts
  1  | import { test, expect } from '../../fixtures.js';
  2  | import { MailpitClient } from '../../helpers/mailpit.js';
  3  | 
  4  | test.describe('Magic Link Authentication', () => {
  5  |   const mailpit = new MailpitClient();
  6  |   const testEmail = `test-student-${Date.now()}@e2e.local`;
  7  | 
  8  |   test.beforeEach(({ features }) => {
  9  |     test.skip(!features.students, 'Students feature not enabled');
  10 |   });
  11 | 
  12 |   test('request magic link, receive email, verify token, get session', async ({
  13 |     browser,
  14 |     customerConfig,
  15 |     customerName,
  16 |   }) => {
  17 |     await mailpit.deleteAllEmails();
  18 | 
  19 |     // Use a fresh context without auth for student login
  20 |     const context = await browser.newContext({
  21 |       baseURL: customerConfig.url,
  22 |       ignoreHTTPSErrors: true,
  23 |     });
  24 |     const page = await context.newPage();
  25 | 
  26 |     try {
  27 |       // 1. Request magic link via API
  28 |       const requestUrl = new URL(
  29 |         '/api/actions/auth/magic-link/request',
  30 |         customerConfig.url
  31 |       );
  32 |       requestUrl.searchParams.set('redirect_uri', customerConfig.url);
  33 |       requestUrl.searchParams.set('customer', customerName);
  34 | 
  35 |       const requestResponse = await fetch(requestUrl.toString(), {
  36 |         method: 'POST',
  37 |         headers: { 'Content-Type': 'application/json' },
  38 |         body: JSON.stringify({ email: testEmail }),
  39 |       });
  40 | 
  41 |       expect(requestResponse.status).toBe(200);
  42 | 
  43 |       // 2. Wait for email to arrive in Mailpit
  44 |       const email = await mailpit.waitForEmail(testEmail, 15_000);
  45 |       expect(email).toBeTruthy();
  46 |       expect(email.Subject).toBeTruthy();
  47 | 
  48 |       // 3. Get full email body and extract magic link
  49 |       const emailDetail = await mailpit.getEmailBody(email.ID);
  50 |       const magicLinkUrl = mailpit.extractMagicLinkUrl(emailDetail.HTML);
  51 |       expect(magicLinkUrl).toContain('/students/verify');
  52 |       expect(magicLinkUrl).toContain('token=');
  53 | 
  54 |       // 4. Navigate to magic link URL in browser
  55 |       await page.goto(magicLinkUrl);
  56 | 
  57 |       // 5. Should end up on students page with active session
  58 |       await expect(page).toHaveURL(/\/students/, { timeout: 15_000 });
  59 | 
  60 |       // 6. Verify session is active
  61 |       await expect(page.locator('body')).toBeVisible();
  62 |     } finally {
  63 |       await context.close();
  64 |     }
  65 |   });
  66 | 
  67 |   test('invalid token returns error', async ({ customerConfig, customerName }) => {
  68 |     const verifyResponse = await fetch(
  69 |       `${customerConfig.url}/api/actions/auth/magic-link/verify`,
  70 |       {
  71 |         method: 'POST',
  72 |         headers: { 'Content-Type': 'application/json' },
  73 |         body: JSON.stringify({
  74 |           token: 'invalid-token-12345',
  75 |           customer: customerName,
  76 |         }),
  77 |       }
  78 |     );
  79 | 
> 80 |     expect(verifyResponse.status).toBe(401);
     |                                   ^ Error: expect(received).toBe(expected) // Object.is equality
  81 |     const body = await verifyResponse.json();
  82 |     expect(body.error).toBeTruthy();
  83 |   });
  84 | });
  85 | 
```