# 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/graph-control.spec.ts >> graph control everywhere (sites#355) >> a member sees Graph on /candidates/ and gets the hint
- Location: tests/ui/graph-control.spec.ts:18:9

# Error details

```
Error: expect(locator).not.toHaveAttribute(expected) failed

Locator:  locator('#auth-slot [data-control="graph"]')
Expected: not "true"
Received: "true"
Timeout:  5000ms

Call log:
  - Expect "not toHaveAttribute" locator('#auth-slot [data-control="graph"]') with timeout 5000ms
  - waiting for locator('#auth-slot [data-control="graph"]')
    14 × locator resolved to <button type="button" data-control="graph" aria-disabled="true" class="ei-control ei-control--locked" title="Needs Graph access: request it" aria-label="Graph (Needs Graph access: request it)">…</button>
       - unexpected value "true"

```

```yaml
- 'button "Graph (Needs Graph access: request it)" [disabled]': Graph
```

# Test source

```ts
  1  | import { test, expect, Page } from '@playwright/test';
  2  | 
  3  | // The Graph member control on every page (sites#355). Entity pages keep the
  4  | // real graph pop-over (entity-graph.js); elsewhere the control
  5  | // is a placeholder: locked for anonymous visitors, and for members a hint
  6  | // pointing at the pages with a graph. Identity is mocked (Authentik on), so
  7  | // these run on CI pods and on preview alike.
  8  | 
  9  | const DNC = '/committees/a75a9110-f1db-a945-39a8-7503ed3c04da/'; // C00010603
  10 | 
  11 | async function as(page: Page, email: string): Promise<void> {
  12 |   await page.route('**/auth/whoami*', r => r.fulfill({ json: { enabled: 'true', email, elevated: false, entitlements: {} } }));
  13 |   await page.route('**/auth/account/me*', r => r.fulfill({ json: { email, requests: [], agreement: null, granted: [] } }));
  14 | }
  15 | 
  16 | test.describe('graph control everywhere (sites#355)', () => {
  17 |   for (const path of ['/', '/candidates/']) {
  18 |     test(`a member sees Graph on ${path} and gets the hint`, async ({ page }) => {
  19 |       await as(page, 'jane@example.org');
  20 |       await page.goto(path);
  21 |       const graph = page.locator('#auth-slot [data-control="graph"]');
  22 |       await expect(graph).toHaveCount(1, { timeout: 15000 });
> 23 |       await expect(graph).not.toHaveAttribute('aria-disabled', 'true');
     |                               ^ Error: expect(locator).not.toHaveAttribute(expected) failed
  24 |       await graph.click();
  25 |       await expect(page.locator('#ei-graph-hint')).toContainText('geography page');
  26 |       await expect(page.locator('dialog.eg-dialog')).toHaveCount(0);
  27 |     });
  28 |   }
  29 | 
  30 |   test('signed out, the homepage Graph is locked and offers sign-in', async ({ page }) => {
  31 |     await as(page, '');
  32 |     await page.goto('/');
  33 |     const graph = page.locator('#auth-slot [data-control="graph"]');
  34 |     await expect(graph).toHaveAttribute('aria-disabled', 'true', { timeout: 15000 });
  35 |     await graph.click({ force: true });
  36 |     await expect(page.locator('dialog#ei-signin h2')).toHaveText('Sign in to use Graph');
  37 |   });
  38 | 
  39 |   test('a committee page keeps one Graph control: the real pop-over', async ({ page }) => {
  40 |     await as(page, 'jane@example.org');
  41 |     await page.goto(DNC);
  42 |     const graph = page.locator('#auth-slot [data-control="graph"]');
  43 |     await expect(graph).toHaveCount(1, { timeout: 15000 });
  44 |     await graph.click();
  45 |     await expect(page.locator('dialog.eg-dialog')).toBeVisible();
  46 |     await expect(page.locator('#ei-graph-hint')).toHaveCount(0);
  47 |   });
  48 | });
  49 | 
```