# 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: tests/ui/cycle-facet.spec.ts >> cycle facet (sites#194, #355) >> an invalid ?cycle= means all cycles
- Location: tests/ui/cycle-facet.spec.ts:54:7

# Error details

```
Test timeout of 30000ms exceeded.
```

```
Error: page.goto: net::ERR_ABORTED; maybe frame was detached?
Call log:
  - navigating to "http://10.1.105.22/?cycle=2023", waiting until "load"

```

# Test source

```ts
  1  | import { test, expect, Page } from '@playwright/test';
  2  | 
  3  | // The global cycle facet and the graph view as identity-bar member controls
  4  | // (electinfo/sites#194, #355). /auth/whoami and /auth/account/me are mocked
  5  | // with Authentik on, so these run on CI pods (Authentik off) as well as on
  6  | // preview. Choosing a cycle reloads the page with ?cycle=YYYY.
  7  | 
  8  | const DNC = '/committees/a75a9110-f1db-a945-39a8-7503ed3c04da/'; // C00010603
  9  | 
  10 | async function as(page: Page, email: string): Promise<void> {
  11 |   await page.route('**/auth/whoami*', r => r.fulfill({ json: { enabled: 'true', email, elevated: false, entitlements: {} } }));
  12 |   await page.route('**/auth/account/me*', r => r.fulfill({ json: { email, requests: [], agreement: null, granted: [] } }));
  13 | }
  14 | 
  15 | test.describe('cycle facet (sites#194, #355)', () => {
  16 |   test('signed out: shown locked, offers sign-in', async ({ page }) => {
  17 |     await as(page, '');
  18 |     await page.goto('/');
  19 |     const cycle = page.locator('#auth-slot [data-control="cycle"]');
  20 |     await expect(cycle).toBeVisible({ timeout: 15000 });
  21 |     await expect(cycle).toHaveAttribute('aria-disabled', 'true');
  22 |     await expect(cycle).toContainText('All cycles');
  23 |     await cycle.click({ force: true });
  24 |     await expect(page.locator('dialog#ei-signin h2')).toHaveText('Sign in to use the cycle facet');
  25 |   });
  26 | 
  27 |   test('signed in: picking a cycle reloads with ?cycle= and links keep it', async ({ page }) => {
  28 |     await as(page, 'jane@example.org');
  29 |     await page.goto('/');
  30 |     const cycle = page.locator('#auth-slot [data-control="cycle"]');
  31 |     await expect(cycle).not.toHaveAttribute('aria-disabled', 'true', { timeout: 15000 });
  32 |     await cycle.click();
  33 |     const menu = page.locator('#ei-cycle-menu');
  34 |     await expect(menu).toBeVisible();
  35 |     await expect(menu.locator('[data-cycle="all"]')).toHaveAttribute('aria-checked', 'true');
  36 |     await Promise.all([page.waitForURL(/[?&]cycle=2024\b/), menu.locator('[data-cycle="2024"]').click()]);
  37 | 
  38 |     const scoped = page.locator('#auth-slot [data-control="cycle"]');
  39 |     await expect(scoped).toContainText('Cycle 2024', { timeout: 15000 });
  40 |     await expect(scoped).toHaveAttribute('aria-pressed', 'true');
  41 | 
  42 |     // An internal link carries the cycle.
  43 |     const link = page.locator('#stats a[href^="/"]').filter({ visible: true }).first();
  44 |     await Promise.all([page.waitForURL(url => url.pathname !== '/' && url.searchParams.get('cycle') === '2024'), link.click()]);
  45 | 
  46 |     // Back to all cycles drops the parameter.
  47 |     await page.locator('#auth-slot [data-control="cycle"]').click();
  48 |     await Promise.all([
  49 |       page.waitForURL(url => !url.searchParams.has('cycle')),
  50 |       page.locator('#ei-cycle-menu [data-cycle="all"]').click(),
  51 |     ]);
  52 |   });
  53 | 
  54 |   test('an invalid ?cycle= means all cycles', async ({ page }) => {
  55 |     await as(page, 'jane@example.org');
> 56 |     await page.goto('/?cycle=2023');
     |                ^ Error: page.goto: net::ERR_ABORTED; maybe frame was detached?
  57 |     await expect(page.locator('#auth-slot [data-control="cycle"]')).toContainText('All cycles', { timeout: 15000 });
  58 |   });
  59 | });
  60 | 
  61 | test.describe('graph view control (sites#355)', () => {
  62 |   test('a member opens the graph from the bar; no header button', async ({ page }) => {
  63 |     await as(page, 'jane@example.org');
  64 |     await page.goto(DNC);
  65 |     const graph = page.locator('#auth-slot [data-control="graph"]');
  66 |     await expect(graph).toBeVisible({ timeout: 15000 });
  67 |     await expect(page.locator('button.eg-open')).toHaveCount(0);
  68 |     await graph.click();
  69 |     await expect(page.locator('dialog.eg-dialog')).toBeVisible();
  70 |   });
  71 | 
  72 |   test('signed out: the graph control is locked', async ({ page }) => {
  73 |     await as(page, '');
  74 |     await page.goto(DNC);
  75 |     const graph = page.locator('#auth-slot [data-control="graph"]');
  76 |     await expect(graph).toHaveAttribute('aria-disabled', 'true', { timeout: 15000 });
  77 |     await graph.click({ force: true });
  78 |     await expect(page.locator('dialog#ei-signin h2')).toHaveText('Sign in to use Graph');
  79 |     await expect(page.locator('dialog.eg-dialog')).toHaveCount(0);
  80 |   });
  81 | });
  82 | 
```