Playwright Flaky Tests: Diagnose Before You Retry
Playwright's auto-waiting kills one kind of flake, not all. Learn to diagnose shared fixtures, network races, and isolation bugs before adding retries.

It is 4pm on a Thursday and the release is stuck. The Playwright suite that ran clean all sprint just failed three unrelated tests on the same pipeline run, and nobody touched that code today. An SDET on the team reruns the job, watches two of the three pass, and ships anyway, quietly annoyed.
This is what Playwright flaky tests look like on a normal week for teams that lean on Playwright's built in waiting to solve every timing problem. Auto-waiting is genuinely good at what it does. But it only covers a narrow slice of what makes a browser suite unreliable. This post walks through the other causes. They show up as random red X marks with no obvious code change behind them. Here is how to tell them apart before you reach for a retry count.
Why Playwright's auto-waiting doesn't eliminate all flakiness
Playwright waits for elements to be visible, stable, and receiving events before it acts on them. That removes the classic "clicked before the button rendered" bug that plagued older frameworks.
What it does not do is wait for your application's business logic to finish. It does not wait for your test data to settle. It does not keep your parallel workers out of each other's way.
A checkout test can find the "Place Order" button perfectly clickable while the cart total behind it is still recalculating from a coupon code applied two seconds earlier. The click succeeds. The assertion on the final price fails. The failure looks like a UI timing bug when it is actually a data race one layer down.
Shared fixture state as a common cause of Playwright flakiness
Fixtures are supposed to give each test a clean slate. In practice, teams often reuse a fixture, like a logged in user or a seeded product catalog, across dozens of tests to save setup time.
The trouble starts when two tests in the same worker mutate that shared state. A test that changes a user's email address can quietly break the next test that expects the original address in a confirmation screen.
These failures are maddening because they only appear depending on execution order. A suite that passes when run alone fails when run with the rest of the file. There is one reliable signal here: if a test passes in isolation but fails inside the full suite, shared fixture state is the first thing to check, not the network or the selectors.
Network timing and race conditions in Playwright tests
Browser tests talk to real or mocked backends, and that introduces a second clock that has nothing to do with the DOM. A search results page might issue three API calls on load: one for the results, one for a recommendations widget, and one for an analytics ping.
If a test asserts on the results grid before waiting for the specific response it depends on, it can pass nine times out of ten. Then it fails the tenth time, exactly when the API happens to be 200 milliseconds slower than usual. Common culprits include:
- Assertions that fire on a fixed timeout instead of waiting for a specific network response
- Mocked endpoints that respond faster in CI than the real service does in staging
- Retried API calls on the frontend that the test does not account for
- Websocket or polling based UI updates that land after the test has already moved on
Playwright's waitForResponse and waitForLoadState exist precisely to pin a test to the right event instead of a guessed delay. Using them consistently removes most of this category.
Parallel test isolation issues
Running tests in parallel is the main way teams keep a 900 test Playwright suite under 15 minutes instead of watching it crawl toward an hour.
Parallelism also introduces its own failure mode. Two workers can write to the same test account, the same database row, or the same uploaded file at once. One worker's teardown can delete a record another worker is mid-assertion on. These failures cluster in specific ways worth watching for:
- They spike when the parallel worker count goes up, not when the code changes
- They involve resources named the same way across tests, like
[email protected]reused everywhere - They vanish when the suite runs with a single worker, which is a useful diagnostic step, not a permanent fix
Giving each test its own scoped data, like a unique email, a unique order ID, or a unique tenant, removes the collision entirely instead of papering over it with fewer workers.
How to diagnose before reaching for a retry() config
Playwright's built in retries setting is tempting. It makes red builds green with one config line. It also erases the evidence you need to fix the actual bug, since a passing retry looks identical to a test that never had a problem.
Before adding retries, run the failing test alone. Then run it alongside the file it normally runs with. Then run it under the real worker count used in CI. That sequence usually narrows the cause to one of the three categories above within a few runs.
Teams that document what actually broke, and where in the suite it showed up, catch the pattern faster the second time the same failure appears somewhere else. That is a documentation and traceability problem as much as a testing one. Knowing which fixture, which environment, and which parallel configuration a failure happened under is what turns a mystery flake into a known, fixable issue.
What to do once you've found the real cause
Once a flake is traced to shared fixtures, an unwaited network call, or a parallel collision, the fix is usually small. Scope the fixture. Wait for the right response. Namespace the test data.
The harder part is remembering which tests were flaky for which reason. The person who diagnosed it in March is often not the person debugging a similar failure in September.
We kept fixing the symptom because nobody wrote down what actually broke last time.
Recording the root cause next to the test case, not just in a closed pull request, means the next flake gets solved in minutes instead of another afternoon of reruns.
Questions people ask
Does Playwright's auto-waiting fix flaky tests on its own?
It fixes one common cause, elements not being ready yet, but not application level timing, shared state, or parallel worker collisions.
How do I know if a flaky test is caused by shared fixtures?
If it passes when run alone but fails inside the full suite or in a different order, shared fixture state is the most likely cause.
What is the difference between a network race and a rendering timing bug?
A rendering timing bug is about the DOM not being ready. A network race is about an assertion firing before a specific API response has returned.
Should I just increase Playwright's retries to stop flaky failures?
Retries can hide the underlying cause, since a passing retry looks identical to a clean run. Diagnose first, then decide if a retry is still needed.
Does Tesbo run or execute my Playwright tests?
No. Tesbo manages and documents test cases. It does not execute automated tests or provide a device or browser grid.
Try Tesbo, or get the next useful idea
Start building your testing workflow now, or get one practical email a month.
Start freeOne email a month
What we shipped, what we learned, and the occasional infographic worth pinning. Unsubscribe in one click.


