# 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/sitemap.spec.ts >> sitemap URL validation >> parties sitemap - sample URLs resolve
- Location: tests/ui/sitemap.spec.ts:273:7

# Error details

```
Error: Errors: Expected 200 for /parties/dts/, got 503, Expected 200 for /parties/lmn/, got 503, Expected 200 for /parties/n/, got 503, Expected 200 for /parties/tra/, got 503, Expected 200 for /parties/constitution/, got 503

expect(received).toHaveLength(expected)

Expected length: 0
Received length: 5
Received array:  ["Expected 200 for /parties/dts/, got 503", "Expected 200 for /parties/lmn/, got 503", "Expected 200 for /parties/n/, got 503", "Expected 200 for /parties/tra/, got 503", "Expected 200 for /parties/constitution/, got 503"]
```

# Page snapshot

```yaml
- generic [active] [ref=f5e1]:
  - heading "503 Service Temporarily Unavailable" [level=1] [ref=f5e3]
  - separator [ref=f5e4]
  - generic [ref=f5e5]: nginx/1.31.7
```

# Test source

```ts
  186 |           // Verify page has content
  187 |           const h1Visible = await page.locator('h1').isVisible().catch(() => false);
  188 |           if (!h1Visible) {
  189 |             const error = `Page ${path} loaded but has no visible h1`;
  190 |             console.log(`${indent}  WARNING: ${error}`);
  191 |             // Don't treat missing h1 as hard failure, just log it
  192 |           }
  193 |         }
  194 |       }
  195 |     }
  196 |   }
  197 | 
  198 |   console.log(`${indent}Tested ${result.tested} URLs from ${sitemapPath}`);
  199 |   return result;
  200 | }
  201 | 
  202 | test.describe('sitemap URL validation', () => {
  203 | 
  204 |   test('sitemap index loads and contains child sitemaps', async ({ page }) => {
  205 |     const response = await page.goto('/sitemap.xml');
  206 |     expect(response?.status()).toBe(200);
  207 | 
  208 |     const content = await page.content();
  209 |     expect(content).toContain('sitemapindex');
  210 |     // Candidates and committees are listed per lead character of the slug (rundeck Sitemaps
  211 |     // LeadBuckets), not through their per-collection index: an index inside an index is not followed.
  212 |     for (const collection of ['candidates', 'committees']) {
  213 |       for (const bucket of LEAD_BUCKETS) {
  214 |         expect(content).toContain(`/${collection}/sitemap-${collection}-${bucket}.xml`);
  215 |       }
  216 |       expect(content).not.toContain(`/${collection}/sitemap-${collection}.xml`);
  217 |     }
  218 |   });
  219 | 
  220 |   test('sitemap index lists no nested index', async ({ request }) => {
  221 |     const index = await (await request.get('/sitemap.xml')).text();
  222 |     const children = parseUrlsFromSitemap(index).map(u => new URL(u).pathname);
  223 |     expect(children.length).toBeGreaterThan(0);
  224 |     const nested: string[] = [];
  225 |     for (const path of children) {
  226 |       // The first bytes say urlset or sitemapindex; the bucket files run to megabytes.
  227 |       const res = await request.get(path, { headers: { Range: 'bytes=0-1023' } });
  228 |       if (res.status() === 404 && !STRICT) continue;
  229 |       expect([200, 206], `${path} should load`).toContain(res.status());
  230 |       if (!(await res.text()).includes('<urlset')) nested.push(path);
  231 |     }
  232 |     expect(nested, 'children of /sitemap.xml that are not urlsets').toEqual([]);
  233 |   });
  234 | 
  235 |   test('candidates sitemap - sample URLs resolve', async ({ page }) => {
  236 |     test.setTimeout(120000);
  237 | 
  238 |     // Navigate to a simple page first so we have a page context for fetch
  239 |     await page.goto('/');
  240 |     const baseUrl = new URL(page.url()).origin;
  241 | 
  242 |     const result = await testSitemapUrls(page, baseUrl, '/candidates/sitemap-candidates.xml');
  243 | 
  244 |     if (result.tested === 0 && !STRICT) {
  245 |       test.skip();
  246 |       return;
  247 |     }
  248 |     expect(result.tested, `sitemap sampled no URLs; errors: ${result.errors.join(', ')}`).toBeGreaterThan(0);
  249 | 
  250 |     console.log(`Tested ${result.tested} URLs from candidates sitemap`);
  251 |     expect(result.errors, `Errors: ${result.errors.join(', ')}`).toHaveLength(0);
  252 |   });
  253 | 
  254 |   test('committees sitemap - sample URLs resolve', async ({ page }) => {
  255 |     test.setTimeout(120000);
  256 | 
  257 |     // Navigate to a simple page first so we have a page context for fetch
  258 |     await page.goto('/');
  259 |     const baseUrl = new URL(page.url()).origin;
  260 | 
  261 |     const result = await testSitemapUrls(page, baseUrl, '/committees/sitemap-committees.xml');
  262 | 
  263 |     if (result.tested === 0 && !STRICT) {
  264 |       test.skip();
  265 |       return;
  266 |     }
  267 |     expect(result.tested, `sitemap sampled no URLs; errors: ${result.errors.join(', ')}`).toBeGreaterThan(0);
  268 | 
  269 |     console.log(`Tested ${result.tested} URLs from committees sitemap`);
  270 |     expect(result.errors, `Errors: ${result.errors.join(', ')}`).toHaveLength(0);
  271 |   });
  272 | 
  273 |   test('parties sitemap - sample URLs resolve', async ({ page }) => {
  274 |     await page.goto('/');
  275 |     const baseUrl = new URL(page.url()).origin;
  276 | 
  277 |     const result = await testSitemapUrls(page, baseUrl, '/parties/sitemap-parties.xml');
  278 | 
  279 |     if (result.tested === 0 && !STRICT) {
  280 |       test.skip();
  281 |       return;
  282 |     }
  283 |     expect(result.tested, `sitemap sampled no URLs; errors: ${result.errors.join(', ')}`).toBeGreaterThan(0);
  284 | 
  285 |     console.log(`Tested ${result.tested} URLs from parties sitemap`);
> 286 |     expect(result.errors, `Errors: ${result.errors.join(', ')}`).toHaveLength(0);
      |                                                                  ^ Error: Errors: Expected 200 for /parties/dts/, got 503, Expected 200 for /parties/lmn/, got 503, Expected 200 for /parties/n/, got 503, Expected 200 for /parties/tra/, got 503, Expected 200 for /parties/constitution/, got 503
  287 |   });
  288 | 
  289 |   test('offices sitemap - sample URLs resolve', async ({ page }) => {
  290 |     await page.goto('/');
  291 |     const baseUrl = new URL(page.url()).origin;
  292 | 
  293 |     const result = await testSitemapUrls(page, baseUrl, '/offices/sitemap-offices.xml');
  294 | 
  295 |     if (result.tested === 0 && !STRICT) {
  296 |       test.skip();
  297 |       return;
  298 |     }
  299 |     expect(result.tested, `sitemap sampled no URLs; errors: ${result.errors.join(', ')}`).toBeGreaterThan(0);
  300 | 
  301 |     console.log(`Tested ${result.tested} URLs from offices sitemap`);
  302 |     expect(result.errors, `Errors: ${result.errors.join(', ')}`).toHaveLength(0);
  303 |   });
  304 | 
  305 |   test('districts sitemap - sample URLs resolve', async ({ page }) => {
  306 |     await page.goto('/');
  307 |     const baseUrl = new URL(page.url()).origin;
  308 | 
  309 |     const result = await testSitemapUrls(page, baseUrl, '/districts/sitemap-districts.xml');
  310 | 
  311 |     if (result.tested === 0 && !STRICT) {
  312 |       test.skip();
  313 |       return;
  314 |     }
  315 |     expect(result.tested, `sitemap sampled no URLs; errors: ${result.errors.join(', ')}`).toBeGreaterThan(0);
  316 | 
  317 |     console.log(`Tested ${result.tested} URLs from districts sitemap`);
  318 |     expect(result.errors, `Errors: ${result.errors.join(', ')}`).toHaveLength(0);
  319 |   });
  320 | 
  321 |   test('states sitemap - sample URLs resolve', async ({ page }) => {
  322 |     await page.goto('/');
  323 |     const baseUrl = new URL(page.url()).origin;
  324 | 
  325 |     const result = await testSitemapUrls(page, baseUrl, '/states/sitemap-states.xml');
  326 | 
  327 |     if (result.tested === 0 && !STRICT) {
  328 |       test.skip();
  329 |       return;
  330 |     }
  331 |     expect(result.tested, `sitemap sampled no URLs; errors: ${result.errors.join(', ')}`).toBeGreaterThan(0);
  332 | 
  333 |     console.log(`Tested ${result.tested} URLs from states sitemap`);
  334 |     expect(result.errors, `Errors: ${result.errors.join(', ')}`).toHaveLength(0);
  335 |   });
  336 | 
  337 |   test('elections sitemap - sample URLs resolve', async ({ page }) => {
  338 |     await page.goto('/');
  339 |     const baseUrl = new URL(page.url()).origin;
  340 | 
  341 |     const result = await testSitemapUrls(page, baseUrl, '/elections/sitemap-elections.xml');
  342 | 
  343 |     if (result.tested === 0 && !STRICT) {
  344 |       test.skip();
  345 |       return;
  346 |     }
  347 |     expect(result.tested, `sitemap sampled no URLs; errors: ${result.errors.join(', ')}`).toBeGreaterThan(0);
  348 | 
  349 |     console.log(`Tested ${result.tested} URLs from elections sitemap`);
  350 |     expect(result.errors, `Errors: ${result.errors.join(', ')}`).toHaveLength(0);
  351 |   });
  352 | 
  353 | });
  354 | 
```