# 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/data-contracts.spec.ts >> graph data contracts >> the graph serves every scalar the schema declares (seeded sample per type)
- Location: tests/ui/data-contracts.spec.ts:81:7

# Error details

```
Error: apiRequestContext.post: connect ETIMEDOUT 10.1.21.217:80
Call log:
  - → POST http://10.1.21.217/api/graphql
    - user-agent: Playwright/1.64.0 (x64; ubuntu 22.04) node/20.9 CI/1
    - accept: */*
    - accept-encoding: gzip,deflate,br
    - content-type: application/json
    - content-length: 189

```

# Test source

```ts
  1  | import { test, expect, APIRequestContext, APIResponse } from '@playwright/test';
  2  | 
  3  | /*
  4  |  * Shared helpers for the us.elect.info specs (copied with them into the runner's
  5  |  * tests/ui; testMatch only picks up *.spec.ts, so this file is never run itself).
  6  |  */
  7  | 
  8  | /** The run's sampling seed: SAMPLE_SEED (the Tekton run id), else today, so a run is reproducible. */
  9  | export const SAMPLE_SEED = process.env.SAMPLE_SEED || new Date().toISOString().slice(0, 10);
  10 | 
  11 | function hash(s: string): number {
  12 |   let h = 2166136261;
  13 |   for (let i = 0; i < s.length; i++) {
  14 |     h ^= s.charCodeAt(i);
  15 |     h = Math.imul(h, 16777619);
  16 |   }
  17 |   return h >>> 0;
  18 | }
  19 | 
  20 | function mulberry32(seed: number): () => number {
  21 |   let a = seed;
  22 |   return () => {
  23 |     a = (a + 0x6d2b79f5) | 0;
  24 |     let t = Math.imul(a ^ (a >>> 15), 1 | a);
  25 |     t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
  26 |     return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  27 |   };
  28 | }
  29 | 
  30 | /**
  31 |  * Up to `count` items of `array`, sampled deterministically from SAMPLE_SEED and
  32 |  * `label` (default: the current test's title), and logged — so a failing sample
  33 |  * can be re-run exactly (SAMPLE_SEED=<seed> npx playwright test ...).
  34 |  */
  35 | export function getRandomItems<T>(array: T[], count: number, label?: string): T[] {
  36 |   let name = label;
  37 |   if (!name) {
  38 |     try {
  39 |       name = test.info().title;
  40 |     } catch {
  41 |       name = 'sample';
  42 |     }
  43 |   }
  44 |   const rand = mulberry32(hash(`${SAMPLE_SEED}:${name}`));
  45 |   const shuffled = [...array];
  46 |   for (let i = shuffled.length - 1; i > 0; i--) {
  47 |     const j = Math.floor(rand() * (i + 1));
  48 |     [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
  49 |   }
  50 |   const picked = shuffled.slice(0, Math.min(count, array.length));
  51 |   const show = (x: T) => (x !== null && typeof x === 'object' ? JSON.stringify(x) : String(x));
  52 |   console.log(`[sample seed=${SAMPLE_SEED}] ${name}: ${picked.map(show).join(', ')}`);
  53 |   return picked;
  54 | }
  55 | 
  56 | /** Path of a URL (absolute or relative). */
  57 | export function toRelativePath(url: string): string {
  58 |   try {
  59 |     return new URL(url).pathname;
  60 |   } catch {
  61 |     return url;
  62 |   }
  63 | }
  64 | 
  65 | /** The path of the page's rel=canonical, whatever host the page was generated for. */
  66 | export function canonicalPath(html: string): string | null {
  67 |   const m = html.match(/<link[^>]+rel=['"]canonical['"][^>]+href=['"]([^'"]+)['"]/i)
  68 |     ?? html.match(/<link[^>]+href=['"]([^'"]+)['"][^>]+rel=['"]canonical['"]/i);
  69 |   if (!m) return null;
  70 |   try {
  71 |     return new URL(m[1]).pathname;
  72 |   } catch {
  73 |     return m[1];
  74 |   }
  75 | }
  76 | 
  77 | /** Run a GraphQL query against the target's /api/graphql proxy; fails with the query on HTTP or GraphQL errors. */
  78 | export async function gql<T = any>(
  79 |   request: APIRequestContext,
  80 |   query: string,
  81 |   variables: Record<string, unknown> = {},
  82 | ): Promise<T> {
> 83 |   const res: APIResponse = await request.post('/api/graphql', { data: { query, variables } });
     |                                          ^ Error: apiRequestContext.post: connect ETIMEDOUT 10.1.21.217:80
  84 |   const label = query.replace(/\s+/g, ' ').trim().slice(0, 120);
  85 |   expect(res.status(), `POST /api/graphql ${label} should answer 200`).toBe(200);
  86 |   const body = await res.json();
  87 |   expect(body.errors, `GraphQL errors for ${label}: ${JSON.stringify(body.errors)}`).toBeUndefined();
  88 |   return body.data as T;
  89 | }
  90 | 
```