Manuals / Playwright with Python / Ch 14

Part 2 · Core InteractionsBeginner40 min read

8. Waits & Auto-waiting

Playwright with Python · 244 pages source format

Actionability checklist, explicit waits for spinner/load states, and why time.sleep is a lose-lose.

What you'll learn

  • Actionability conditions
  • wait_for_selector / wait_for_load_state
  • Never sleep “just in case”

The actionability checklist

Before performing most actions, Playwright runs through an actionability checklist on the target element:

1. Attached — is it in the DOM at all? 2. Visible — non-zero size, not display:none / visibility:hidden? 3. Stable — stopped moving/animating (checked across at least two animation frames)? 4. Enabled — not disabled? 5. Receives events — not covered by another element (e.g., a loading spinner overlay)?

Playwright re-checks this list repeatedly until all conditions pass or the timeout is hit. This is exactly why you rarely need manual waits.

Interactive study board
The actionability checklistDrag stickies · tap for tips
Study mapDrag stickies · tap for tipsKeep it shortdrag · tap →Name the waitdrag · tap →Scope locatorsdrag · tap →Trace when stuckdrag · tap →One browser firstdrag · tap →Isolate statedrag · tap →Assert the UIdrag · tap →Retry wiselydrag · tap →Seed datadrag · tap →Close the loopdrag · tap →Keep it shortdrag · tap →Name the waitdrag · tap →Scope locatorsdrag · tap →Trace when stuckdrag · tap →One browser firstdrag · tap →Isolate statedrag · tap →Pathwise hackdrag · tap →Page under testdrag · tap →Multi-browserdrag · tap →Automation pathdrag · tap →Tooling nodedrag · tap →
Clear?

Explicit waits when you need them

Use state-based waits for cases auto-waiting doesn’t cover directly — e.g., waiting for a spinner to hit “hidden” before checking results underneath.

wait_for_load_state covers load, domcontentloaded, and networkidle (no network for ~500ms). networkidle is handy after actions that trigger background calls with no specific element to target — but avoid it on pages with continuous polling (dashboards), since it’ll never go idle and will time out.

State waits
page.wait_for_selector(".spinner", state="hidden")
page.wait_for_selector(".results", state="visible")
page.wait_for_load_state("domcontentloaded")
Interactive study board
Explicit waits when you need themDrag stickies · tap for tips
Study mapDrag stickies · tap for tipsKeep it shortdrag · tap →Name the waitdrag · tap →Scope locatorsdrag · tap →Trace when stuckdrag · tap →One browser firstdrag · tap →Isolate statedrag · tap →Assert the UIdrag · tap →Retry wiselydrag · tap →Seed datadrag · tap →Close the loopdrag · tap →Keep it shortdrag · tap →Name the waitdrag · tap →Scope locatorsdrag · tap →Trace when stuckdrag · tap →One browser firstdrag · tap →Isolate statedrag · tap →Pathwise hackdrag · tap →Page under testdrag · tap →Multi-browserdrag · tap →Automation pathdrag · tap →Tooling nodedrag · tap →
Clear?

Avoid time.sleep

A hard sleep() is a lose-lose: too short and the test is flaky; too long and every run wastes time even when the app responded instantly. Auto-waiting solves both problems simultaneously. The only legitimate reasons to add explicit waits are the state-based cases above — never as a blanket “just in case” habit.

Prefer auto-wait
# Avoid:
# time.sleep(3)
# page.click(".submit-button")

# Prefer:
page.get_by_role("button", name="Submit").click()  # auto-waits already

Do this now

grep your practice repo for sleep( and delete or replace each hit.

Interactive study board
Avoid time.sleepDrag stickies · tap for tips
Study mapDrag stickies · tap for tipsKeep it shortdrag · tap →Name the waitdrag · tap →Scope locatorsdrag · tap →Trace when stuckdrag · tap →One browser firstdrag · tap →Isolate statedrag · tap →Assert the UIdrag · tap →Retry wiselydrag · tap →Seed datadrag · tap →Close the loopdrag · tap →Keep it shortdrag · tap →Name the waitdrag · tap →Scope locatorsdrag · tap →Trace when stuckdrag · tap →One browser firstdrag · tap →Isolate statedrag · tap →Pathwise hackdrag · tap →Page under testdrag · tap →Multi-browserdrag · tap →Automation pathdrag · tap →Tooling nodedrag · tap →
Clear?

Checklist