You can change how your whole test suite runs without touching a single line of test code. pytest-playwright adds options to the pytest command for picking browsers, watching tests run, emulating phones and capturing screenshots, videos and traces when something fails. In this lesson you will try each option on a small test file and see exactly what it produces.
๐ What You’ll Learn: running tests in Chromium, Firefox and WebKit, using installed Chrome or Edge, headed mode and slow motion, device emulation, capturing screenshots, videos and traces only on failure, the test-results folder, –base-url, and the core pytest flags for selecting and reporting tests.
๐งช The Test File for This Lesson
Create tests/test_cli.py. It has one passing test, one test that fails on purpose (so you can see failure artifacts), one test that prints the viewport size, and one test that uses a relative URL:
๐ tests/test_cli.py
from playwright.sync_api import Page, expect
def test_practice_title(page: Page):
page.goto("https://sqatools.in/automation-practice-page/")
expect(page).to_have_title("Automation Practice Page - SQA Tools")
def test_broken_heading(page: Page):
# Fails on purpose: the real heading text is "Text Fields"
page.goto("https://sqatools.in/automation-practice-page/")
heading = page.get_by_role("heading", name="Text Fields")
expect(heading).to_have_text("Text Boxes", timeout=1000)
def test_viewport(page: Page, browser_name: str):
size = page.viewport_size
is_mobile = "Mobile" in page.evaluate("navigator.userAgent")
print(f"\n{browser_name}: viewport {size['width']}x{size['height']}, mobile user agent: {is_mobile}")
def test_relative_url(page: Page):
# Works only when a base URL is set (see --base-url below)
page.goto("/automation-practice-page/")
expect(page).to_have_url("https://sqatools.in/automation-practice-page/")
browser_nameis another pytest-playwright fixture: a string such as"chromium". Asking for it is as simple as adding a parameter.page.viewport_sizereturns a dictionary like{'width': 1280, 'height': 720}.timeout=1000makes the failing assertion give up after 1 second instead of the default 5, so the demo is quick.
๐ Choose the Browser: –browser and –browser-channel
Without options, tests run in Chromium. Pick another engine with --browser:
โจ๏ธ Terminal
pytest --browser firefox
pytest --browser webkit
Repeat the option to run every test in several browsers in one go:
โจ๏ธ Terminal
pytest --browser chromium --browser firefox --browser webkit -k title
๐ฅ๏ธ Output
... [100%]
3 passed, 9 deselected in 9.37s
The single test_practice_title test ran three times, once per browser (that is what the three dots mean). With -v you would see the suffixes [chromium], [firefox] and [webkit].
To run Google Chrome or Microsoft Edge as installed on your machine (instead of Playwright’s own Chromium build), use a channel:
โจ๏ธ Terminal
pytest --browser-channel chrome
pytest --browser-channel msedge
๐ก Tip: Testing in branded Chrome or Edge is useful when you must match exactly what your users run. For everyday runs, Playwright’s bundled Chromium is faster to set up and identical across machines.
๐ Watch Tests Run: –headed and –slowmo
โจ๏ธ Terminal
pytest --headed
pytest --headed --slowmo 1000
--headedopens visible browser windows. By default tests are headless.--slowmo 1000waits 1000 milliseconds after every Playwright action, so you can follow each step. Never leave it on in CI: it makes every test much slower.
๐ฑ Emulate a Device: –device
--device applies one of Playwright’s built-in device profiles (screen size, user agent, touch support, pixel ratio) to every test:
โจ๏ธ Terminal
pytest -s --device "iPhone 13" -k viewport
๐ฅ๏ธ Output
chromium: viewport 390x664, mobile user agent: True
1 passed, 3 deselected in 0.49s
Without the option, the same test prints the default desktop viewport:
โจ๏ธ Terminal
pytest -s -k viewport
๐ฅ๏ธ Output
chromium: viewport 1280x720, mobile user agent: False
- Device names must match Playwright’s list exactly, including capitals and spaces, so put them in quotes. Popular ones include
"iPhone 13","Pixel 7"and"iPad Pro 11". - The browser engine is still chosen by
--browser(Chromium by default). For the most realistic iPhone emulation, combine--browser webkit --device "iPhone 13". -sturns off pytest’s output capturing so thatprint()output appears in the terminal.
You will go deeper in Mobile Device Emulation.
๐ธ Capture Evidence: –screenshot, –video and –tracing
When a test fails in CI, you need evidence. These options record it automatically:
| Option | Values | What you get |
|---|---|---|
--screenshot | on, off, only-on-failure | A PNG taken at the end of each test |
--full-page-screenshot | flag | Make those screenshots capture the full scrolling page (use with --screenshot) |
--video | on, off, retain-on-failure | A .webm recording of each test |
--tracing | on, off, retain-on-failure | A trace.zip you can replay step by step in the Trace Viewer |
--output | folder path | Where all of these go (default test-results) |
The most useful combination keeps evidence only for failed tests:
โจ๏ธ Terminal
pytest -k "not relative" --screenshot only-on-failure --video retain-on-failure --tracing retain-on-failure
๐ฅ๏ธ Output
FAILED tests/test_cli.py::test_broken_heading[chromium] - AssertionError: Loc...
1 failed, 2 passed, 1 deselected in 6.12s
(-k "not relative" skips the relative-URL test for now, because it needs the --base-url option shown later in this lesson.)
The test-results folder now holds one sub-folder, for the failed test only:
๐ฅ๏ธ Output
test-results/
โโโ tests-test-cli-py-test-broken-heading-chromium/
โโโ test-failed-1.png
โโโ trace.zip
โโโ video.webm
- The folder name is built from the file name, the test name and the browser, so failures in different browsers never overwrite each other.
- Passing tests left nothing behind, which keeps CI artifacts small.
- Open the trace with
playwright show-trace test-results/tests-test-cli-py-test-broken-heading-chromium/trace.zip. You will learn the Trace Viewer in Module 11.
๐ Note: pytest-playwright clears the output folder at the start of each run, so old artifacts never get mixed with new ones.
๐ Shorter URLs: –base-url
Typing the full URL in every test is repetitive, and it makes it hard to run the same tests against a staging server. Set a base URL once and use relative paths:
โจ๏ธ Terminal
pytest --base-url https://sqatools.in -k relative
๐ฅ๏ธ Output
. [100%]
1 passed, 3 deselected in 1.29s
page.goto("/automation-practice-page/") was resolved against the base URL. In pytest-playwright 0.10 the --base-url option works out of the box. You can also set it with the PYTEST_BASE_URL environment variable or a base_url entry in pytest.ini, which you will do in the next lesson.
๐ฏ Core pytest Options You Will Use Every Day
These come from pytest itself and combine freely with the Playwright options:
| Option | Meaning |
|---|---|
-v / -q | More / less output |
-k "expression" | Run tests whose names match, e.g. -k "login and not locked" |
-m marker | Run tests with a marker, e.g. -m smoke (Module 3) |
-x | Stop after the first failure |
--maxfail=3 | Stop after three failures |
-s | Show print() output |
--lf | Re-run only the tests that failed last time |
--collect-only | List the tests without running them |
--durations=5 | Show the five slowest tests |
For example, --collect-only -q lists every test with its browser suffix:
โจ๏ธ Terminal
pytest --collect-only -q
๐ฅ๏ธ Output
tests/test_cli.py::test_practice_title[chromium]
tests/test_cli.py::test_broken_heading[chromium]
tests/test_cli.py::test_viewport[chromium]
tests/test_cli.py::test_relative_url[chromium]
4 tests collected in 0.00s
๐งพ Quick Reference
โจ๏ธ Terminal
# All browsers, verbose
pytest --browser chromium --browser firefox --browser webkit -v
# Debug one test visually
pytest tests/test_login.py::test_valid_login_shows_products --headed --slowmo 500
# CI-style run with evidence on failure
pytest --tracing retain-on-failure --screenshot only-on-failure --video retain-on-failure
# Same tests against another environment
pytest --base-url https://staging.example.com
To see every option on your machine, run pytest --help and look for the Playwright section.
โ Frequently Asked Questions
๐ค How do I avoid typing the same options every time?
Put them in the addopts setting of pytest.ini or pyproject.toml. That is the first thing you will do in the next lesson.
๐ค Can I run tests in parallel?
Yes, with the pytest-xdist plugin (pytest -n auto). It is covered in Parallel Execution with pytest-xdist.
๐ค Do these options affect browsers I create myself?
No. They configure the browser, context and page fixtures from pytest-playwright. A browser you launch yourself with sync_playwright() inside a test is not affected.
๐ค Is there a –retries option?
Not in pytest-playwright. Retries come from the pytest-rerunfailures plugin (pytest --reruns 2), covered in Module 6.
๐ Summary
--browser(repeatable) and--browser-channelchoose where tests run;--headedand--slowmolet you watch.--deviceemulates phones and tablets;-sshows printed output.--screenshot only-on-failure --video retain-on-failure --tracing retain-on-failurekeeps evidence for failed tests intest-results.--base-urllets tests use relative URLs; pytest’s own flags (-k,-x,-v,--lf) select and report tests.
Next, you will move these options into configuration files and learn how conftest.py customises the browser and context for the whole suite.
๐ฌ Watch the Playwright tutorial series on YouTube!
Subscribe to SqaToolsByDY • Practice on the SQA Tools Automation Practice Page