# 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-suggest.spec.ts >> entity type-ahead (sites#392) >> does not fetch while composing and fits the mobile search form
- Location: tests/ui/entity-suggest.spec.ts:187:7

# Error details

```
Error: page.goto: net::ERR_CONNECTION_REFUSED at http://10.1.105.22/politicians/
Call log:
  - navigating to "http://10.1.105.22/politicians/", waiting until "load"

```

# Test source

```ts
  90  |     await input.press('Escape');
  91  |     await expect(input).toHaveAttribute('aria-expanded', 'false');
  92  |     await expect(input).not.toHaveAttribute('aria-activedescendant');
  93  |     await input.fill('ted cruz');
  94  |     await expect(page.locator('.entity-suggestions').getByRole('option')).toHaveCount(2);
  95  |     await input.press('ArrowDown');
  96  |     await input.press('Enter');
  97  |     await expect(page).toHaveURL(/\/candidates\/ted-cruz-s2tx00312\/\?cycle=2024$/);
  98  |     await expect(page.getByRole('heading')).toHaveText('Canonical candidate');
  99  |   });
  100 | 
  101 |   for (const [collection, type] of [['committees', 'Committee'], ['parties', 'Party']]) {
  102 |     test(`pointer opens ${collection} via UUID fallback if canonical lookup is unavailable`, async ({ page }) => {
  103 |       const item = { ...candidate, type, name: '<img src=x onerror=alert(1)> & test' };
  104 |       await setup(page, [item]);
  105 |       await page.route(`**/${collection}/${candidate.id}/`, route => route.request().method() === 'HEAD'
  106 |         ? route.fulfill({ status: 503 })
  107 |         : route.fulfill({ contentType: 'text/html', body: '<h1>Entity page</h1>' }));
  108 |       await page.goto(`/${collection}/`);
  109 |       await page.getByRole('combobox', { name: 'Search entities' }).fill('test');
  110 |       await expect(page.locator('.entity-suggestions').getByRole('option')).toHaveText(new RegExp('onerror=alert'));
  111 |       await expect(page.locator('.entity-suggestions').getByRole('option').locator('img')).toHaveCount(0);
  112 |       await page.locator('.entity-suggestions').getByRole('option').click();
  113 |       await expect(page).toHaveURL(new RegExp(`/${collection}/${candidate.id}/$`));
  114 |     });
  115 |   }
  116 | 
  117 |   for (const mode of ['ok', 'http-error', 'graphql-error'] as const) {
  118 |     test(`submitted search still displays returned rows with total=0 (${mode})`, async ({ page }) => {
  119 |       const requests = await setup(page, mode === 'ok' ? [candidate] : [], mode);
  120 |       await page.goto('/politicians/');
  121 |       const input = page.getByRole('combobox', { name: 'Search entities' });
  122 |       await input.fill('ted cru');
  123 |       if (mode === 'ok') await expect(page.locator('.entity-suggestions').getByRole('option')).toHaveCount(1);
  124 |       else await expect(page.getByRole('status')).toContainText('Suggestions unavailable');
  125 |       // Without an arrow-key selection, Enter must retain the submit fallback.
  126 |       await input.press('Enter');
  127 |       await expect(page.locator('#entity-results-title')).toHaveText('Search Results for "ted cru"');
  128 |       await expect(page.locator('.entity-search-result')).toContainText(candidate.name);
  129 |       await expect(page.locator('.entity-search-result')).not.toContainText('Browse politician');
  130 |       await expect(page.getByRole('listbox')).toBeHidden();
  131 |       expect(requests.find(r => r.query.includes('searchEntities('))?.variables).toMatchObject({ query: 'ted cru', entityType: 'Politician' });
  132 |       await expect(page).toHaveURL(/q=ted\+cru/);
  133 |     });
  134 |   }
  135 | 
  136 |   test('empty suggestions keep explicit Search and Show All working', async ({ page }) => {
  137 |     await setup(page, []);
  138 |     await page.goto('/politicians/');
  139 |     await page.getByRole('combobox', { name: 'Search entities' }).fill('ted cruz');
  140 |     await expect(page.getByRole('status')).toContainText('No suggestions');
  141 |     await page.getByRole('button', { name: 'Search', exact: true }).click();
  142 |     await expect(page.locator('.entity-search-result')).toContainText(candidate.name);
  143 |     await page.getByRole('button', { name: 'Show All' }).click();
  144 |     await expect(page.locator('#entity-results-title')).toHaveText('All Politicians');
  145 |     await expect(page.getByRole('combobox', { name: 'Search entities' })).toHaveValue('');
  146 |   });
  147 | 
  148 |   test('ignores late replies after a new prefix, dismissal, or clearing below the minimum', async ({ page }) => {
  149 |     await setup(page);
  150 |     let release!: () => void;
  151 |     await page.route('**/api/graphql', async route => {
  152 |       if (!(route.request().postDataJSON() as Request).query.includes('entitySuggest(')) return route.fallback();
  153 |       await new Promise<void>(r => { release = r; });
  154 |       await route.fulfill({ json: { data: { entitySuggest: [{ ...candidate, name: 'Stale match' }] } } }).catch(() => {});
  155 |     });
  156 |     await page.goto('/politicians/');
  157 |     const input = page.getByRole('combobox', { name: 'Search entities' });
  158 |     for (const action of ['clear', 'escape', 'blur']) {
  159 |       release = undefined as any;
  160 |       await input.fill('ted cru');
  161 |       await expect.poll(() => !!release).toBe(true);
  162 |       if (action === 'clear') await input.fill('t');
  163 |       else if (action === 'escape') await input.press('Escape');
  164 |       else await input.press('Tab');
  165 |       release();
  166 |       await page.waitForTimeout(100);
  167 |       await expect(input).toHaveAttribute('aria-expanded', 'false');
  168 |       await expect(page.locator('.entity-suggestions').getByRole('option')).toHaveCount(0);
  169 |     }
  170 |   });
  171 | 
  172 |   test.describe('touch selection', () => {
  173 |     test.use({ hasTouch: true, isMobile: true, viewport: { width: 390, height: 844 } });
  174 |     test('tap opens an option without blur removing it first', async ({ page }) => {
  175 |       await setup(page);
  176 |       await page.route(`**/candidates/${candidate.id}/`, route => route.request().method() === 'HEAD'
  177 |         ? route.fulfill({ status: 503 })
  178 |         : route.fulfill({ contentType: 'text/html', body: '<h1>Entity page</h1>' }));
  179 |       await page.goto('/politicians/');
  180 |       await page.getByRole('combobox', { name: 'Search entities' }).fill('ted cru');
  181 |       await expect(page.getByRole('listbox').getByRole('option')).toBeVisible();
  182 |       await page.getByRole('listbox').getByRole('option').tap();
  183 |       await expect(page).toHaveURL(new RegExp(`/candidates/${candidate.id}/$`));
  184 |     });
  185 |   });
  186 | 
  187 |   test('does not fetch while composing and fits the mobile search form', async ({ page }) => {
  188 |     const requests = await setup(page);
  189 |     await page.setViewportSize({ width: 390, height: 844 });
> 190 |     await page.goto('/politicians/');
      |                ^ Error: page.goto: net::ERR_CONNECTION_REFUSED at http://10.1.105.22/politicians/
  191 |     const input = page.getByRole('combobox', { name: 'Search entities' });
  192 |     await input.dispatchEvent('compositionstart');
  193 |     await input.fill('ted cru');
  194 |     await page.waitForTimeout(350);
  195 |     expect(suggestRequests(requests)).toHaveLength(0);
  196 |     await input.dispatchEvent('compositionend');
  197 |     await expect(page.locator('.entity-suggestions').getByRole('option')).toHaveCount(1);
  198 |     const bounds = await page.getByRole('listbox').boundingBox();
  199 |     expect(bounds!.x).toBeGreaterThanOrEqual(0);
  200 |     expect(bounds!.x + bounds!.width).toBeLessThanOrEqual(390);
  201 |   });
  202 | });
  203 | 
```