Skip to content
SDETRole
SDETRole

Playwright interview question

A Playwright test passes locally but fails intermittently in CI. How do you debug and fix it?

advanced 5+ yrs #flaky-tests#trace-viewer#debugging#ci#retries

Short answer

Collect evidence first: traces on retry, screenshots, video. Reproduce with --repeat-each and different worker counts. Classify the cause (timing, data, isolation, environment, real product race) and fix it with web-first assertions, isolated data and explicit signals. Track and quarantine; never just add retries.

Answer

My first goal is evidence, not a fix. “Passes locally, fails in CI” usually means the test is timing-sensitive, depends on data or state that differs in CI, interferes with other tests running in parallel, or has found a real race in the product. I collect artifacts, reproduce the failure deliberately, classify the cause, and fix the root cause. Adding retries or timeouts without understanding the failure just makes it fail less often and harder to debug.

1. Capture evidence in CI

// playwright.config.ts
export default defineConfig({
  retries: process.env.CI ? 2 : 0,
  use: {
    trace: 'on-first-retry',          // or 'retain-on-failure'
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },
});

Open the trace from the HTML report or with npx playwright show-trace trace.zip. The trace viewer shows every action with before/after DOM snapshots, the locator resolution log, console messages, network requests with timing, and the source line. Questions I ask:

  • Did the action target the element I expected, or a similarly named one?
  • Was a network request still pending, or did it fail, when the assertion ran?
  • Did something unexpected appear: a cookie banner, a toast covering a button, a different A/B variant?

test.step() in tests makes long traces far easier to navigate.

2. Reproduce deliberately

npx playwright test checkout.spec.ts --repeat-each=30 --workers=4
npx playwright test checkout.spec.ts --repeat-each=30 --workers=1   # compare: isolation problem?
  • Fails only with many workers: shared data or state between tests.
  • Fails only when run with the whole suite but not alone: order dependency or leaked server state.
  • Fails even with one worker: timing within the test or a product race. Emulating a slower machine helps, for example CPU throttling through a CDP session in Chromium or running in the same Docker image as CI.
  • Fails only in CI: compare environment, browser version, viewport, locale, time zone, and test data.

3. Common root causes and fixes

Snapshot assertions and manual waits

// flaky
expect(await page.locator('.total').textContent()).toBe('$42.00');
await page.waitForTimeout(2000);

// robust
await expect(page.getByTestId('order-total')).toHaveText('$42.00');

Asserting before the data exists: wait for the response that matters, or poll the API with expect.poll.

Missing await: a floating promise lets the test end early. Enable @typescript-eslint/no-floating-promises.

Shared test data: two workers editing the same user. Create unique data per test in a fixture.

Ambiguous locators: getByText('Save') matching a hidden duplicate in a modal. Scope it to the dialog or use getByRole with a name.

Animations and transient UI: toasts or overlays intercepting clicks. Assert they are gone, or disable animations in the test environment.

Time and locale: tests that assume the local time zone or the current date. Set timezoneId and locale in config, and use page.clock (1.45+) to control time.

Real product races: a button enabled before its handler is ready, double submits. These are bugs to report, not flakes to hide.

4. Process: retries are a detector, not a cure

  • Treat a test that passes on retry as flaky, which the Playwright report labels separately. Track flaky counts over time from CI results.
  • Use --fail-on-flaky-tests (and in newer versions the failOnFlakyTests config option) in pipelines where flakiness must block merges.
  • Quarantine a flaky test (test.fixme or a tagged project that does not block) only with an owner and a deadline, so the suite stays trusted without silently losing coverage.

What interviewers look for

  • An evidence-first approach with the trace viewer and CI artifacts.
  • Deliberate reproduction to separate timing, isolation and environment causes.
  • Root-cause fixes using web-first assertions, isolated data and explicit signals.
  • A mature stance on retries, tracking and quarantine.

A strong answer covers

  • Uses the trace viewer and CI artifacts (trace on first retry, screenshots, video)
  • Reproduces with --repeat-each, workers or throttling
  • Classifies root causes: timing, data, isolation, environment, product bug
  • Fixes with web-first assertions and explicit signals, not sleeps
  • Treats retries as detection, tracks flakiness and quarantines
Practise answering under time pressure

Type to search across SDETRole.

Full-text search by Pagefind · runs in your browser Open search page →