NashTech Blog

How to Avoid Flaky Tests in Playwright

Table of Contents

Flaky tests are those that pass sometimes and fail other times, even when nothing changes in the code. And in a tool like Playwright, which is designed for fast, powerful browser automation, those flakes can multiply if you’re not careful.

Let’s talk about why they happen and how to avoid them—without turning your test suite into a brittle nightmare.

Why Are Playwright Tests Flaky?

Some usual suspects:

              •            Timing issues – your test clicks a button before the page is fully ready.

              •            Animations or transitions – websites using much of animations and transitions that make the test be difficult to interact with or check the visibility of an element before an animation or transition completes.

              •            Race conditions: Tests proceed before the application is ready, leading to timing failures.

              •            State bleed – one test’s leftover state affects another.

              •            Poor selectors – you’re grabbing elements that aren’t stable across runs.

Now let’s talk prevention.

1. Use await expect(…) Smartly

Playwright has built-in waiting. Use it. Instead of this:

await page.click('text=Submit');
await expect(page.locator('text=Thank you')).toBeVisible();

Make sure the element is ready:

await expect(page.locator('text=Submit')).toBeVisible();
await page.click('text=Submit');
await expect(page.locator('text=Thank you')).toBeVisible();

Playwright waits automatically on most actions and assertions. Don’t fight it — embrace auto-waiting.

2. Be Thoughtful with waitForTimeout()

Avoid using this hard waits:

await page.waitForTimeout(1000); 

Use condition-based waits:

await page.waitForSelector('.done-loading'); // ✅ better

If you must wait for an animation or transition, prefer expect(…).toBeVisible() or toHaveClass, which wait for the state you care about.

3. Use Stable Selectors

Avoid CSS soup like this:

page.click('div:nth-child(4) > span > a');

Instead, favor:

              •            data-testid or data-test

              •            Text-based selectors (when stable)

              •            Role-based selectors for accessibility (e.g., getByRole(‘button’, { name: ‘Submit’ }))

Example:

await page.getByTestId('login-button').click();

Bonus: you can standardize this in your team’s component libraries for consistency.

4. Reset State Before Each Test

You don’t want test A leaking data into test B.

Use beforeEach() to:

              •            Clear cookies / local storage

              •            Navigate to a clean start page

              •            Re-login if needed

test.beforeEach(async ({ page }) => {
  await page.goto('https://yourapp.com/login');
  await page.evaluate(() => localStorage.clear());
});

In particular, if you can use the API in your tests, you should take advantage of it. For example, you can log in via the backend for beforeEachTest() instead of having to repeat the login steps multiple times.

5. Run Tests in Parallel, But Isolate State

Parallelism is awesome — until your tests step on each other.

Use Playwright’s test fixtures to set up separate contexts and avoid shared state.

test.use({ storageState: 'state.json' });

You can even isolate sessions for multi-user tests.

6. Monitor for Flakes with Retries

Retries are a tool, not a solution.

Use them sparingly, mainly to detect flakes — not to hide them.

npx playwright test --retries=1

If you notice frequent retries, investigate. Look for patterns: Is it always the same test? Always on CI?

Final Tips

              •            Run your tests headless and headed during dev (–headed).

              •            Slow down flaky tests with –slow-mo=100 to debug.

              •            Use page.screenshot() or trace viewer to debug stubborn failures.

              •            Set up CI to collect flake reports and track over time.

Conclusion

Playwright is powerful, but sometimes we meet some flaky tests.
So, to avoid flaky tests, some points are noted

              •            Wait for conditions, not time

              •            Use stable selectors

              •            Control test precondition tightly

              •            Using retries smartly

Hope that with some tips, you can enjoy time with Playwright!

 

Picture of Trang Truong Hoai

Trang Truong Hoai

Hi, I'm an automation test engineer. I’m excited about learning new technologies.

Leave a Comment

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

Suggested Article

Scroll to Top