🎭️ Playwright
Playwright is an end-to-end testing library. It allows you to write tests that interact with your web application in a browser to ensure that it works as expected.
You can use JavaScript, Python, Java or C#. I've used it with Python so the examples are in Python.
Navigation
# go to a page and wait for everything to load
page.goto("https://example.com")
# do something and assume a certain URL change
page.get_by_text("Let me in!").click()
page.wait_for_url("**/login")
# but, in general, Playwright is smart enough to wait for the element to load
page.get_by_text("Let me in!").click()
expect(page.get_by_role("heading", name="Welcome!")).to_be_visible()
page.get_by_label("Username").fill("bob")
Do not use with page.expect_navigation()
as it's not reliable. Use page.wait_for_url
.
page.wait_for_url("**/my-account")
Finding Elements
You use get_by_*
and locate
functions to find elements on the page.
- For form fields, use
label
>placeholder
>testid
- For images, use
alt_text
>testid
- For everything else, use
role+name
>text
>testid
.
page.get_by_label("Birthday")
page.get_by_placeholder("Birthday")
page.get_by_testid("birthday")
# etc.
Avoid locating elements with CSS or XPath. They are the least resilient and can break on unrelated DOM changes.
You use filter
to narrow down the elements you're looking for.
page.get_by_role("listitem").filter(
has_text="Product 2"
).get_by_role(
"button", name="Add to cart"
).click()
You can also filter
with "one that has
a child like this".
page.get_by_role("listitem").filter(
has=page.get_by_role("heading", name="Product 2")
).get_by_role(
"button",
name="Add to cart"
).click()
Performing Actions
page.get_by_label("Birthday").fill("2020-02-02")
page.get_by_label('I agree').check()
expect(page.get_by_label('Subscribe to newsletter')).to_be_checked()
page.get_by_label('Choose a color').select_option('blue')
# the name here is "the accessible name" of the element
# https://w3c.github.io/accname/#dfn-accessible-name
page.get_by_role("button", name="Submit", exact=True).click()
page.get_by_role("button", name=re.compile("submit", re.IGNORECASE)).click()
Checking Assumptions
expect(page.get_by_role("heading", name="Welcome!")).to_be_visible()
expect(page.get_by_role("button", name="Submit")).not_to_be_disabled()
expect(page.locator("list > .component")).to_have_count(3)
expect(page.locator("ul > li")).to_have_text(["Text 1", "Text 2", "Text 3"])
Browser Context
Each test runs in a separate browser context. A kin to an incognito tab in a browser.
You can emulate a lot with the context like setting viewport, timezone, geolocation, permissions, etc.
When you notice that registration and login per test becomes slow, use context.storage_state
. It snapshots cookies and local storage so you can restore them later.
# Save storage state into the file.
storage = context.storage_state(path="playwright/.auth/state.json")
...
# Create a new context with the saved storage state.
context = browser.new_context(storage_state="playwright/.auth/state.json")
You'd normally use
playwright/.auth
directory to save this.