# 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/routing.spec.ts >> routing: every index link resolves >> /employers/ first-page links all answer 200 or 301
- Location: tests/ui/routing.spec.ts:84:9

# Error details

```
Error: /employers/ links that do not resolve

expect(received).toEqual(expected) // deep equality

- Expected  -  1
+ Received  + 21

- Array []
+ Array [
+   "/employers/b4116417-a32c-5f1b-cef0-033c090ea585/ -> 500",
+   "/employers/12811d6a-1e42-c9fa-6003-0864fe35ce72/ -> 500",
+   "/employers/9ba78b2b-197c-2ec7-bb27-baeb24ddf906/ -> 500",
+   "/employers/233356c6-077e-a4cc-cf1d-5b12bcc88379/ -> 500",
+   "/employers/d28c1533-71e9-4f3d-8152-6c3d1aede593/ -> 500",
+   "/employers/e8a343f7-d045-1c51-7924-c008624bf29d/ -> 500",
+   "/employers/2ed73cbb-e574-6fc4-5c1c-52abf126fd1b/ -> 500",
+   "/employers/ef27d8ac-8c12-a357-add6-e17089a38077/ -> 500",
+   "/employers/bd11573f-59c3-36f5-4332-6ce340852449/ -> 500",
+   "/employers/a004d1e1-ddac-9803-a2a6-c111879cdfba/ -> 500",
+   "/employers/b399f07c-3861-2963-a027-93e259c6c009/ -> 500",
+   "/employers/6ce623af-b9af-4466-f897-5a312b9c2692/ -> 500",
+   "/employers/ed6f8bbe-52a5-f7f4-241d-23ba4c6ee760/ -> 500",
+   "/employers/5b7a10e6-fb00-c019-14ff-15b345c3a245/ -> 500",
+   "/employers/44d740cc-5ada-e9b6-9991-f63b276dbb1b/ -> 500",
+   "/employers/4918e8b4-a9b4-db26-25fe-46b379efc933/ -> 500",
+   "/employers/29b9be2e-98b1-cb8a-4f61-42de0bbb7dfb/ -> 500",
+   "/employers/7fd4e4ea-6be6-a629-77fb-e7364bfddeee/ -> 500",
+   "/employers/c76e3e27-2b8b-debb-50c4-ca9a8d1dc20a/ -> 500",
+ ]
```

# Page snapshot

```yaml
- generic [active] [ref=e1]:
  - link "← Back to Home" [ref=e2] [cursor=pointer]:
    - /url: /
  - banner [ref=e3]:
    - heading "Employers" [level=1] [ref=e4]
    - paragraph [ref=e5]: Organizations with contributing employees
  - generic [ref=e6]:
    - generic [ref=e7]:
      - textbox "Search employers by name..." [ref=e8]
      - button "Search" [ref=e9] [cursor=pointer]
    - generic [ref=e10]:
      - heading "All Employers" [level=3] [ref=e12]
      - generic [ref=e13]:
        - 'link "RETIRED $6.4B in employee contributions Party Affinity – DEM: 32% REP: 68%" [ref=e14] [cursor=pointer]':
          - /url: /employers/7a4c48f4-b68c-3388-5cfe-9bfdfc967224/
          - generic [ref=e15]: RETIRED
          - generic [ref=e16]: $6.4B in employee contributions
          - generic [ref=e17]: "Party Affinity – DEM: 32% REP: 68%"
        - 'link "NOT EMPLOYED $5.9B in employee contributions Party Affinity – DEM: 81% REP: 19%" [ref=e18] [cursor=pointer]':
          - /url: /employers/3bfc633d-7783-3d8a-26b0-c9ba598f2fd9/
          - generic [ref=e19]: NOT EMPLOYED
          - generic [ref=e20]: $5.9B in employee contributions
          - generic [ref=e21]: "Party Affinity – DEM: 81% REP: 19%"
        - 'link "SELF-EMPLOYED $3.0B in employee contributions Party Affinity – DEM: 50% REP: 50%" [ref=e22] [cursor=pointer]':
          - /url: /employers/0133f6ff-00fe-ab4d-4158-d8bef9e42f47/
          - generic [ref=e23]: SELF-EMPLOYED
          - generic [ref=e24]: $3.0B in employee contributions
          - generic [ref=e25]: "Party Affinity – DEM: 50% REP: 50%"
        - 'link "N/A $2.2B in employee contributions Party Affinity – DEM: 63% REP: 37%" [ref=e26] [cursor=pointer]':
          - /url: /employers/b4116417-a32c-5f1b-cef0-033c090ea585/
          - generic [ref=e27]: N/A
          - generic [ref=e28]: $2.2B in employee contributions
          - generic [ref=e29]: "Party Affinity – DEM: 63% REP: 37%"
        - 'link "SELF $1.9B in employee contributions Party Affinity – DEM: 64% REP: 36%" [ref=e30] [cursor=pointer]':
          - /url: /employers/64abba32-9149-b706-9d04-c7c2426a1120/
          - generic [ref=e31]: SELF
          - generic [ref=e32]: $1.9B in employee contributions
          - generic [ref=e33]: "Party Affinity – DEM: 64% REP: 36%"
        - 'link "SELF EMPLOYED $1.7B in employee contributions Party Affinity – DEM: 54% REP: 46%" [ref=e34] [cursor=pointer]':
          - /url: /employers/12811d6a-1e42-c9fa-6003-0864fe35ce72/
          - generic [ref=e35]: SELF EMPLOYED
          - generic [ref=e36]: $1.7B in employee contributions
          - generic [ref=e37]: "Party Affinity – DEM: 54% REP: 46%"
        - 'link "NONE $1.4B in employee contributions Party Affinity – DEM: 60% REP: 40%" [ref=e38] [cursor=pointer]':
          - /url: /employers/9dcdb4bb-6588-3a32-1bae-e49ee15b7a70/
          - generic [ref=e39]: NONE
          - generic [ref=e40]: $1.4B in employee contributions
          - generic [ref=e41]: "Party Affinity – DEM: 60% REP: 40%"
        - 'link "BLOOMBERG INC. $1.3B in employee contributions Party Affinity – DEM: 91% REP: 9%" [ref=e42] [cursor=pointer]':
          - /url: /employers/80b9da95-4d78-7197-9b49-56ffecaa3972/
          - generic [ref=e43]: BLOOMBERG INC.
          - generic [ref=e44]: $1.3B in employee contributions
          - generic [ref=e45]: "Party Affinity – DEM: 91% REP: 9%"
        - 'link "HOMEMAKER $996.7M in employee contributions Party Affinity – DEM: 37% REP: 63%" [ref=e46] [cursor=pointer]':
          - /url: /employers/b7a187b0-79ea-038d-356f-49e278a4006e/
          - generic [ref=e47]: HOMEMAKER
          - generic [ref=e48]: $996.7M in employee contributions
          - generic [ref=e49]: "Party Affinity – DEM: 37% REP: 63%"
        - 'link "ULINE $420.1M in employee contributions Party Affinity – DEM: 33% REP: 67%" [ref=e50] [cursor=pointer]':
          - /url: /employers/09ed6529-6bef-844a-3b96-c9e2b9e20bc1/
          - generic [ref=e51]: ULINE
          - generic [ref=e52]: $420.1M in employee contributions
          - generic [ref=e53]: "Party Affinity – DEM: 33% REP: 67%"
        - 'link "SPACE EXPLORATION TECHNOLOGIES CORP. $326.3M in employee contributions Party Affinity – DEM: 57% REP: 43%" [ref=e54] [cursor=pointer]':
          - /url: /employers/5f9a1727-2225-3699-685b-8fb15c17c8f3/
          - generic [ref=e55]: SPACE EXPLORATION TECHNOLOGIES CORP.
          - generic [ref=e56]: $326.3M in employee contributions
          - generic [ref=e57]: "Party Affinity – DEM: 57% REP: 43%"
        - 'link "ADELSON DRUG CLINIC $309.9M in employee contributions Party Affinity – DEM: 53% REP: 47%" [ref=e58] [cursor=pointer]':
          - /url: /employers/a3c70989-0fb6-1336-b986-f8e43a738ad5/
          - generic [ref=e59]: ADELSON DRUG CLINIC
          - generic [ref=e60]: $309.9M in employee contributions
          - generic [ref=e61]: "Party Affinity – DEM: 53% REP: 47%"
        - 'link "FAHR, LLC $282.7M in employee contributions Party Affinity – DEM: 64% REP: 36%" [ref=e62] [cursor=pointer]':
          - /url: /employers/9ba78b2b-197c-2ec7-bb27-baeb24ddf906/
          - generic [ref=e63]: FAHR, LLC
          - generic [ref=e64]: $282.7M in employee contributions
          - generic [ref=e65]: "Party Affinity – DEM: 64% REP: 36%"
        - 'link "FAHR LLC $274.5M in employee contributions Party Affinity – DEM: 95% REP: 5%" [ref=e66] [cursor=pointer]':
          - /url: /employers/a7a37742-351b-4610-7625-d1ac72127018/
          - generic [ref=e67]: FAHR LLC
          - generic [ref=e68]: $274.5M in employee contributions
          - generic [ref=e69]: "Party Affinity – DEM: 95% REP: 5%"
        - 'link "SIG $254.6M in employee contributions Party Affinity – DEM: 22% REP: 78%" [ref=e70] [cursor=pointer]':
          - /url: /employers/f3b91900-a6f1-5ef3-e977-d11bd6644234/
          - generic [ref=e71]: SIG
          - generic [ref=e72]: $254.6M in employee contributions
          - generic [ref=e73]: "Party Affinity – DEM: 22% REP: 78%"
        - 'link "SOROS FUND MANAGEMENT LLC $192.6M in employee contributions Party Affinity – DEM: 47% REP: 53%" [ref=e74] [cursor=pointer]':
          - /url: /employers/233356c6-077e-a4cc-cf1d-5b12bcc88379/
          - generic [ref=e75]: SOROS FUND MANAGEMENT LLC
          - generic [ref=e76]: $192.6M in employee contributions
          - generic [ref=e77]: "Party Affinity – DEM: 47% REP: 53%"
        - 'link "ATTORNEY $148.0M in employee contributions Party Affinity – DEM: 60% REP: 40%" [ref=e78] [cursor=pointer]':
          - /url: /employers/32b64939-633b-c322-d952-efd27ff31302/
          - generic [ref=e79]: ATTORNEY
          - generic [ref=e80]: $148.0M in employee contributions
          - generic [ref=e81]: "Party Affinity – DEM: 60% REP: 40%"
        - 'link "CITADEL INVESTMENT GROUP $147.9M in employee contributions Party Affinity – DEM: 48% REP: 52%" [ref=e82] [cursor=pointer]':
          - /url: /employers/d28c1533-71e9-4f3d-8152-6c3d1aede593/
          - generic [ref=e83]: CITADEL INVESTMENT GROUP
          - generic [ref=e84]: $147.9M in employee contributions
          - generic [ref=e85]: "Party Affinity – DEM: 48% REP: 52%"
        - 'link "BLOOMBERG LP $145.1M in employee contributions Party Affinity – DEM: 56% REP: 44%" [ref=e86] [cursor=pointer]':
          - /url: /employers/01bb2352-69d9-de12-727a-afd85e7d2bf5/
          - generic [ref=e87]: BLOOMBERG LP
          - generic [ref=e88]: $145.1M in employee contributions
          - generic [ref=e89]: "Party Affinity – DEM: 56% REP: 44%"
        - 'link "BLACKSTONE $141.6M in employee contributions Party Affinity – DEM: 52% REP: 48%" [ref=e90] [cursor=pointer]':
          - /url: /employers/266a4fae-9cfc-abe3-9a11-3e03ccf5a885/
          - generic [ref=e91]: BLACKSTONE
          - generic [ref=e92]: $141.6M in employee contributions
          - generic [ref=e93]: "Party Affinity – DEM: 52% REP: 48%"
        - 'link "NEA $137.6M in employee contributions Party Affinity – DEM: 68% REP: 32%" [ref=e94] [cursor=pointer]':
          - /url: /employers/1f66dc86-7dc1-2ce8-4adf-f45bc1a07b73/
          - generic [ref=e95]: NEA
          - generic [ref=e96]: $137.6M in employee contributions
          - generic [ref=e97]: "Party Affinity – DEM: 68% REP: 32%"
        - 'link "ADELSON CLINIC $134.3M in employee contributions Party Affinity – DEM: 53% REP: 47%" [ref=e98] [cursor=pointer]':
          - /url: /employers/e8a343f7-d045-1c51-7924-c008624bf29d/
          - generic [ref=e99]: ADELSON CLINIC
          - generic [ref=e100]: $134.3M in employee contributions
          - generic [ref=e101]: "Party Affinity – DEM: 53% REP: 47%"
        - 'link "HOUSEWIFE $133.2M in employee contributions Party Affinity – DEM: 44% REP: 56%" [ref=e102] [cursor=pointer]':
          - /url: /employers/c8cf4f44-fed3-9324-e19d-8617a0a06f27/
          - generic [ref=e103]: HOUSEWIFE
          - generic [ref=e104]: $133.2M in employee contributions
          - generic [ref=e105]: "Party Affinity – DEM: 44% REP: 56%"
        - 'link "INFORMATION REQUESTED $130.5M in employee contributions Party Affinity – DEM: 56% REP: 44%" [ref=e106] [cursor=pointer]':
          - /url: /employers/8b48dc28-3a5f-5908-929b-929d1a42b4cf/
          - generic [ref=e107]: INFORMATION REQUESTED
          - generic [ref=e108]: $130.5M in employee contributions
          - generic [ref=e109]: "Party Affinity – DEM: 56% REP: 44%"
        - 'link "LAS VEGAS SANDS CORPORATION $129.1M in employee contributions Party Affinity – DEM: 54% REP: 46%" [ref=e110] [cursor=pointer]':
          - /url: /employers/2ed73cbb-e574-6fc4-5c1c-52abf126fd1b/
          - generic [ref=e111]: LAS VEGAS SANDS CORPORATION
          - generic [ref=e112]: $129.1M in employee contributions
          - generic [ref=e113]: "Party Affinity – DEM: 54% REP: 46%"
        - 'link "NEWSWEB CORPORATION $94.0M in employee contributions Party Affinity – DEM: 45% REP: 55%" [ref=e114] [cursor=pointer]':
          - /url: /employers/ef27d8ac-8c12-a357-add6-e17089a38077/
          - generic [ref=e115]: NEWSWEB CORPORATION
          - generic [ref=e116]: $94.0M in employee contributions
          - generic [ref=e117]: "Party Affinity – DEM: 45% REP: 55%"
        - 'link "AH CAPITAL MANAGEMENT $93.9M in employee contributions Party Affinity – DEM: 66% REP: 34%" [ref=e118] [cursor=pointer]':
          - /url: /employers/bd11573f-59c3-36f5-4332-6ce340852449/
          - generic [ref=e119]: AH CAPITAL MANAGEMENT
          - generic [ref=e120]: $93.9M in employee contributions
          - generic [ref=e121]: "Party Affinity – DEM: 66% REP: 34%"
        - 'link "CORPORATION $93.2M in employee contributions Party Affinity – DEM: 43% REP: 57%" [ref=e122] [cursor=pointer]':
          - /url: /employers/1338261d-1070-db29-7c1a-da8cc621c0bf/
          - generic [ref=e123]: CORPORATION
          - generic [ref=e124]: $93.2M in employee contributions
          - generic [ref=e125]: "Party Affinity – DEM: 43% REP: 57%"
        - 'link "EMC $92.6M in employee contributions Party Affinity – DEM: 49% REP: 51%" [ref=e126] [cursor=pointer]':
          - /url: /employers/91e362f3-a07b-2d78-f6c0-bf47fd7f58b0/
          - generic [ref=e127]: EMC
          - generic [ref=e128]: $92.6M in employee contributions
          - generic [ref=e129]: "Party Affinity – DEM: 49% REP: 51%"
        - 'link "CANDIDATE $89.3M in employee contributions Party Affinity – DEM: 23% REP: 77%" [ref=e130] [cursor=pointer]':
          - /url: /employers/a004d1e1-ddac-9803-a2a6-c111879cdfba/
          - generic [ref=e131]: CANDIDATE
          - generic [ref=e132]: $89.3M in employee contributions
          - generic [ref=e133]: "Party Affinity – DEM: 23% REP: 77%"
        - 'link "NOT-EMPLOYED $87.3M in employee contributions Party Affinity – DEM: 74% REP: 26%" [ref=e134] [cursor=pointer]':
          - /url: /employers/5d8845e4-85a9-b965-dccf-ef6c7fdab185/
          - generic [ref=e135]: NOT-EMPLOYED
          - generic [ref=e136]: $87.3M in employee contributions
          - generic [ref=e137]: "Party Affinity – DEM: 74% REP: 26%"
        - 'link "RENAISSANCE TECHNOLOGIES $86.7M in employee contributions Party Affinity – DEM: 43% REP: 57%" [ref=e138] [cursor=pointer]':
          - /url: /employers/b399f07c-3861-2963-a027-93e259c6c009/
          - generic [ref=e139]: RENAISSANCE TECHNOLOGIES
          - generic [ref=e140]: $86.7M in employee contributions
          - generic [ref=e141]: "Party Affinity – DEM: 43% REP: 57%"
        - 'link "CITADEL ASSET MANAGEMENT $81.1M in employee contributions Party Affinity – DEM: 45% REP: 55%" [ref=e142] [cursor=pointer]':
          - /url: /employers/6ce623af-b9af-4466-f897-5a312b9c2692/
          - generic [ref=e143]: CITADEL ASSET MANAGEMENT
          - generic [ref=e144]: $81.1M in employee contributions
          - generic [ref=e145]: "Party Affinity – DEM: 45% REP: 55%"
        - 'link "REYES HOLDINGS LLC $79.3M in employee contributions Party Affinity – DEM: 50% REP: 50%" [ref=e146] [cursor=pointer]':
          - /url: /employers/ed6f8bbe-52a5-f7f4-241d-23ba4c6ee760/
          - generic [ref=e147]: REYES HOLDINGS LLC
          - generic [ref=e148]: $79.3M in employee contributions
          - generic [ref=e149]: "Party Affinity – DEM: 50% REP: 50%"
        - 'link "ASANA $78.0M in employee contributions Party Affinity – DEM: 55% REP: 45%" [ref=e150] [cursor=pointer]':
          - /url: /employers/1ea20bae-7127-f698-e959-62ea157e489b/
          - generic [ref=e151]: ASANA
          - generic [ref=e152]: $78.0M in employee contributions
          - generic [ref=e153]: "Party Affinity – DEM: 55% REP: 45%"
        - 'link "LAS VEGAS SANDS INC. $77.7M in employee contributions Party Affinity – DEM: 48% REP: 52%" [ref=e154] [cursor=pointer]':
          - /url: /employers/da2307f5-284f-8e70-bcde-af64768446b0/
          - generic [ref=e155]: LAS VEGAS SANDS INC.
          - generic [ref=e156]: $77.7M in employee contributions
          - generic [ref=e157]: "Party Affinity – DEM: 48% REP: 52%"
        - 'link "STATE OF FLORIDA $72.4M in employee contributions Party Affinity – DEM: 34% REP: 66%" [ref=e158] [cursor=pointer]':
          - /url: /employers/5b196af7-558c-3e6b-5be5-d7296a6a0b06/
          - generic [ref=e159]: STATE OF FLORIDA
          - generic [ref=e160]: $72.4M in employee contributions
          - generic [ref=e161]: "Party Affinity – DEM: 34% REP: 66%"
        - 'link "Info Requested $70.6M in employee contributions Party Affinity – DEM: 30% REP: 70%" [ref=e162] [cursor=pointer]':
          - /url: /employers/5b7a10e6-fb00-c019-14ff-15b345c3a245/
          - generic [ref=e163]: Info Requested
          - generic [ref=e164]: $70.6M in employee contributions
          - generic [ref=e165]: "Party Affinity – DEM: 30% REP: 70%"
        - 'link "PHYSICIAN $68.3M in employee contributions Party Affinity – DEM: 45% REP: 55%" [ref=e166] [cursor=pointer]':
          - /url: /employers/44d740cc-5ada-e9b6-9991-f63b276dbb1b/
          - generic [ref=e167]: PHYSICIAN
          - generic [ref=e168]: $68.3M in employee contributions
          - generic [ref=e169]: "Party Affinity – DEM: 45% REP: 55%"
        - 'link "GOOGLE $67.8M in employee contributions Party Affinity – DEM: 78% REP: 22%" [ref=e170] [cursor=pointer]':
          - /url: /employers/da0fd30d-9df1-1df2-1e94-998cc68ddc39/
          - generic [ref=e171]: GOOGLE
          - generic [ref=e172]: $67.8M in employee contributions
          - generic [ref=e173]: "Party Affinity – DEM: 78% REP: 22%"
        - 'link "STEPHENS INC. $66.9M in employee contributions Party Affinity – DEM: 43% REP: 57%" [ref=e174] [cursor=pointer]':
          - /url: /employers/4918e8b4-a9b4-db26-25fe-46b379efc933/
          - generic [ref=e175]: STEPHENS INC.
          - generic [ref=e176]: $66.9M in employee contributions
          - generic [ref=e177]: "Party Affinity – DEM: 43% REP: 57%"
        - 'link "EUCLIDEAN CAPITAL $65.0M in employee contributions Party Affinity – DEM: 47% REP: 53%" [ref=e178] [cursor=pointer]':
          - /url: /employers/28cba756-82fd-bf00-4aad-26253fbdcd2a/
          - generic [ref=e179]: EUCLIDEAN CAPITAL
          - generic [ref=e180]: $65.0M in employee contributions
          - generic [ref=e181]: "Party Affinity – DEM: 47% REP: 53%"
        - 'link "ANDREESSEN HOROWITZ $62.1M in employee contributions Party Affinity – DEM: 56% REP: 44%" [ref=e182] [cursor=pointer]':
          - /url: /employers/29b9be2e-98b1-cb8a-4f61-42de0bbb7dfb/
          - generic [ref=e183]: ANDREESSEN HOROWITZ
          - generic [ref=e184]: $62.1M in employee contributions
          - generic [ref=e185]: "Party Affinity – DEM: 56% REP: 44%"
        - 'link "BLACKSTONE GROUP $62.0M in employee contributions Party Affinity – DEM: 43% REP: 57%" [ref=e186] [cursor=pointer]':
          - /url: /employers/7fd4e4ea-6be6-a629-77fb-e7364bfddeee/
          - generic [ref=e187]: BLACKSTONE GROUP
          - generic [ref=e188]: $62.0M in employee contributions
          - generic [ref=e189]: "Party Affinity – DEM: 43% REP: 57%"
        - 'link "ENTREPRENEUR $58.1M in employee contributions Party Affinity – DEM: 32% REP: 68%" [ref=e190] [cursor=pointer]':
          - /url: /employers/8fadf54b-b4a5-b8c7-971a-443b79a7f9b5/
          - generic [ref=e191]: ENTREPRENEUR
          - generic [ref=e192]: $58.1M in employee contributions
          - generic [ref=e193]: "Party Affinity – DEM: 32% REP: 68%"
        - 'link "LONE PINE CAPITAL $53.6M in employee contributions Party Affinity – DEM: 54% REP: 46%" [ref=e194] [cursor=pointer]':
          - /url: /employers/fc053346-cf8c-a249-ef6e-5f5149f76a46/
          - generic [ref=e195]: LONE PINE CAPITAL
          - generic [ref=e196]: $53.6M in employee contributions
          - generic [ref=e197]: "Party Affinity – DEM: 54% REP: 46%"
        - 'link "CHARLES SCHWAB CORPORATION $53.5M in employee contributions Party Affinity – DEM: 41% REP: 59%" [ref=e198] [cursor=pointer]':
          - /url: /employers/f8e34f37-1ea2-67e6-22ce-cfcb621a25a1/
          - generic [ref=e199]: CHARLES SCHWAB CORPORATION
          - generic [ref=e200]: $53.5M in employee contributions
          - generic [ref=e201]: "Party Affinity – DEM: 41% REP: 59%"
        - 'link "ASANA INC $52.1M in employee contributions Party Affinity – DEM: 58% REP: 42%" [ref=e202] [cursor=pointer]':
          - /url: /employers/c76e3e27-2b8b-debb-50c4-ca9a8d1dc20a/
          - generic [ref=e203]: ASANA INC
          - generic [ref=e204]: $52.1M in employee contributions
          - generic [ref=e205]: "Party Affinity – DEM: 58% REP: 42%"
        - 'link "FTX $51.2M in employee contributions Party Affinity – DEM: 67% REP: 33%" [ref=e206] [cursor=pointer]':
          - /url: /employers/f1ce8a13-eb9c-bcda-174f-d1dc6ab05bb2/
          - generic [ref=e207]: FTX
          - generic [ref=e208]: $51.2M in employee contributions
          - generic [ref=e209]: "Party Affinity – DEM: 67% REP: 33%"
        - 'link "INVESTOR $50.3M in employee contributions Party Affinity – DEM: 48% REP: 52%" [ref=e210] [cursor=pointer]':
          - /url: /employers/5e3e4bc1-d2b9-0ade-5ca3-46e42b938692/
          - generic [ref=e211]: INVESTOR
          - generic [ref=e212]: $50.3M in employee contributions
          - generic [ref=e213]: "Party Affinity – DEM: 48% REP: 52%"
      - generic [ref=e214]:
        - generic [ref=e215]: Showing 1-50
        - generic [ref=e216]:
          - button "First" [disabled] [ref=e217]
          - button "Prev" [disabled] [ref=e218]
          - button "1" [ref=e219] [cursor=pointer]
          - button "Next" [ref=e220] [cursor=pointer]
  - main [ref=e221]
```

# Test source

```ts
  1   | import { test, expect, APIRequestContext } from '@playwright/test';
  2   | import { canonicalPath, getRandomItems, toRelativePath } from './helpers';
  3   | 
  4   | /*
  5   |  * Routing coverage across every collection (electinfo/rundeck#700, ops#514).
  6   |  *
  7   |  * What slipped past the existing specs:
  8   |  *   - a /tracts/ catch-all location shadowed the alias resolver, so every tract
  9   |  *     URL answered 200 with the JS browse page and no rel=canonical (sites#161)
  10  |  *     -- nothing sampled tracts;
  11  |  *   - the preview nginx lacked the /politicians/ -> /candidates/ rewrite the
  12  |  *     production config has (sites#162) -- only 3 random index links were followed;
  13  |  *   - unknown paths fall through to the Payload slug lookup, which answers
  14  |  *     400/500 instead of 404.
  15  |  */
  16  | 
  17  | const ALIASES = process.env.EXPECT_ALIASES === '1';
  18  | 
  19  | /** Collections whose sitemap lists canonical URLs (rundeck PagePaths Sitemaps + CyclePages). */
  20  | const SITEMAP_COLLECTIONS = ['candidates', 'committees', 'parties', 'offices', 'districts', 'states', 'elections'];
  21  | 
  22  | /** Indexes whose first results page lists entity links (.entity-search-result). */
  23  | // (/states/ lists map chips and /districts/ lists .district-result behind a state
  24  | // filter; their sitemap tests cover them)
  25  | const LINKED_INDEXES = ['/candidates/', '/committees/', '/parties/', '/offices/', '/elections/', '/employers/', '/vendors/'];
  26  | 
  27  | const locs = (xml: string) => [...xml.matchAll(/<loc>([^<]+)<\/loc>/g)].map(m => m[1]);
  28  | 
  29  | /** Canonical page URLs from a collection's sitemap, following one level of sitemap index. */
  30  | async function sitemapLocs(request: APIRequestContext, collection: string): Promise<string[]> {
  31  |   const path = `/${collection}/sitemap-${collection}.xml`;
  32  |   const res = await request.get(path);
  33  |   expect(res.status(), `${path} should answer 200`).toBe(200);
  34  |   const xml = await res.text();
  35  |   if (!xml.includes('<sitemapindex')) return locs(xml);
  36  |   const [child] = getRandomItems(locs(xml), 1, `child:${path}`);
  37  |   const childPath = toRelativePath(child);
  38  |   const childRes = await request.get(childPath);
  39  |   expect(childRes.status(), `${childPath} should answer 200`).toBe(200);
  40  |   return locs(await childRes.text());
  41  | }
  42  | 
  43  | test.describe('routing: canonical URLs per collection', () => {
  44  |   test.skip(!ALIASES, 'Set EXPECT_ALIASES=1 against a target with published page paths');
  45  | 
  46  |   for (const collection of SITEMAP_COLLECTIONS) {
  47  |     test(`${collection}: sitemap URLs serve their page with rel=canonical = the sitemap URL`, async ({ request }) => {
  48  |       // Entity pages only: a sitemap may also list the collection's index (/elections/)
  49  |       const entityLocs = (await sitemapLocs(request, collection)).filter(l => toRelativePath(l) !== `/${collection}/`);
  50  |       const sample = getRandomItems(entityLocs, 3);
  51  |       expect(sample.length, `${collection} sitemap should list URLs`).toBeGreaterThan(0);
  52  |       for (const loc of sample) {
  53  |         const path = toRelativePath(loc);
  54  |         const res = await request.get(path, { maxRedirects: 0 });
  55  |         expect(res.status(), `${path} (from the ${collection} sitemap) should answer 200`).toBe(200);
  56  |         expect(canonicalPath(await res.text()), `${path} rel=canonical`).toBe(path);
  57  |       }
  58  |     });
  59  |   }
  60  | 
  61  |   test('tract URLs resolve through the alias resolver, not a catch-all', async ({ request }) => {
  62  |     // Regression for sites#161: Travis County tract 48453000101 by GEOID
  63  |     const res = await request.get('/tracts/48453000101/', { maxRedirects: 0 });
  64  |     expect([200, 301], '/tracts/48453000101/ should answer 200 or 301').toContain(res.status());
  65  |     if (res.status() === 200) {
  66  |       expect(canonicalPath(await res.text()), '/tracts/48453000101/ rel=canonical').toMatch(/^\/tracts\/[^/]+\/$/);
  67  |     }
  68  |   });
  69  | 
  70  |   test('party badge links by FEC code redirect to the party page', async ({ request }) => {
  71  |     // us.elect.news links parties as /parties/<code>/ (sites#164)
  72  |     for (const code of ['rep', 'dem']) {
  73  |       const res = await request.get(`/parties/${code}/`, { maxRedirects: 0 });
  74  |       expect(res.status(), `/parties/${code}/ should redirect permanently`).toBe(301);
  75  |       const target = res.headers()['location'] ?? '';
  76  |       const page = await request.get(target, { maxRedirects: 0 });
  77  |       expect(page.status(), `/parties/${code}/ -> ${target} should answer 200`).toBe(200);
  78  |     }
  79  |   });
  80  | });
  81  | 
  82  | test.describe('routing: every index link resolves', () => {
  83  |   for (const index of LINKED_INDEXES) {
  84  |     test(`${index} first-page links all answer 200 or 301`, async ({ page, request }) => {
  85  |       test.setTimeout(120000);
  86  |       const res = await page.goto(index);
  87  |       expect(res?.status(), `${index} should answer 200`).toBe(200);
  88  |       await expect(page.locator('.entity-search-result').first(), `${index} should list results`).toBeVisible({ timeout: 15000 });
  89  |       const hrefs = (await page.locator('.entity-search-result').evaluateAll(els => els.map(e => e.getAttribute('href'))))
  90  |         .filter((h): h is string => !!h)
  91  |         .map(toRelativePath);
  92  |       const broken: string[] = [];
  93  |       for (const href of [...new Set(hrefs)]) {
  94  |         const r = await request.get(href, { maxRedirects: 0 });
  95  |         if (r.status() !== 200 && r.status() !== 301) broken.push(`${href} -> ${r.status()}`);
  96  |       }
> 97  |       expect(broken, `${index} links that do not resolve`).toEqual([]);
      |                                                            ^ Error: /employers/ links that do not resolve
  98  |     });
  99  |   }
  100 | });
  101 | 
  102 | test.describe('routing: unknown addresses', () => {
  103 |   test('an unknown entity path answers 404', async ({ request }) => {
  104 |     // Today the miss falls through to Payload /api/slug-lookup, which answers
  105 |     // 400/500. Remove test.fail once slug-lookup returns 404 (ops#514 follow-up).
  106 |     test.fail(true, 'Payload slug-lookup answers 400/500 for unknown paths');
  107 |     for (const path of ['/candidates/no-such-entity-zz/', '/tracts/no-such-tract/']) {
  108 |       const res = await request.get(path, { maxRedirects: 0 });
  109 |       expect(res.status(), `${path} should answer 404`).toBe(404);
  110 |     }
  111 |   });
  112 | });
  113 | 
```