Playwright for Browser Automation
Introduction to a simple library for automating tasks (and tests) on the web.
For anyone who’s built a web application, they know it can be tricky to test all its functionality, or even just the most important functionality, properly. Developers want a way to interact with their web app as if they were a user, testing the edge cases as well as the core functionality. Doing so can be hard; after all, you can’t reasonably have an army of humans testing all of the site’s functions every time new code gets pushed. This is why being able to programmatically interact with a web page is so important.
For automating these types of web-based tests, there is Playwright, an incredibly nimble coding library with extensive uses. Playwright is open sourced and available as a package in Java, JavaScript, TypeScript, and Python. Its main purpose is to allow users to write code that interacts with a web page. To do this, it includes operations like spinning up a web browser, locating CSS selectors on web pages, clicking, and filling forms. It is meant to be simple and compartmentalized, offering a quick and easy way to test even the simplest features of your app.
Specs
Playwright was built to be compatible with an ever changing internet landscape. It supports all major browser types, including Firefox, Chromium, and WebKit. It works locally on your machine or in your CI workflows, offering both headless or headed browser options (headless means you won’t see a window pop up with the browser, headed means you will). With synchronous and asynchronous implementations you can build simple, quick tests or integrate Playwright into async-capable frameworks like FastAPI.
Playwright also creates a new browser context for each test, allowing full test isolation. To test whether user changes persist across the same browsing session, you can use a persistent context, which gives you access to the same browser instance where the changes were originally made. This simulates scenarios where a user logs in but then leaves the page. Normally, websites cache that information in the browser’s cookies and as long as the user is using the same browser session, they can open that website anytime and still be logged in. With Playwright’s persistent context and browser session management, testing this type of functionality is possible.
Example
Let’s say you have a basic web application that employs some sort of sign in feature.
As part of your tests, you might want to ensure that users who enter the wrong password are denied entry. To test this, you would need to be able to act like the user on the frontend of the web application without actually being there yourself. So to test this, you could use Playwright.
First you would spin up a browser and navigate to the website you want to test:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
# Navigate to website
page.goto("https://example.com/login")
Then you can fill the username and password fields with whatever input you want. It’s important to note that to accurately interact with any web page you need to know the CSS selectors for the fields involved. In this case, the user name and password fields are input types and their CSS selectors are used by Playwright to identify the correct areas to fill on the page:
page.fill("input[name='username']", "my_username")
page.fill("input[name='password']", "wrong_password")
Finally, you can “click” on the submit button by using Playwright’s built in click method and the corresponding CSS selector of the button itself. It will look something like this:
page.click("button[type='submit']")
To test the result, we need to know which selectors we expect to see. In the case of a failed password, there might be an error message on the page that we can examine. If it’s present, we know the site has functioned properly and handled the incorrect password flow appropriately. Because Playwright was built for tests, it has some very nice built-in methods for asserting these kinds of situations. Let’s say our web page displays an error message like the following for wrong passwords.
We might test for that error message like this:
# Assert: error message shows up
error_box = page.locator(".error-message")
expect(error_box).to_be_visible()
expect(error_box).to_have_text("Invalid username or password.")
This is Playwright’s way of asserting that we expect there to be a “.error-message” selector on the page, and we expect that said selector to say “Invalid username or password.”
After running Playwright, always be sure to close the browser session:
browser.close()
Under the hood, Playwright has a lot more functionality than what’s been presented here. It’s a robust solution to interacting with web pages programmatically via headless or headed browsers and automated actions. Because of this, it could even be used for other things besides testing web page functionality. But that’s a discussion for a later time!