TesterArmyTesterArmy
  • Pricing
Sign inGet started
HomeBlogWhy Your Playwright Tests Are Flaky and How to Fix Them

Why Your Playwright Tests Are Flaky and How to Fix Them

Playwright removed the classic flaky-test causes, so flaky suites have specific ones: app-settling gaps, shared state, environment drift. Find yours fast.

TesterArmy
TesterArmy
August 22, 20265 min read

Playwright's auto-waiting was supposed to end flaky tests, and it genuinely ended one generation of them: the Selenium-era race between the script and the page. So when a Playwright suite is flaky anyway, the causes are more specific, and the generic advice ("add retries, increase timeouts") treats the symptom while the suite quietly loses everyone's trust. Here are the five causes that account for almost every flaky Playwright test we see, roughly in order of frequency.

1. Asserting before the app settles, in ways auto-wait cannot see

Auto-waiting covers actionability: Playwright waits for an element to be visible, stable, and enabled before clicking it. What it cannot know is your application's semantics. A dashboard that renders instantly with skeleton data, a list that paints and then re-sorts, a form that enables its button before the API call that validates it: in each case the element is technically actionable while the app is not actually ready. The fix is asserting on outcomes users can see (await expect(row).toContainText('Paid')) rather than on presence, and letting web-first assertions poll until reality matches. Tests that assert on intermediate states inherit the timing of those states.

2. Shared state between tests

The test passes alone and fails in the suite, or fails only on CI where parallelism is higher: that is state leaking between tests. Common leaks are a shared test user whose data another worker just mutated, leftover records from a previous run, and ordering assumptions ("the newest item is mine"). The fix is isolation: unique users or namespaced data per worker, setup that creates what the test needs, and assertions that select their own records rather than trusting position. This class of flake gets misdiagnosed as timing because retries sometimes pass, but no wait fixes a collision.

3. The unmocked outside world

Third-party scripts, payment sandboxes, email delivery, rate-limited APIs: every external dependency donates its reliability to your test. Decide per dependency: mock it (fast, but you stop testing the integration), stub it at the network layer, or accept the dependency and quarantine those tests so their failures read differently from product regressions. What kills trust is mixing them silently, so a Stripe sandbox hiccup reads identically to a broken checkout.

4. The test environment is not the app's environment

Animations still running, viewport differences between local and CI, seeded clocks, timezone-sensitive rendering, resource-starved CI runners where everything takes four times longer. These produce the maddening "only on CI" flakes. Disable animations for test runs, pin viewport and locale, and treat any test that only fails on CI as an environment bug to reproduce rather than a retry candidate.

5. Retries as a way of life

Retries are a diagnostic tool that got promoted into a lifestyle. A retry that turns red into green tells you the test measures something unstable; leaving retries on globally means your suite reports "eventually passed" as "passed" and the underlying instability compounds. Use retries to gather traces on failure, then turn them off per test as you fix causes. A suite trusted at zero retries is the actual goal.

Diagnose before fixing

The trace viewer is the fastest route from symptom to cause: run with tracing on retries, open the trace for a flaky run, and look at what the page showed at the failing step. Flakes from cause 1 show the app mid-transition; cause 2 shows wrong data; cause 3 shows a third-party spinner; cause 4 shows the CI-only rendering difference. Ten minutes with a trace beats an afternoon of guessing.

The part nobody enjoys saying

Every fix above is real, and every one is ongoing work owned by your team: the isolation discipline, the mock boundaries, the environment pinning. That maintenance economy is a choice, and there is a different one. TesterArmy's agent performs flows by looking at the rendered page the way a user does, on every run, so the timing and selector classes of flakiness stop existing structurally, and shared-state discipline shrinks to describing flows that use their own data. Failures come back with a recording and a step trace on the pull request, which makes "is this the app or the test" a question you can answer in one viewing. The wider picture, including what flakiness costs and where it comes from beyond one framework, is in our pillar: Flaky Tests: What They Are, Why They Happen, and What They Cost.

FAQ

Why do my Playwright tests pass locally and fail in CI? Usually cause 4 (environment differences) or cause 2 amplified by CI parallelism. Reproduce with the CI viewport, locale, and worker count locally before touching timeouts.

Should I use retries in Playwright? As a trace-gathering tool during diagnosis, yes. As a permanent setting that hides instability, no.

Do flaky tests mean Playwright is the wrong tool? No; flakiness has causes, and Playwright gives you good instruments to find them. It does mean someone owns that work forever, which is a model question rather than a tooling one: TesterArmy vs Playwright lays out both sides, and the best Playwright alternatives sorts the wider field by what each option actually removes.

ON THIS PAGE

  • 1. Asserting before the app settles, in ways auto-wait cannot see
  • 2. Shared state between tests
  • 3. The unmocked outside world
  • 4. The test environment is not the app's environment
  • 5. Retries as a way of life
  • Diagnose before fixing
  • The part nobody enjoys saying
  • FAQ

SHARE THIS ARTICLE

  • X

Check other TesterArmy insights

August 20, 2026

Introducing the Issues Tab: One Row Per Bug, No Matter How Many Runs Found It

Agent-found bugs now land in one deduplicated list instead of scattered run reports. Every issue carries expected vs actual, repro steps, and a replay of the exact moment it broke - and leaves the list as a Linear ticket, a prompt for your coding agent, or resolved.

Read article
August 18, 2026

We Benchmarked 10 Vision Models on Clicking What They See

All ten models answered every visual understanding question correctly. Grounding the click is where the field splits, and where GPT-5.6 Luna won on accuracy, precision, and cost.

Read article
July 22, 2026

Introducing Scout: API Testing Built for AI Agents

We built Scout, an open source CLI that gives coding agents a safe harness for testing APIs. Point it at an OpenAPI spec and it sweeps, fuzzes, and records findings - with guardrails on by default. In this walkthrough it finds three real bugs in the Swagger Petstore.

Read article
TesterArmyTesterArmy

AI-powered QA testing for modern teams. Ship faster with confidence.

SOC 2 Type 2 badge
GDPR badge

© 2026 TesterArmy, Inc.

Solutions
  • AI app testingAI app testing
  • EcommerceEcommerce
  • Expo app testingExpo app testing
  • MobileMobile
  • Production monitoringProduction monitoring
  • React Native testingReact Native testing
  • WebWeb
  • WordPress testingWordPress testing
Quick links
  • HomeHome
  • DemoDemo
  • FeaturesFeatures
  • How it worksHow it works
  • FAQFAQ
  • PricingPricing
  • Get a demoGet a demo
  • About usAbout us
  • Contact usContact us
Resources
  • DocumentationDocumentation
  • BlogBlog
  • API referenceAPI reference
  • Getting startedGetting started
Legal
  • Privacy policyPrivacy policy
  • Terms of serviceTerms of service
TesterArmyTesterArmy
  • Pricing
Sign inGet started
Quick links
  • HomeHome
  • DemoDemo
  • FeaturesFeatures
  • How it worksHow it works
  • FAQFAQ
  • PricingPricing
  • Get a demoGet a demo
  • About usAbout us
  • Contact usContact us