Playwright Test Flaky Failures Fix: Complete Troubleshooting Guide

Introduction: What Are Playwright Flaky Test Failures?

A flaky test is a test that sometimes passes and sometimes fails even though the application code and test code have not intentionally changed.

For example:

Run 1 → PASS

Run 2 → PASS

Run 3 → FAIL

Run 4 → PASS

This is different from a genuine product failure.

A deterministic product bug normally fails consistently under the same conditions. A flaky Playwright test often depends on timing, shared state, network conditions, dynamic data, or the test environment.

Common examples include:

  • Element appears at different times.
  • API response is delayed.
  • Tests share the same user account.
  • Parallel workers modify the same data.
  • Authentication expires.
  • CI machines are slower than developer machines.
  • Animations or dynamic content change the page state.

This playwright test flaky failures fix tutorial explains how to identify and eliminate these causes instead of simply adding retries or increasing timeouts.


What Causes Flaky Tests in Playwright?

The most common causes are:

CauseExample
SynchronizationTest clicks before UI is ready
Weak locatorDynamic CSS class changes
Dynamic dataProduct order changes
Shared stateTwo tests modify the same account
AuthenticationSession expires
NetworkAPI response is slow
Parallel executionWorkers conflict
CI environmentDifferent resources
AnimationsElement moves during interaction
Test dependencyTest assumes another test ran first

The most effective Playwright flaky test fix is usually to make the test deterministic.


Common Symptoms of Playwright Test Flakiness

You may notice:

Test passes locally but fails in CI.

or:

Timeout waiting for locator

or:

Expected: “10”

Received: “9”

Other warning signs include:

That last symptom is particularly important.

If adding a fixed sleep makes the test pass, you probably have a synchronization problem—not a timeout problem.


Locator and Synchronization Problems

Consider this test:

await page.locator(‘.submit-button’).click();

The CSS class may be generated dynamically.

A more reliable locator is:

await page.getByRole(‘button’, {

 name: ‘Submit’

}).click();

Playwright’s locator actions automatically wait for required actionability conditions. This makes reliable locators an important part of preventing flaky tests.

Problem → Root Cause → Fix → Best Practice

Problem: Button sometimes cannot be clicked.

Root cause: The locator is fragile or the button is still changing state.

Fix:

const submit = page.getByRole(‘button’, {

 name: ‘Submit’

});

await expect(submit).toBeVisible();

await expect(submit).toBeEnabled();

await submit.click();

Best practice: Prefer semantic locators such as getByRole() and getByLabel().


Playwright Auto-Waiting and Reliable Assertions

Playwright provides automatic waiting for many browser actions.

Instead of:

await page.waitForTimeout(3000);

await page.getByRole(‘button’, {

 name: ‘Checkout’

}).click();

use:

const checkout = page.getByRole(‘button’, {

 name: ‘Checkout’

});

await expect(checkout).toBeVisible();

await checkout.click();

Assertions retry until their condition is satisfied or the assertion timeout is reached.

This is one of the most important principles in Playwright Test Flakiness prevention:

Wait for a meaningful application condition instead of waiting for an arbitrary amount of time.


Avoiding Unnecessary waitForTimeout() Usage

Problem

await page.getByRole(‘button’, {

 name: ‘Search’

}).click();

await page.waitForTimeout(5000);

await expect(

 page.getByText(‘Laptop’)

).toBeVisible();

Root Cause

The test doesn’t know what condition means “search completed.”

Fix

await page.getByRole(‘button’, {

 name: ‘Search’

}).click();

await expect(

 page.getByText(‘Laptop’)

).toBeVisible();

Best Practice

Avoid:

waitForTimeout()

for normal application synchronization.

Use:

  • Locator assertions
  • waitForURL()
  • Response/event synchronization when genuinely needed
  • API setup
  • Application-specific readiness indicators

Test Data and Playwright Test Isolation

Shared data is one of the biggest causes of intermittent failures.

Imagine two parallel tests:

Test A → Login as user@example.com

Test B → Login as user@example.com

Both modify the same shopping cart.

Test A expects:

Cart = 1 item

But Test B adds another item.

Now Test A sees:

Cart = 2 items

The failure is intermittent because execution order can change.

Better approach

Use independent users:

const users = {

 userA: ‘qa-user-a@example.com’,

 userB: ‘qa-user-b@example.com’

};

Or generate independent test data through an API.

Best Practice

Each test should control its own:

Playwright’s browser contexts provide strong browser-level isolation, but your application data must also be isolated.


Authentication and Session-Related Flakiness

Authentication failures often appear to be UI failures.

For example:

await page.goto(‘/dashboard’);

await expect(

 page.getByText(‘Welcome’)

).toBeVisible();

Sometimes the dashboard appears. Sometimes the application redirects to /login.

Root Cause

The authentication state is missing or expired.

Fix

Use a controlled authentication setup and reusable storageState where appropriate:

await page.context().storageState({

 path: ‘playwright/.auth/user.json’

});

Then configure the project:

use: {

 storageState: ‘playwright/.auth/user.json’

}

Best Practice

Don’t make every test perform UI login if your goal is to test an already-authenticated workflow. Use a dedicated authentication setup and isolate credentials.


Network and API-Related Flaky Failures

A UI test can fail because the backend is slow.

For example:

await page.getByRole(‘button’, {

 name: ‘Generate Report

}).click();

await expect(

 page.getByText(‘Report ready’)

).toBeVisible();

If the API sometimes takes 2 seconds and sometimes 15 seconds, the test can become intermittent.

Better approach

Wait for the actual UI condition:

await expect(

 page.getByText(‘Report ready’)

).toBeVisible({

 timeout: 20_000

});

If the API is a test dependency, you can also prepare test data through Playwright’s API capabilities instead of navigating through several UI screens.

Important

A larger timeout is appropriate only when the slower behavior is legitimate. If the API normally takes 2 seconds but occasionally takes 60 seconds, the test timeout is not the real problem—the backend performance may be.


Parallel Execution and Shared-State Problems

Parallel execution makes flaky tests easier to expose.

Run tests with multiple workers:

npx playwright test –workers=4

If tests fail only with multiple workers, investigate shared state.

Common conflicts include:

Same user

Same database record

Same shopping cart

Same output file

Same server resource

Same test account

Fix

Use independent test data.

You can also temporarily run:

npx playwright test –workers=1

If the failure disappears, that is a useful diagnostic signal—not necessarily the final solution.


Using Retries Correctly in Playwright

Playwright supports retries:

import { defineConfig } from ‘@playwright/test’;

export default defineConfig({

 retries: process.env.CI ? 2 : 0

});

Retries can be useful for:

  • Collecting evidence about intermittent failures
  • Preventing a single environmental glitch from failing a pipeline
  • Identifying tests that need investigation

But retries are not a real flaky test fix.

If this happens:

Attempt 1 → FAIL

Attempt 2 → PASS

the test should be investigated.

Do not hide the problem with:

retries: 10

A retry can make a pipeline green while the underlying test remains unreliable.


Debugging Flaky Tests with Trace Viewer, Screenshots, and Videos

Configure failure artifacts:

import { defineConfig } from ‘@playwright/test’;

export default defineConfig({

 use: {

   screenshot: ‘only-on-failure’,

   video: ‘retain-on-failure’,

   trace: ‘retain-on-failure’

 },

 reporter: [[‘html’]]

});

Run:

npx playwright test

Then:

npx playwright show-report

Trace Viewer helps you inspect:

  • Actions
  • Locator resolution
  • Screenshots
  • Timing
  • Network activity
  • Page state
  • Errors

You can also debug interactively:

await page.pause();

or:

npx playwright test –debug

For intermittent failures, traces are particularly useful because the failure may disappear when you rerun the test manually.


Fixing Flaky Tests in CI/CD

A common scenario is:

Developer machine → PASS

CI/CD → FAIL

Possible causes

  • Slower CPU
  • Limited memory
  • Network latency
  • Different browser version
  • Missing environment variables
  • Authentication problems
  • Parallel resource contention
  • Different test data

Practical approach

First collect:

Trace

Screenshot

Video

HTML report

Console errors

Test logs

Then compare the CI failure with a local run.

Avoid immediately increasing:

timeout: 120_000

Instead determine whether the CI environment is:

  • Missing dependencies
  • Running too many workers
  • Using incorrect credentials
  • Connecting to a slow environment
  • Sharing test data

For reproducibility, Docker can help standardize browser and OS-level dependencies.


Real-World Playwright Flaky Test Troubleshooting Examples

Example 1: Dynamic product list

Problem: Product test sometimes fails.

Root cause: The product API has not finished rendering.

Fix:

await expect(

 page.getByRole(‘listitem’).filter({

   hasText: ‘Laptop’

 })

).toBeVisible();

Best practice: Wait for the product condition rather than sleeping.


Example 2: Animation causes click failure

Problem: Button occasionally isn’t clickable.

Root cause: Animation moves the element.

Fix: Wait for the expected stable state or disable nonessential animations in the test environment.

Best practice: Don’t use force: true as the default solution.


Example 3: Shared shopping cart

Problem: Cart count changes unexpectedly.

Root cause: Parallel tests use the same account.

Fix: Give each test an independent account or reset the cart through controlled test setup.

Best practice: Isolate application state, not just browser pages.


Example 4: Local passes, CI fails

Problem: Test intermittently fails in GitHub Actions.

Root cause: CI has different performance or test-data conditions.

Fix: Inspect the trace and test environment, then reproduce using the same browser and configuration.

Best practice: Make CI failures observable rather than simply increasing retries.


Playwright Flaky Test Prevention Best Practices

Use this checklist:

Locators

  • Prefer getByRole().
  • Use getByLabel() for form fields.
  • Use stable test IDs where necessary.
  • Avoid dynamic CSS classes.

Synchronization

  • Trust Playwright auto-waiting.
  • Use web-first assertions.
  • Avoid arbitrary sleeps.
  • Wait for meaningful application state.

Test isolation

  • Use independent users.
  • Don’t share carts.
  • Don’t depend on test execution order.
  • Generate unique data where necessary.

Authentication

  • Use controlled authentication state.
  • Don’t rely on expired sessions.
  • Keep credentials secure.

Parallel execution

  • Identify shared resources.
  • Make tests worker-safe.
  • Run with one worker as a diagnostic technique.

CI/CD

  • Capture traces.
  • Capture screenshots and videos.
  • Standardize environments.
  • Investigate failures before adding retries.

Playwright Flaky Test Interview Questions

1. What is a flaky test?

A flaky test produces inconsistent results without an intentional change to the test or application.

2. What causes Playwright test flakiness?

Common causes include synchronization problems, weak locators, shared state, dynamic data, authentication issues, network delays, and CI resource differences.

3. Does increasing the timeout fix flaky tests?

Not necessarily. It can hide synchronization or application problems.

4. Why should waitForTimeout() be avoided?

It waits for a fixed duration rather than an actual application condition, making tests slower and potentially flaky.

5. How do you debug flaky Playwright tests?

Use:

Trace Viewer

Screenshots

Videos

HTML reports

Debug mode

Logs

6. Why do tests fail only in parallel?

They may share application data or other resources.

7. Are retries a flaky test solution?

Retries are a mitigation and diagnostic tool, not a substitute for fixing the underlying cause.


FAQs: Playwright Test Flaky Failures Fix

What causes Playwright flaky tests?

The most common causes are timing problems, dynamic content, unreliable locators, shared test data, authentication state, network delays, parallel execution, and CI environment differences.

How do I fix flaky tests in Playwright?

Make tests deterministic by using reliable locators, auto-waiting, web-first assertions, isolated test data, independent authentication, and controlled environments.

Why does my Playwright test pass locally but fail in CI?

CI may have different CPU, memory, network, browser, credentials, test data, or parallel-execution conditions.

Should I increase Playwright timeouts to fix flaky tests?

Only when the application operation is legitimately slow. Increasing every timeout can hide the real problem.

Does Playwright auto-wait?

Yes. Playwright automatically waits for many locator actions to become actionable, reducing the need for manual synchronization.

How do I identify a flaky test?

Run the test repeatedly and compare failures. If the same test alternates between passing and failing without relevant changes, investigate it as a potential flaky test.

Leave a Comment

Your email address will not be published. Required fields are marked *