# 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/district-maps.spec.ts >> state-house map of MN: boundaries within budget, polygons keyed to graph Districts
- Location: tests/ui/district-maps.spec.ts:36:7

# Error details

```
Error: expect(locator).toHaveAttribute(expected) failed

Locator: locator('.map-chamber-btn[data-kind="sldl"]')
Expected: "true"
Timeout: 5000ms
Error: element(s) not found

Call log:
  - Expect "toHaveAttribute" locator('.map-chamber-btn[data-kind="sldl"]') with timeout 5000ms
  - waiting for locator('.map-chamber-btn[data-kind="sldl"]')

```

```yaml
- link "← Back to Home":
  - /url: /
- banner:
  - heading "Districts" [level=1]
  - paragraph: Congressional, State Senate and State House districts
- text: Not signed in
- link "Log in":
  - /url: /outpost.goauthentik.io/start?rd=https%3A%2F%2Fus.elect.info%2Fdistricts%2F%3Fview%3Dmap%26tab%3Dstate-house%26state%3DMN
- link "Create an account":
  - /url: /signin/register?rd=https%3A%2F%2Fus.elect.info%2Fdistricts%2F%3Fview%3Dmap%26tab%3Dstate-house%26state%3DMN
- toolbar "Member tools":
  - button "All cycles (Sign in to use the cycle facet)" [disabled]: All cycles
  - button "Graph (Sign in to use Graph)" [disabled]: Graph
- button "Congressional map"
- button "List"
- main:
  - textbox "Search districts by name..."
  - button "Search"
  - button "All"
  - button "Congressional"
  - button "State Senate"
  - button "State House" [pressed]
  - text: "State:"
  - combobox "State:":
    - option "All states"
    - option "Alabama"
    - option "Alaska"
    - option "American Samoa"
    - option "Arizona"
    - option "Arkansas"
    - option "California"
    - option "Colorado"
    - option "Connecticut"
    - option "Delaware"
    - option "District of Columbia"
    - option "Florida"
    - option "Georgia"
    - option "Guam"
    - option "Hawaii"
    - option "Idaho"
    - option "Illinois"
    - option "Indiana"
    - option "Iowa"
    - option "Kansas"
    - option "Kentucky"
    - option "Louisiana"
    - option "Maine"
    - option "Maryland"
    - option "Massachusetts"
    - option "Michigan"
    - option "Minnesota" [selected]
    - option "Mississippi"
    - option "Missouri"
    - option "Montana"
    - option "Nebraska"
    - option "Nevada"
    - option "New Hampshire"
    - option "New Jersey"
    - option "New Mexico"
    - option "New York"
    - option "North Carolina"
    - option "North Dakota"
    - option "Northern Mariana Islands"
    - option "Ohio"
    - option "Oklahoma"
    - option "Oregon"
    - option "Pennsylvania"
    - option "Puerto Rico"
    - option "Rhode Island"
    - option "South Carolina"
    - option "South Dakota"
    - option "Tennessee"
    - option "Texas"
    - option "U.S. Virgin Islands"
    - option "Utah"
    - option "Vermont"
    - option "Virginia"
    - option "Washington"
    - option "West Virginia"
    - option "Wisconsin"
    - option "Wyoming"
  - heading "All Districts" [level=3]
  - link "Minnesota State House District 01A State House":
    - /url: /districts/mn-hd-01a/
  - link "Minnesota State House District 01B State House":
    - /url: /districts/mn-hd-01b/
  - link "Minnesota State House District 02A State House":
    - /url: /districts/mn-hd-02a/
  - link "Minnesota State House District 02B State House":
    - /url: /districts/mn-hd-02b/
  - link "Minnesota State House District 03A State House":
    - /url: /districts/mn-hd-03a/
  - link "Minnesota State House District 03B State House":
    - /url: /districts/mn-hd-03b/
  - link "Minnesota State House District 04A State House":
    - /url: /districts/mn-hd-04a/
  - link "Minnesota State House District 04B State House":
    - /url: /districts/mn-hd-04b/
  - link "Minnesota State House District 05A State House":
    - /url: /districts/mn-hd-05a/
  - link "Minnesota State House District 05B State House":
    - /url: /districts/mn-hd-05b/
  - link "Minnesota State House District 06A State House":
    - /url: /districts/mn-hd-06a/
  - link "Minnesota State House District 06B State House":
    - /url: /districts/mn-hd-06b/
  - link "Minnesota State House District 07A State House":
    - /url: /districts/mn-hd-07a/
  - link "Minnesota State House District 07B State House":
    - /url: /districts/mn-hd-07b/
  - link "Minnesota State House District 08A State House":
    - /url: /districts/mn-hd-08a/
  - link "Minnesota State House District 08B State House":
    - /url: /districts/mn-hd-08b/
  - link "Minnesota State House District 09A State House":
    - /url: /districts/mn-hd-09a/
  - link "Minnesota State House District 09B State House":
    - /url: /districts/mn-hd-09b/
  - link "Minnesota State House District 10A State House":
    - /url: /districts/mn-hd-10a/
  - link "Minnesota State House District 10B State House":
    - /url: /districts/mn-hd-10b/
  - link "Minnesota State House District 11A State House":
    - /url: /districts/mn-hd-11a/
  - link "Minnesota State House District 11B State House":
    - /url: /districts/mn-hd-11b/
  - link "Minnesota State House District 12A State House":
    - /url: /districts/mn-hd-12a/
  - link "Minnesota State House District 12B State House":
    - /url: /districts/mn-hd-12b/
  - link "Minnesota State House District 13A State House":
    - /url: /districts/mn-hd-13a/
  - link "Minnesota State House District 13B State House":
    - /url: /districts/mn-hd-13b/
  - link "Minnesota State House District 14A State House":
    - /url: /districts/mn-hd-14a/
  - link "Minnesota State House District 14B State House":
    - /url: /districts/mn-hd-14b/
  - link "Minnesota State House District 15A State House":
    - /url: /districts/mn-hd-15a/
  - link "Minnesota State House District 15B State House":
    - /url: /districts/mn-hd-15b/
  - link "Minnesota State House District 16A State House":
    - /url: /districts/mn-hd-16a/
  - link "Minnesota State House District 16B State House":
    - /url: /districts/mn-hd-16b/
  - link "Minnesota State House District 17A State House":
    - /url: /districts/mn-hd-17a/
  - link "Minnesota State House District 17B State House":
    - /url: /districts/mn-hd-17b/
  - link "Minnesota State House District 18A State House":
    - /url: /districts/mn-hd-18a/
  - link "Minnesota State House District 18B State House":
    - /url: /districts/mn-hd-18b/
  - link "Minnesota State House District 19A State House":
    - /url: /districts/mn-hd-19a/
  - link "Minnesota State House District 19B State House":
    - /url: /districts/mn-hd-19b/
  - link "Minnesota State House District 20A State House":
    - /url: /districts/mn-hd-20a/
  - link "Minnesota State House District 20B State House":
    - /url: /districts/mn-hd-20b/
  - link "Minnesota State House District 21A State House":
    - /url: /districts/mn-hd-21a/
  - link "Minnesota State House District 21B State House":
    - /url: /districts/mn-hd-21b/
  - link "Minnesota State House District 22A State House":
    - /url: /districts/mn-hd-22a/
  - link "Minnesota State House District 22B State House":
    - /url: /districts/mn-hd-22b/
  - link "Minnesota State House District 23A State House":
    - /url: /districts/mn-hd-23a/
  - link "Minnesota State House District 23B State House":
    - /url: /districts/mn-hd-23b/
  - link "Minnesota State House District 24A State House":
    - /url: /districts/mn-hd-24a/
  - link "Minnesota State House District 24B State House":
    - /url: /districts/mn-hd-24b/
  - link "Minnesota State House District 25A State House":
    - /url: /districts/mn-hd-25a/
  - link "Minnesota State House District 25B State House":
    - /url: /districts/mn-hd-25b/
  - text: Showing 1-50
  - button "First" [disabled]
  - button "Prev" [disabled]
  - button "1"
  - button "Next"
```

# Test source

```ts
  1  | import { test, expect, type Page } from '@playwright/test';
  2  | 
  3  | /*
  4  |  * /districts/ Map + List per chamber (sites#467), against an installed target.
  5  |  *
  6  |  * Boundaries are GeoShapeImageSync's simplified per-state TIGER collections
  7  |  * (Congressional /geo/districts/, State Senate /geo/sldu/, State House
  8  |  * /geo/sldl/). Each state file is fetched only on drill-in and must stay within
  9  |  * the payload budget. Polygons link to the serving graph's District: on a graph
  10 |  * with state legislative Districts every polygon the graph has links and its
  11 |  * page answers 200; on a graph without them (production before the SLD graph
  12 |  * release) no SLD polygon links. Both are asserted, never skipped.
  13 |  */
  14 | 
  15 | const BUDGET_BYTES = 500_000;  // uncompressed; largest today is TX State House (~490 KB)
  16 | 
  17 | const SAMPLES: Array<{ tab: string; kind: string; state: string; url: string; label?: [string, string] }> = [
  18 |   { tab: 'congressional', kind: 'cd', state: 'TX', url: '/geo/districts/us-districts-tx.geojson' },
  19 |   { tab: 'state-senate', kind: 'sldu', state: 'AK', url: '/geo/sldu/us-sldu-ak.geojson', label: ['ak-00a', 'Alaska State Senate District A'] },
  20 |   { tab: 'state-senate', kind: 'sldu', state: 'VT', url: '/geo/sldu/us-sldu-vt.geojson', label: ['vt-ben', 'Vermont Bennington Senatorial District'] },
  21 |   { tab: 'state-house', kind: 'sldl', state: 'MN', url: '/geo/sldl/us-sldl-mn.geojson', label: ['mn-01a', 'Minnesota State House District 1A'] },
  22 |   { tab: 'state-house', kind: 'sldl', state: 'TX', url: '/geo/sldl/us-sldl-tx.geojson' },
  23 | ];
  24 | 
  25 | function inventoryResponse(page: Page, kind: string, state: string) {
  26 |   return page.waitForResponse(response => {
  27 |     if (!response.url().includes('/api/graphql') || response.request().method() !== 'POST') return false;
  28 |     try {
  29 |       const body = response.request().postDataJSON();
  30 |       return /\bbrowseEntities\s*\(/.test(body?.query || '') && body?.variables?.filter === `district_type:${kind},state:${state}` && body?.variables?.page === 1;
  31 |     } catch { return false; }
  32 |   });
  33 | }
  34 | 
  35 | for (const sample of SAMPLES) {
  36 |   test(`${sample.tab} map of ${sample.state}: boundaries within budget, polygons keyed to graph Districts`, async ({ page, request }) => {
  37 |     test.setTimeout(90000);
  38 |     const geo = await request.get(sample.url);
  39 |     expect(geo.status(), `${sample.url} should answer 200`).toBe(200);
  40 |     expect(geo.headers()['content-type']).toContain('application/geo+json');
  41 |     const body = await geo.body();
  42 |     expect(body.length, `${sample.url} payload budget`).toBeLessThanOrEqual(BUDGET_BYTES);
  43 |     const features = JSON.parse(body.toString()).features;
  44 |     expect(features.length).toBeGreaterThan(0);
  45 | 
  46 |     const inventory = sample.kind === 'cd' ? null : inventoryResponse(page, sample.kind, sample.state);
  47 |     await page.goto(`/districts/?view=map&tab=${sample.tab}&state=${sample.state}`);
> 48 |     await expect(page.locator(`.map-chamber-btn[data-kind="${sample.kind}"]`)).toHaveAttribute('aria-pressed', 'true');
     |                                                                                ^ Error: expect(locator).toHaveAttribute(expected) failed
  49 |     await expect(page.locator('#map-view')).toHaveAttribute('data-loaded', sample.kind, { timeout: 45000 });
  50 |     await expect(page.locator('#map path[data-district]')).toHaveCount(features.length);
  51 |     if (sample.label) {
  52 |       await expect(page.locator(`#map path[data-district="${sample.label[0]}"]`)).toHaveAttribute('aria-label', new RegExp(`^${sample.label[1]}( \\(page not yet available\\))?$`));
  53 |     }
  54 | 
  55 |     const linked = page.locator('#map path[data-href]');
  56 |     if (inventory) {
  57 |       const payload = await (await inventory).json();
  58 |       expect(payload.errors, 'graph inventory query must succeed').toBeUndefined();
  59 |       const total = payload.data?.browseEntities?.total ?? 0;
  60 |       if (total === 0) {
  61 |         // A serving graph without state legislative Districts: nothing links to a missing page.
  62 |         await expect(linked).toHaveCount(0);
  63 |         return;
  64 |       }
  65 |       // TIGER 2025 and the graph's Districts match 1:1 (sites#467): every polygon links.
  66 |       await expect(linked).toHaveCount(features.length);
  67 |     } else {
  68 |       await expect(linked).toHaveCount(features.length);
  69 |     }
  70 | 
  71 |     const href = await linked.first().getAttribute('data-href');
  72 |     expect(href).toMatch(/^\/districts\/[^/]+\/$/);
  73 |     await linked.first().scrollIntoViewIfNeeded();
  74 |     await Promise.all([page.waitForURL(`**${href}`), linked.first().dispatchEvent('click')]);
  75 |     const destination = await request.get(href!);
  76 |     expect(destination.status(), `${href} should answer 200`).toBe(200);
  77 |     await expect(page.locator('h1')).toBeVisible();
  78 |   });
  79 | }
  80 | 
  81 | test('State House on Nebraska explains the unicameral legislature', async ({ page }) => {
  82 |   await page.goto('/districts/?view=map&tab=state-house&state=NE');
  83 |   await expect(page.locator('.map-notice')).toContainText('unicameral', { timeout: 45000 });
  84 | });
  85 | 
```