1. Timing β async races and premature assertions
Symptom: Test fails ~5 % of runs. Failure is always on the assertion right after a click / navigation / network call. Re-running makes it green. Slower CI machines fail more often.
// Instrument: replay the SAME test 50 times in a loop on CI
npx playwright test --repeat-each=50 --grep "flaky-test-name"
// Read the output β flakiness is a FREQUENCY, not a boolean.
// "3/50 failed" is a smoking gun; "1/50" might be noise.
// Enable trace viewer on failures to see exact timing
npx playwright test --trace on-first-retry --reporter=html// Artificial CPU pressure exposes timing bugs deterministically
await page.context().setDefaultTimeout(1000); // tight timeout
await page.emulateNetworkConditions({ latency: 500 });
// Or run under stress: parallel heavy workload on the same machine// β Manual wait β the delay is a guess AND a tax on every run
await page.waitForTimeout(2000);
expect(await page.locator('.status').textContent()).toBe('Done');
// β
Auto-waiting assertion β polls until true or times out
await expect(page.locator('.status')).toHaveText('Done');
// For navigation, wait for the URL OR a visible element, not both
await page.waitForURL('/success');
await expect(page.getByRole('heading', { name: /thanks/i })).toBeVisible();Rule of thumb: If the fix is 'add a longer sleep', the bug is still there β you just pushed it further out. Replace every sleep with a condition-based wait, and the race disappears AND the test gets faster.