Run Playwright Python Tests: pytest and pytest-playwright CLI Options Explained

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.

Advertisement

๐Ÿ“– 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_name is another pytest-playwright fixture: a string such as "chromium". Asking for it is as simple as adding a parameter.
  • page.viewport_size returns a dictionary like {'width': 1280, 'height': 720}.
  • timeout=1000 makes 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
  • --headed opens visible browser windows. By default tests are headless.
  • --slowmo 1000 waits 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".
  • -s turns off pytest’s output capturing so that print() 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:

OptionValuesWhat you get
--screenshoton, off, only-on-failureA PNG taken at the end of each test
--full-page-screenshotflagMake those screenshots capture the full scrolling page (use with --screenshot)
--videoon, off, retain-on-failureA .webm recording of each test
--tracingon, off, retain-on-failureA trace.zip you can replay step by step in the Trace Viewer
--outputfolder pathWhere 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:

OptionMeaning
-v / -qMore / less output
-k "expression"Run tests whose names match, e.g. -k "login and not locked"
-m markerRun tests with a marker, e.g. -m smoke (Module 3)
-xStop after the first failure
--maxfail=3Stop after three failures
-sShow print() output
--lfRe-run only the tests that failed last time
--collect-onlyList the tests without running them
--durations=5Show 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-channel choose where tests run; --headed and --slowmo let you watch.
  • --device emulates phones and tablets; -s shows printed output.
  • --screenshot only-on-failure --video retain-on-failure --tracing retain-on-failure keeps evidence for failed tests in test-results.
  • --base-url lets 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

Leave a Comment