# 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/entity-graph.spec.ts >> entityGraph API >> P00009423: neighbours without individuals, money edges with amounts
- Location: tests/ui/entity-graph.spec.ts:40:9

# Error details

```
Error: expect(received).toBe(expected) // Object.is equality

Expected: 200
Received: 400
```

# Test source

```ts
  1  | import { test, expect } from '@playwright/test';
  2  | 
  3  | // Entity graph pop-over (electinfo/sites#249). nginx injects /js/entity-graph.js
  4  | // next to money-flow.js on Candidate and Committee detail pages. The script
  5  | // adds a "Graph" button to the header; opening it fetches entityGraph from
  6  | // /api/graphql, loads /js/entity-graph-view.js (Cytoscape) and draws the node
  7  | // and its most significant neighbours in a modal dialog.
  8  | //
  9  | // Same targets and pages as money-flow.spec.ts.
  10 | 
  11 | const SCRIPT = '<script src="/js/entity-graph.js" defer></script>';
  12 | const DNC = '/committees/a75a9110-f1db-a945-39a8-7503ed3c04da/'; // C00010603
  13 | const HARRIS = '/candidates/a8897257-430c-2bf3-4498-349021b09ca3/'; // P00009423
  14 | const OTHER_PAGES = [
  15 |   '/states/032f8d61-f554-f435-2a6d-50b3c8cc01d7/', // AK
  16 |   '/elections/2024/',
  17 |   '/offices/president/',
  18 | ];
  19 | 
  20 | test.describe('entity-graph script injection', () => {
  21 |   for (const path of [DNC, HARRIS]) {
  22 |     test(`injected once on ${path}`, async ({ request }) => {
  23 |       const res = await request.get(path);
  24 |       expect(res.status()).toBe(200);
  25 |       expect((await res.text()).split(SCRIPT).length - 1).toBe(1);
  26 |     });
  27 |   }
  28 | 
  29 |   for (const path of OTHER_PAGES) {
  30 |     test(`not injected on ${path}`, async ({ request }) => {
  31 |       const res = await request.get(path);
  32 |       expect(res.status()).toBe(200);
  33 |       expect(await res.text()).not.toContain('entity-graph.js');
  34 |     });
  35 |   }
  36 | });
  37 | 
  38 | test.describe('entityGraph API', () => {
  39 |   for (const fecId of ['C00010603', 'P00009423']) {
  40 |     test(`${fecId}: neighbours without individuals, money edges with amounts`, async ({ request }) => {
  41 |       const res = await request.post('/api/graphql', {
  42 |         data: {
  43 |           query: 'query($f: String!) { entityGraph(fecId: $f) { focalId nodes { id label labels focal displayName } edges { type amount } } }',
  44 |           variables: { f: fecId },
  45 |         },
  46 |         timeout: 60000,
  47 |       });
> 48 |       expect(res.status()).toBe(200);
     |                            ^ Error: expect(received).toBe(expected) // Object.is equality
  49 |       const g = (await res.json())?.data?.entityGraph;
  50 |       expect(g).toBeTruthy();
  51 |       expect(g.nodes.filter((n: { focal: boolean }) => n.focal)).toHaveLength(1);
  52 |       expect(g.nodes.length).toBeGreaterThan(5);
  53 |       expect(g.nodes.some((n: { labels: string[] }) => n.labels.includes('Individual'))).toBe(false);
  54 |       expect(g.nodes.every((n: { displayName: string }) => !!n.displayName)).toBe(true);
  55 |       expect(g.edges.some((e: { amount: number | null }) => e.amount != null && e.amount > 0)).toBe(true);
  56 |     });
  57 |   }
  58 | });
  59 | 
  60 | test.describe('entity-graph pop-over', () => {
  61 |   for (const path of [DNC, HARRIS]) {
  62 |     test(`opens and draws on ${path}`, async ({ page }) => {
  63 |       const errors: string[] = [];
  64 |       page.on('pageerror', (e) => errors.push(String(e)));
  65 |       await page.goto(path);
  66 |       const button = page.locator('button.eg-open');
  67 |       await expect(button).toHaveCount(1, { timeout: 15000 });
  68 |       await button.click();
  69 |       const dialog = page.locator('dialog.eg-dialog');
  70 |       await expect(dialog).toBeVisible();
  71 |       await expect(dialog.locator('.eg-canvas canvas').first()).toBeVisible({ timeout: 60000 });
  72 |       // centred in the viewport, horizontally and vertically
  73 |       const box = (await dialog.boundingBox())!;
  74 |       const vp = page.viewportSize()!;
  75 |       expect(Math.abs(box.x - (vp.width - box.x - box.width))).toBeLessThanOrEqual(2);
  76 |       expect(Math.abs(box.y - (vp.height - box.y - box.height))).toBeLessThanOrEqual(2);
  77 |       await page.keyboard.press('Escape');
  78 |       await expect(dialog).toBeHidden();
  79 |       expect(errors).toEqual([]);
  80 |     });
  81 |   }
  82 | });
  83 | 
```