THE REPLACEQA BLOG
How to debug failed Playwright tests with a trace
Open a Playwright trace and inspect the failed action, page state and network evidence to investigate a failed test.
To debug a failed Playwright test, open its trace, find the failed action, and work backward to the first point where the observed behavior differs from the expected journey. Then check whether that expectation and the starting environment were correct. A timeout identifies something the test could not finish; it does not tell you who should fix it.
Open the trace from the failed run
Download the failed run's trace artifact from your CI system, or locate the local trace.zip. From your project directory, open it with:
npx playwright show-trace path/to/trace.zip
Replace the example path with the actual file. Trace Viewer shows the recorded run after execution. Select the failed action and inspect its error, locator, source location, and before/after snapshots. Check the preceding action too: a missing heading might follow navigation to the wrong page. These views are documented in the Playwright Trace Viewer guide.
Confirm which attempt you opened. A trace from a successful retry is useful for comparison, but it cannot show exactly what happened in the original failure.
If no trace was recorded, opening the HTML report cannot reconstruct one. Preserve the existing failure output, then configure capture for the next run.
Capture the first failure deliberately
For an investigation where the original failing attempt matters, merge these settings into your existing playwright.config.ts:
import { defineConfig } from '@playwright/test';
export default defineConfig({
retries: 0,
use: {
trace: 'retain-on-failure',
screenshot: 'only-on-failure',
},
});
This records each test attempt and keeps the trace when it fails. The example disables retries to isolate that attempt. Keep your existing projects, server configuration, and other settings. Artifacts normally appear under test-results, unless you configured another output directory. See Playwright's recording configuration.
For routine CI use, another option is retries: 1 with use: { trace: 'on-first-retry' }. That records the first retry, whether it passes or fails. It does not record the initial attempt, and with zero retries it produces no retry trace. Choose the mode according to the evidence you need; the trace option reference describes the available modes.
For a focused investigation, you can also request tracing directly:
npx playwright test tests/search.spec.ts --trace on --retries 0
Replace the file with your failing spec. --trace on retains the recording even if this run passes. Add --project=chromium only if your configuration has a project named chromium. These flags and test-file filters are covered in the Playwright CLI reference.
Preserve the context before another run
Save the trace outside the next run's output directory, together with the failure message and relevant CI output. Record the app release, test revision, target URL, browser project, attempt number, and test data identity. Otherwise, a later pass against a newer deployment may look like a reproduction when it tested something different.
Check the starting state before interpreting the failed step. Was the account signed in? Did the selected record still exist? Did this run use the intended tenant, feature flags, and deployment? A redirect to sign-in could mean expired test credentials, an authentication regression, or an incorrect setup assumption. The redirect alone does not choose between them.
Treat traces as private debugging artifacts. They can contain page content and request data; keep access limited and review what is included before sharing. Opening a local file avoids needing to publish it at a public URL.
Follow the evidence through one journey
Consider an illustrative search journey: enter a project name, submit the search, open a matching result, and check that the detail page belongs to that project.
Start by writing the expected result in ordinary language. “Open the project I selected” is a behavior requirement. “Find a button named Search” is an assumption about how the test performs that task. Both matter, but they can fail for different reasons.
| Observation in the failed run | Possible explanation | Next check |
|---|---|---|
| The test waits for “Search”; the page shows “Find projects” | The locator became obsolete after an intentional label change | Confirm the approved UI behavior and whether the new control performs the same task |
| The selected result identifies project A, but the detail page shows project B | Navigation, response data, rendering, or test selection may be wrong | Compare the selected link, destination URL, request, and returned identity |
| The results area stays loading and a request has not completed | The dependency, network, runner, or application may be slow or stuck | Correlate the request with server logs and compare behavior from the same environment |
For the first case, changing the locator is justified only after confirming the intended interface. If the button disappeared accidentally, updating the test would hide a regression.
For the second, identify where the identity first changes. A link to B from A's card points toward link construction. A request for A that returns B points toward the service or data. A response for A displayed as B points toward client state or rendering. These are investigation paths; logs and a controlled reproduction are still needed to establish the cause.
For the third, a timeout leaves the cause unresolved. A browser trace cannot tell you what an unobserved backend worker was doing. Keep that uncertainty in the issue instead of assigning “environment failure” because the request was slow.
Inspect the request in context
Use the Network and Console panels around the relevant action. Check the request URL, status, and available payload alongside the visible page state. Expand the selected time range if filtering hides an earlier request. The Trace Viewer documentation explains these panels and their action filtering.
A successful response can still contain the wrong record. A failed response can reflect an intentionally rejected request caused by invalid test data. Likewise, a console error may be unrelated to the failed task. Connect each observation to the expected outcome before treating it as an explanation.
If changing page content caused the mismatch, preserve the relationship between selection and destination. The companion guide to testing dynamic content without hardcoded text develops that assertion pattern.
Use retries to compare, then verify the fix
Playwright classifies a test that fails initially and passes on retry as flaky. That classification describes the execution history, not whether the underlying defect belongs to the test or the application. See the retry documentation.
Compare what changed between attempts: account state, returned data, response timing, and the point where the page became usable. An application race can pass on retry and still affect customers. Failure to reproduce manually also leaves the original evidence intact.
Before closing the issue, reproduce the faulty behavior in a controlled environment and show that the check detects it. Then apply the fix and verify the intended task passes. If you revise an assertion, confirm it still rejects the meaningful wrong outcome. Increasing a timeout needs a reason tied to expected behavior; removing the failed assertion removes coverage.
A useful issue records the expected task, observed divergence, relevant artifact, current hypothesis, and next verification step. That gives the next person something concrete to investigate.
ReplaceQA's closed beta supports public journey discovery, generated Playwright tests, and validation evidence. You can request closed-beta access to explore those available checks for your site.