# 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/map-insets.spec.ts >> /blocks/ map draws AK, HI and DC insets and drills in from a label
- Location: tests/ui/map-insets.spec.ts:19:7

# Error details

```
Test timeout of 90000ms exceeded.
```

```
Error: locator.click: Test timeout of 90000ms exceeded.
Call log:
  - waiting for locator('.toggle-btn[data-view="map"]')

```

# Page snapshot

```yaml
- generic [ref=e1]:
  - generic:
    - region "Status messages"
  - generic [active] [ref=e7]:
    - text: ⋯
    - banner
    - main "Authentication form" [ref=e8]:
      - generic [ref=e9]: elect.info
      - generic [ref=e10]:
        - heading "Sign in to elect.info" [level=1] [ref=e12]
        - generic [ref=e14]:
          - paragraph [ref=e15]: Login to continue to us.elect.info.
          - generic [ref=e16]:
            - generic [ref=e17]: Email
            - textbox "Email" [ref=e19]
          - generic [ref=e20]:
            - generic [ref=e21]: Password
            - textbox "Password" [ref=e26]:
              - /placeholder: Please enter your password
          - button "Log in" [ref=e28] [cursor=pointer]
        - generic [ref=e29]:
          - group "Login sources" [ref=e30]:
            - text: or
            - button "Continue with Google" [ref=e32] [cursor=pointer]
          - group "Additional actions" [ref=e33]:
            - generic [ref=e35]:
              - text: Need an account?
              - link "Sign up." [ref=e36] [cursor=pointer]:
                - /url: /if/flow/elect-info-enrollment/?client_id=KI5Be8scLVeZN7n5zY8p5s8VbpyradOSKQvo9T2c&redirect_uri=https%3A%2F%2Fus.elect.info%2Foutpost.goauthentik.io%2Fcallback%3FX-authentik-auth-callback%3Dtrue&response_type=code&scope=openid+entitlements+ak_proxy+email+profile&state=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnb2F1dGhlbnRpay5pby9vdXRwb3N0L0tJNUJlOHNjTFZlWk43bjV6WThwNXM4VmJweXJhZE9TS1F2bzlUMmMiLCJzaWQiOiI0V05LQUlWU1k2NEtaQVlOQktRUTNDSTNOVkEyUVdNUkxUUVBYTEdaQUFKVEdQWEFPQk1RIiwic3RhdGUiOiJldG90Y3FpWGtaVWxiOUFJUVhsNTItVFBiemJDckUtaFNIVXVXb01UZWNVIiwicmVkaXJlY3QiOiJodHRwczovL3VzLmVsZWN0LmluZm8vYmxvY2tzLyJ9.-43x5EpgYnEgmvM90L3MEbZm5wj2LlyisjawHfaZiwo&next=%2Fapplication%2Fo%2Fauthorize%2F%3Fclient_id%3DKI5Be8scLVeZN7n5zY8p5s8VbpyradOSKQvo9T2c%26redirect_uri%3Dhttps%253A%252F%252Fus.elect.info%252Foutpost.goauthentik.io%252Fcallback%253FX-authentik-auth-callback%253Dtrue%26response_type%3Dcode%26scope%3Dopenid%2Bentitlements%2Bak_proxy%2Bemail%2Bprofile%26state%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnb2F1dGhlbnRpay5pby9vdXRwb3N0L0tJNUJlOHNjTFZlWk43bjV6WThwNXM4VmJweXJhZE9TS1F2bzlUMmMiLCJzaWQiOiI0V05LQUlWU1k2NEtaQVlOQktRUTNDSTNOVkEyUVdNUkxUUVBYTEdaQUFKVEdQWEFPQk1RIiwic3RhdGUiOiJldG90Y3FpWGtaVWxiOUFJUVhsNTItVFBiemJDckUtaFNIVXVXb01UZWNVIiwicmVkaXJlY3QiOiJodHRwczovL3VzLmVsZWN0LmluZm8vYmxvY2tzLyJ9.-43x5EpgYnEgmvM90L3MEbZm5wj2LlyisjawHfaZiwo
            - link "Forgot username or password?" [ref=e38] [cursor=pointer]:
              - /url: /if/flow/elect-info-recovery/?client_id=KI5Be8scLVeZN7n5zY8p5s8VbpyradOSKQvo9T2c&redirect_uri=https%3A%2F%2Fus.elect.info%2Foutpost.goauthentik.io%2Fcallback%3FX-authentik-auth-callback%3Dtrue&response_type=code&scope=openid+entitlements+ak_proxy+email+profile&state=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnb2F1dGhlbnRpay5pby9vdXRwb3N0L0tJNUJlOHNjTFZlWk43bjV6WThwNXM4VmJweXJhZE9TS1F2bzlUMmMiLCJzaWQiOiI0V05LQUlWU1k2NEtaQVlOQktRUTNDSTNOVkEyUVdNUkxUUVBYTEdaQUFKVEdQWEFPQk1RIiwic3RhdGUiOiJldG90Y3FpWGtaVWxiOUFJUVhsNTItVFBiemJDckUtaFNIVXVXb01UZWNVIiwicmVkaXJlY3QiOiJodHRwczovL3VzLmVsZWN0LmluZm8vYmxvY2tzLyJ9.-43x5EpgYnEgmvM90L3MEbZm5wj2LlyisjawHfaZiwo&next=%2Fapplication%2Fo%2Fauthorize%2F%3Fclient_id%3DKI5Be8scLVeZN7n5zY8p5s8VbpyradOSKQvo9T2c%26redirect_uri%3Dhttps%253A%252F%252Fus.elect.info%252Foutpost.goauthentik.io%252Fcallback%253FX-authentik-auth-callback%253Dtrue%26response_type%3Dcode%26scope%3Dopenid%2Bentitlements%2Bak_proxy%2Bemail%2Bprofile%26state%3DeyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnb2F1dGhlbnRpay5pby9vdXRwb3N0L0tJNUJlOHNjTFZlWk43bjV6WThwNXM4VmJweXJhZE9TS1F2bzlUMmMiLCJzaWQiOiI0V05LQUlWU1k2NEtaQVlOQktRUTNDSTNOVkEyUVdNUkxUUVBYTEdaQUFKVEdQWEFPQk1RIiwic3RhdGUiOiJldG90Y3FpWGtaVWxiOUFJUVhsNTItVFBiemJDckUtaFNIVXVXb01UZWNVIiwicmVkaXJlY3QiOiJodHRwczovL3VzLmVsZWN0LmluZm8vYmxvY2tzLyJ9.-43x5EpgYnEgmvM90L3MEbZm5wj2LlyisjawHfaZiwo
```

# Test source

```ts
  1  | import { test, expect } from '@playwright/test';
  2  | 
  3  | /*
  4  |  * Relocated states on the Leaflet map pages (electinfo/rundeck#852).
  5  |  *
  6  |  * The states view opens on the contiguous 48. Alaska, Hawaii and Puerto Rico
  7  |  * are drawn again, scaled and moved into open water in roughly their true
  8  |  * direction, dashed and labelled; DC gets a labelled marker. Clicking a label
  9  |  * fires the click of the state's real outline, so the drill-in uses the real
  10 |  * bounds and each page's own rules apply (precincts: HI has no VTD data, so
  11 |  * its click is a no-op there). The insets show at the national zoom only.
  12 |  * A jurisdiction with no boundary file yet (PR until GeoShapeImageSync has
  13 |  * run) simply has no inset.
  14 |  */
  15 | 
  16 | const PAGES = ['/districts/', '/counties/', '/places/', '/postalcodes/', '/tracts/', '/precincts/', '/blocks/'];
  17 | 
  18 | for (const path of PAGES) {
  19 |   test(`${path} map draws AK, HI and DC insets and drills in from a label`, async ({ page, request }) => {
  20 |     test.setTimeout(90000);
  21 |     const geo = await request.get('/geo/states/us-states.geojson');
  22 |     test.skip(geo.status() !== 200, 'state boundaries are not served in this environment');
  23 | 
  24 |     const res = await page.goto(path);
  25 |     expect(res?.status(), `${path} should answer 200`).toBe(200);
> 26 |     await page.locator('.toggle-btn[data-view="map"]').click();
     |                                                        ^ Error: locator.click: Test timeout of 90000ms exceeded.
  27 | 
  28 |     const labels = page.locator('.map-inset-label');
  29 |     await expect(labels.first()).toBeVisible({ timeout: 30000 });
  30 |     for (const code of ['ak', 'hi', 'dc']) {
  31 |       await expect(page.locator(`.map-inset-label[data-state="${code}"]`)).toBeVisible();
  32 |     }
  33 | 
  34 |     // Alaska has shapes and precinct data on every page, so its label drills in.
  35 |     await page.locator('.map-inset-label[data-state="ak"]').click();
  36 |     await expect(labels).toHaveCount(0);
  37 |     await expect(page.locator('.map-back-btn').first()).toBeVisible({ timeout: 15000 });
  38 |   });
  39 | }
  40 | 
  41 | // /states/ has no drill-in: a state click opens its page, so the AK label
  42 | // lands on /states/ak/, which may redirect to the canonical /states/alaska/.
  43 | // The opening view frames the 48 and every inset.
  44 | test('/states/ map frames AK, HI and DC insets and a label opens the state page', async ({ page, request }) => {
  45 |   test.setTimeout(90000);
  46 |   const geo = await request.get('/geo/states/us-states.geojson');
  47 |   test.skip(geo.status() !== 200, 'state boundaries are not served in this environment');
  48 | 
  49 |   const res = await page.goto('/states/');
  50 |   expect(res?.status(), '/states/ should answer 200').toBe(200);
  51 |   await page.locator('.toggle-btn[data-view="map"]').click();
  52 | 
  53 |   await expect(page.locator('.map-inset-label').first()).toBeVisible({ timeout: 30000 });
  54 |   const map = await page.locator('#map').boundingBox();
  55 |   const codes = (await geo.json()).features.map((f: any) => f.properties.code);
  56 |   for (const code of ['ak', 'hi', 'dc', 'pr'].filter(c => codes.includes(c))) {
  57 |     const label = page.locator(`.map-inset-label[data-state="${code}"]`);
  58 |     await expect(label).toBeVisible();
  59 |     const box = await label.boundingBox();
  60 |     expect(box && map && box.x >= map.x && box.x + box.width <= map.x + map.width
  61 |       && box.y >= map.y && box.y + box.height <= map.y + map.height, `${code} label inside the map frame`).toBeTruthy();
  62 |   }
  63 | 
  64 |   await page.locator('.map-inset-label[data-state="ak"]').click();
  65 |   await expect(page).toHaveURL(/\/states\/(ak|alaska)\/$/);
  66 | });
  67 | 
```