Module 6 ยท Python for SDETs
UI automation
with Playwright
Drive a real browser โ locate, act, and assert like a user would
page fixture
get_by_* locators
auto-waiting
web-first expect
One fixture: page
# pip install pytest-playwright
import re
from playwright.sync_api import expect
def test_products_page(page):
page.goto("http://localhost:3000/products")
expect(page).to_have_title(re.compile("TestMarket Lab"))
๐pytest-playwright hands every test a fresh page โ a clean browser context, no setup or teardown to write.
๐ฌHeadless by default; add --headed to watch it drive, --slowmo to slow it down while debugging.
Find elements the way a user sees them
Locators: get_by_*
test id
get_by_test_id()
the data-testid hooks the app ships โ most robust
role
get_by_role()
buttons, links, headings โ also an a11y check
label
get_by_label()
form fields by their visible label
text
get_by_text()
visible text โ handy, but the most fragile
๐ฏLocate by intent: get_by_test_id is the most robust (a hook that survives restyling); get_by_role / get_by_label double as accessibility checks; get_by_text is the most fragile.
No manual sleeps
Actions wait for the element โ automatically
locate the element
โ
Playwright waits: visible & enabled
โ
then .click() / .fill()
page.get_by_label("Email").fill("customer@test.io")
page.get_by_test_id("login-submit").click()
โฑ๏ธEach action auto-waits up to the timeout for the element to be actionable โ so time.sleep() is a smell, not a fix.
Assertions that retry
from playwright.sync_api import expect
# waits until it's visible, or fails
expect(
page.get_by_test_id("nav-logout")
).to_be_visible()
โ
expect(locator) auto-retries until the condition holds or the timeout hits โ no flake from asserting a millisecond too early.
๐Different from pytest's plain assert: a web-first expect polls the live page instead of checking once.
๐ญ
Drive the
real browser
Locate by role, act with auto-waiting, and assert with web-first expect
๐งช
Practice
Log in through the UI and expect the logout button visible
๐ฏ
Locators
Reach for get_by_role / get_by_label before CSS or XPath
โก๏ธ
Module 7
Page Object Model โ hide selectors behind readable page classes