Skip to main content

Testing (playwright)

How to test

Click X, then Y, then Z. Finally, assert that XYZ is visible on the page.

Finding elements

Locators

API methods on locators

page.get_by_role("checkbox", name="Subscribe").check()
page.get_by_role("button", name=re.compile("submit", re.IGNORECASE)).click()

page.get_by_label("Password").fill("secret")

page.get_by_placeholder("name@example.com").fill("playwright@microsoft.com")

expect(page.get_by_text("Welcome, John")).to_be_visible()
expect(page.get_by_text("Welcome, John", exact=True)).to_be_visible()

page.get_by_alt_text("playwright logo").click()

page.get_by_test_id("directions").click()

page.locator("css=button").click()
page.locator("xpath=//button").click()
page.locator("button").click()
page.locator("//button").click()
page.locator(
    "#tsf > div:nth-child(2) > div.A8SBwf > div.RNNXgb > div > div.a4bIc > input"
).click()
page.locator("x-details", has_text="Details").click()

expect(page.get_by_role("listitem")).to_have_count(3)
expect(page.get_by_role("listitem")).to_have_text(["apple", "banana", "orange"])

Taking actions

Initial page navigation

@pytest.mark.asyncio
async def test_index_url(self) -> None:
    await self.page.goto(f"{self.server_url}")

Mouse events

await locator.click()
await locator.hover()
await locator.focus()

Input fields

await my_input_element.fill("my text or numbers")
await my_input_element.type("enter text slowly over time")
await my_input_element.press("Enter")

Input file elements

await locator.setInputFiles()

Input checkbox

await locator.check()
await locator.uncheck()

Select option

await locator.selectOption()

Assertions

Playwright will automatically retry assertions as javascript code is being executed. Sometimes elements or text are not available until the page has fully loaded (sometimes it takes a few seconds).

Always use expect as it will retry multiple times until the expected situation appears or the timeout (default 5000ms) hits. Do not use assert directly as it doesn't have this retry mechanic.

await expect(my_input).to_have_value("test_value")
await expect(my_div_element).to_have_text("test_text")
await expect(table_tbody_rows).to_have_count(7)
await expect(dialog).to_be_visible()
await expect(dialog).not_to_be_visible()
await expect(locator).toContainClass()

Other

Sometimes you have to explicitly wait for events to happen, e.g. an alert dialog opening

await page.wait_for_timeout(1000)  # Time in ms

To accept a dialog alert pop up

alert_clicked = False

# Set up the dialog event handler
async def handle_dialog(dialog: Dialog) -> None:
    nonlocal alert_clicked
    # Verify the dialog type is an alert
    assert dialog.type == "alert", f"Expected alert, got {dialog.type}"
    # Verify the alert message
    assert dialog.message == "My alert message", (
        f"Expected message 'Expected alert message', got '{dialog.message}'"
    )
    # Accept the alert
    await dialog.accept()
    alert_clicked = True

# Handle alert pop-up
self.page.on("dialog", handle_dialog)
# Click something that triggers the dialog
await page.wait_for_timeout(1000)  # Time in ms
assert alert_clicked is True

Debugger support

Works out of the box