Why did it pass locally but fail in CI?
Fixed sleeps hide real timing problems. Wait on the right signal, then read the trace when it breaks.
Wait for the signal, not the clock
await page.waitForTimeout(2000) is a guess, and a slower server in CI proves it wrong. Wait on waitForURL or an assertion like expect(locator).toBeVisible(), which finish when the condition is true instead of when a timer expires.
Why is a fixed sleep a bad way to wait in a Playwright test, and what signal should I wait on instead of
waitForTimeout after clicking a submit button in a Next.js App Router form?
Read the trace when it breaks
When a test still fails in CI, run it with tracing on. The trace records every action, request, and screenshot, so Trace Viewer shows exactly what Playwright saw when it gave up.
How do I debug a Playwright test that passes locally but fails in CI, including how to enable tracing and open the Trace Viewer?
Wait on the right signal, not a fixed sleep. When a test still breaks in CI, the trace shows you exactly what Playwright saw.
Additional Resources
Explore these carefully curated resources to deepen your understanding and practice the concepts covered in this lesson.
Playwright Trace Viewer
DocumentationRecord and replay test runs step-by-step to see exactly what Playwright saw on failure.
https://playwright.dev/docs/trace-viewer
Playwright Auto-waiting
DocumentationHow Playwright checks actionability before clicking, typing, or asserting.
https://playwright.dev/docs/actionability

