← Stackzilla Blog
Fixing Flaky Playwright Tests Without Adding More Sleep
Published November 8, 2026
· 3 min read
· Playwright, testing, frontend, CI/CD
Replace timing guesses with observable conditions, isolated data, and diagnostics that explain why a browser test failed.
A flaky browser test sometimes passes and sometimes fails without an intentional code change. The tempting fix is a longer delay. That may reduce failures on one machine while making the suite slower and leaving the underlying race intact.
Treat flakiness as evidence that the test depends on an uncontrolled condition. The condition might be rendering, network timing, shared data, animation, clock behavior, or interference from another test.
## Wait for behavior, not elapsed time
Playwright locators and assertions provide waiting behavior for many common interactions. Prefer asserting that a result is visible or that a button is enabled over sleeping for an arbitrary number of milliseconds.
Choose stable locators based on roles, accessible names, labels, or an intentional test identifier. A chain of positional CSS selectors can break when an unrelated element is inserted.
Be specific about completion. A successful click only proves that the action was performed; it does not prove that a background save finished. Assert a user-visible confirmation or another reliable outcome appropriate to the workflow.
## Give each test its own world
Tests that edit the same account or delete the same record will interfere when run concurrently. Create isolated fixtures and use unique resource identifiers. Clean up safely without assuming the test reached its final line.
Browser-context isolation helps with cookies and local storage, but it does not isolate a shared backend database. Design fixtures on both sides of the network.
Control unstable dependencies when they are not what the test is meant to validate. Mocking a third-party exchange rate can make a checkout layout test deterministic. A separate integration check should verify the real provider contract.
## Use failures to gather evidence
Capture traces, screenshots, and relevant logs on failure. Inspect whether the expected element never existed, existed under another name, was covered, or appeared after a failed request.
Retries can distinguish transient symptoms and preserve useful evidence, but a passing retry should not erase the failure from attention. Track tests that repeatedly require another attempt.
Test under the same concurrency and resource constraints used in CI. A suite that passes serially on a developer laptop can fail when several workers share a small runner.
Avoid fixing a brittle test by weakening its assertions until nothing meaningful remains. If a form submission is the behavior under test, checking that the page title exists is not an adequate replacement.
A trustworthy browser suite synchronizes with application behavior and controls its data. Longer sleeps merely postpone the next encounter with the same race.
## Further reading
- [Playwright: Best practices](https://playwright.dev/docs/best-practices)
- [Playwright: Trace viewer](https://playwright.dev/docs/trace-viewer)
Read the full article on Stackzilla →