In Playwright, what does the error code passed to route.abort() change?
answer
- Failing a request, not answering it
- There is a default failure code
- Fidelity for the reader, not for the app
- Rejects rather than resolving with an error status
- Named codes for blocked and offline cases
basics
~20 sIt picks which browser-level failure the request reports — the default is failed, with codes such as connectionrefused, namenotresolved and blockedbyclient available. Page JavaScript still sees only a generic network error, so the code affects fidelity and diagnosis, not app branching.
solid answer
~40 s`route.abort()` settles a route by failing the request instead of answering it, and its optional argument names the failure. The default is `'failed'`; the list includes `'aborted'`, `'timedout'`, `'accessdenied'`, `'blockedbyclient'`, `'blockedbyresponse'`, `'addressunreachable'`, `'namenotresolved'`, `'internetdisconnected'` and the `connection*` family. The code shows up in the failure Playwright reports for the request and in the browser's own error output, but page code cannot read it: `fetch()` just rejects and `XMLHttpRequest` just fires `onerror`, whichever code you chose. So pick the code that describes the scenario honestly — `blockedbyclient` for an extension-blocked call, `internetdisconnected` for going offline — and assert on the UI state your dashboard renders, not on the error text.
code
typescript · 9 linesimport { test, expect } from '@playwright/test';
test('dashboard shows offline state when the forecast call fails', async ({ page }) => {
await page.route('**/api/forecast**', route => route.abort('internetdisconnected'));
await page.goto('/dashboard?city=oslo');
await expect(page.getByTestId('forecast-error')).toBeVisible();
await expect(page.getByTestId('temperature')).toBeHidden();
});go deeper
Know that abort fails the request instead of answering it, that the argument is optional, and that a failed call is what makes the page show its network-error state.
Explain that the code selects the browser-level failure, that page JavaScript cannot read it, and how an abort differs from a fulfilled 5xx in whether the promise rejects or resolves.
Demonstrate using abort deliberately — muting third-party beacons and images to steady a run, choosing a code that reads honestly in a trace, and keeping the aborted glob narrow enough not to break the page itself.
Own the distinction between mechanism and policy: your teams need a shared vocabulary for which network failures are simulated where, so failure handling is designed once rather than reinvented per suite.
## What abort does `route.abort()` settles a route by failing the request instead of answering it. The browser is told the request could not be completed, so the page takes whatever path it has for a dead network call: `fetch()` rejects, `XMLHttpRequest` fires its error handler, an `<img>` fires `onerror`, a stylesheet simply never arrives. Nothing goes to the server. Called with no argument it uses the default error code `failed`. The optional argument picks a more specific browser-level failure: - `aborted`, `failed`, `timedout` - `accessdenied`, `blockedbyclient`, `blockedbyresponse` - `addressunreachable`, `namenotresolved`, `internetdisconnected` - `connectionaborted`, `connectionclosed`, `connectionfailed`, `connectionrefused`, `connectionreset` ## What the code actually changes The code changes the failure Playwright reports and the failure the browser records — not the shape of the error your application code sees. | observer | sees the specific code? | |---|---| | page JavaScript (`fetch`, `XHR`) | no — a generic network failure | | `request.failure()` in the test | yes, as the error text | | browser console / devtools output | usually, as a browser-specific error name | So a weather dashboard whose forecast call is aborted with `namenotresolved` renders exactly the same error state it renders for `connectionrefused`. The value of choosing a code is in **fidelity and diagnosis**, not in branching: `blockedbyclient` is what an ad blocker or extension-blocked request looks like, so it is the honest way to simulate "a privacy extension ate our analytics call"; `internetdisconnected` reads correctly in a trace when you meant "the user went into a tunnel". ## When abort beats fulfilling an error status A 500 and an aborted request are different failures and exercise different code: 1. `route.fulfill({ status: 500 })` — the round trip completed. `fetch()` **resolves**; only code that checks `response.ok` notices anything is wrong. 2. `route.abort()` — the round trip never completed. `fetch()` **rejects**; only a `catch` or an error boundary notices. An app that handles one and not the other looks fine until production. Choosing which of these to encode as a test is a test-design question that belongs with the front-end's error-simulation practice; the mechanism — which route verb produces which browser behaviour — is what this call gives you. ## Practical notes - Aborting is also the cheap way to cut noise: abort fonts, images or third-party beacons a test does not care about and the run gets faster and quieter. - An aborted route is settled, so you cannot fulfil it afterwards; the handler is done. - The full code list is Chromium-shaped. All the codes are accepted on every engine, but the exact name the browser surfaces for a given code varies, so assert on your app's error state rather than on error text. - Aborting everything under a glob is a blunt instrument — a page that fails to load its own bundle produces a confusing test failure that looks like a locator bug.
- How is aborting a request different from fulfilling it with status 500?A 500 is a completed round trip: `fetch()` resolves and only a check on `response.ok` notices anything is wrong. An abort never completes: `fetch()` rejects and only a `catch` or error boundary notices. Applications routinely handle one and not the other, so they exercise genuinely different code paths.
- Can a test assert on the specific abort code from inside the page?No. Browsers do not expose the underlying network error to page JavaScript, so the app sees a generic failure whichever code you pass. The code is visible to the test through the request's failure information and in browser error output, so assert on the UI state the failure produces instead.
saying these in an interview costs you the question
- Thinks aborting produces a response with status 0 the app can read
- Expects fetch to resolve after an abort
- Believes the app can branch on the abort code
- Treats abort and a 500 stub as interchangeable failures
- Aborts a broad glob and breaks the page's own assets