DEV Community

Cover image for Prevent flaky tests with Playwright
spO0q
spO0q

Posted on

Prevent flaky tests with Playwright

Flaky tests are technical debt.

Be careful with loops and manual delays in your e2e tests.

Loop .all()

You can leverage locator.all() to get an array of Locator objects for all elements matching the locator's selector.

It's helpful to check counts and other associated values.

Fantastic, but avoid misusage, such as naive for loops ❌:

const items = await page.locator('.myselector').all()
for (item in items) // or (for i=0 ... etc)
Enter fullscreen mode Exit fullscreen mode

It will likely introduce flakiness and improper handling of async locators.

✅ Playwright recommend using allInnerTexts(), allTextContents, count(), or filter() instead.

✅ If you absolutely need a for loop, do this:

for (const item of items) {
  await item.scrollIntoViewIfNeeded();
  await expect(item).toBeVisible();
}
Enter fullscreen mode Exit fullscreen mode

However, be aware that Playwright usually provides bulk actions on locators.

Timing Violations

Some tests can miss their targets, which is often due to dynamic DOM changes or unready pages.

Even if Playwright already adds some magic for you, it's usually better to make your tests as explicit as possible.

Instead of doing this ❌:

const anchor = await expect(page.locator('#anchor');
Enter fullscreen mode Exit fullscreen mode

You may do this ✅:

await expect(page.locator('#target')).toBeVisible();
await page.locator('#target').scrollIntoViewIfNeeded();
Enter fullscreen mode Exit fullscreen mode

Source: Playwright - Auto-waiting

Convenient configuration

Playwright can retry tests:

import { defineConfig } from '@playwright/test';
export default defineConfig({
  retries: 5,
});
Enter fullscreen mode Exit fullscreen mode

You get categorized results, such as:

Passed: Succeeds on first attempt
Flaky: Fails initially but passes on retry
Failed: Fails all 5 attempts

❌ Don't use retries to ignore flaky tests
✅ Flag it, fix it

Top comments (0)