Automate Web Testing with Playwright

Build a CI/CD pipeline that runs Playwright tests on every GitHub push.

Introduction

30 Second Summary

Every developer has pushed code that looked fine locally, only to discover it broke something on the live site. Automated testing catches those issues before they reach users.

In this project, you will build a complete end-to-end testing pipeline using Playwright and GitHub Actions. You'll write tests that drive a real browser, push them to GitHub, and watch a CI/CD pipeline run them automatically every time you change your code.

What You'll Build

You push code to GitHub, and within minutes a cloud runner spins up real browsers, navigates your target site, clicks links, checks content, and reports back with a green checkmark or a detailed trace file showing exactly where things went wrong.

By the end of this project, you'll have:

  • A test suite that navigates a real website, clicks links, and asserts page content is correct.
  • A GitHub Actions workflow that installs browsers and runs your tests headlessly on every code push.
  • Trace artifacts that capture a timeline of every test action so you can debug failures without re-running locally.
  • Secret Mission: Run your tests across multiple browsers (Chromium, Firefox, WebKit) in parallel.

Are there any prerequisites?

This project assumes basic Python knowledge and familiarity with pytest. You do not need prior experience with browser automation or CI/CD.

Before We Start

Before we dive in, let's lock in what you're about to build and why it matters.

Set Up Your Playwright Project

Before you can write any tests, you need a Python environment with the right testing tools installed. Playwright needs its own browser binaries to drive automated tests, so the setup has one extra step beyond a typical pip install.

In this step, you'll create a dedicated project folder, install the pytest-playwright package, and download the browser engines that Playwright controls during test runs.

In this step, get ready to:
  • Create a project folder with a Python virtual environment.
  • Install pytest-playwright and download browser binaries.
  • Create a requirements.txt for reproducibility.
Create a project folder and virtual environment

A virtual environment keeps your project's packages isolated from the rest of your system. This prevents version conflicts between different Python projects on your machine.

  • Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
  • Type Terminal (macOS) or PowerShell (Windows) and press Enter to open it.
  • Move to your Desktop by running this command:
cd ~/Desktop
  • Create your project folder and move into it by running these commands:
mkdir playwright-tests
cd playwright-tests
  • Create a virtual environment and activate it by running the commands for your operating system:

macOS

python3 -m venv venv
source venv/bin/activate

Windows

python -m venv venv
venv\Scripts\activate

You should see (venv) appear at the start of your terminal prompt. This confirms the virtual environment is active.

Don't see (venv) in your prompt?

Make sure you ran both commands (create and activate) in sequence. On Windows, if you see an error about execution policies, run Set-ExecutionPolicy -Scope CurrentUser RemoteSigned first, then retry the activate command.

On macOS, if python3 is not found, confirm Python is installed by checking your Applications folder or re-running the installer.

help me activate my Python virtual environment

Install pytest-playwright and download browsers

The pytest-playwright package bundles Playwright's browser automation with pytest's testing framework. It gives you ready-made fixtures like page that handle browser setup and teardown automatically.

  • Install the pytest-playwright package by running:
pip install pytest-playwright

You should see pip download and install several packages including playwright and pytest.

What does this install?

The pytest-playwright package pulls in Playwright (the browser automation engine) and pytest (the test runner). It also adds fixtures like page and browser that inject a fresh browser context into every test function automatically.

  • Download the browser binaries that Playwright drives during tests by running:
playwright install

This downloads Chromium, Firefox, and WebKit. The download is several hundred megabytes, so it may take a minute or two depending on your connection.

Why download entire browsers?

Playwright ships its own browser builds rather than relying on whatever is installed on your system. This guarantees your tests behave identically on your machine, a teammate's laptop, and a CI/CD server.

Seeing a network or permission error?

If the browser download fails, check your internet connection and retry. On corporate networks, a proxy may block the download. Try switching to a personal network or mobile hotspot.

help me download Playwright browser binaries

Create a requirements.txt and verify the setup

A requirements.txt file pins your dependencies so anyone (or any CI server) can recreate the same environment. You only need to pin the top-level package here.

  • Create requirements.txt with the pinned version by running the command for your operating system:

macOS

echo "pytest-playwright==0.9.0" > requirements.txt

Windows

Set-Content -Path requirements.txt -Value "pytest-playwright==0.9.0"
  • Confirm the file was created by running:
cat requirements.txt

You should see pytest-playwright==0.9.0 printed in the terminal.

Why pin only the top-level package?

Running pip freeze would list every transitive dependency (dozens of packages). Pinning just pytest-playwright==0.9.0 keeps the file readable and lets pip resolve compatible sub-dependencies on each install.

Before you run the next command, what do you think pytest will report when there are no test files in the project?

  • Verify that pytest-playwright is installed correctly by running:
pytest --co

You should see a line ending with no tests ran and no import errors. The --co flag tells pytest to collect tests without running them. Since you have no test files yet, zero tests collected is the correct result.

✔️ Awesome, I've got everything!

Great. Double check that requirements.txt is saved in your playwright-tests folder.

ⓧ I'd like to double check the full code

Your requirements.txt should contain exactly this:

pytest-playwright==0.9.0

Seeing an import error or command not found?

If you see a message about pytest not being recognized, your virtual environment may not be active. Check that (venv) appears in your terminal prompt and re-activate if needed.

If you see an import error mentioning playwright, re-run pip install pytest-playwright inside your activated environment.

help me fix pytest not being found in my virtual environment

Your testing environment is ready. Next up, you'll write your first Playwright test and watch it drive a real browser.

Write and Run Your First Test

Your Playwright environment is set up with browsers downloaded and ready to go. Now it's time to write your first automated test and watch it run against a real website.

Playwright tests are Python functions that receive a page object controlling a real browser. You write navigation commands and assertions, and Playwright handles launching the browser, waiting for elements, and reporting pass or fail.

In this step, get ready to:
  • Write tests that navigate a live website and verify page content.
  • Run your tests in verbose and headed mode to observe browser automation in action.
Create a test file following the pytest naming convention

pytest discovers test files automatically, but only if they follow a naming convention. Files must start with test_ and test functions inside them must also start with test_.

  • In PyCharm, right-click your project folder in the Project panel.
  • Select New then Python File.
  • Name the file test_homepage (PyCharm adds the .py extension automatically).
  • Add the following code to test_homepage.py:
import re
from playwright.sync_api import Page, expect


def test_homepage_has_playwright_in_title(page: Page):
    page.goto("https://playwright.dev/")
    expect(page).to_have_title(re.compile("Playwright"))

What does this code do?

  • import re brings in Python's regular expression module for flexible string matching.
  • from playwright.sync_api import Page, expect imports the Page type and Playwright's built-in assertion helper.
  • page: Page is a fixture provided automatically by pytest-playwright. Each test gets a fresh browser page with no setup code needed.
  • page.goto() navigates the browser to the given URL.
  • expect(page).to_have_title(re.compile("Playwright")) asserts the page title contains the word "Playwright".
  • Save test_homepage.py.
  • Run your first test by entering this command in the terminal:
pytest

You should see output ending with 1 passed in green.

Test not passing?

  • Make sure your file is named test_homepage.py with the test_ prefix. Pytest only discovers files that start with test_.
  • Check that your virtual environment is still activated. You should see (venv) at the start of your terminal prompt.
  • Verify your function name also starts with test_. Pytest skips functions without this prefix.
  • My first Playwright test is failing. How do I debug it?

Now let's add a second test that does something more interesting. This test clicks a link on the page and verifies the navigation worked correctly.

  • Add the following function below your first test in test_homepage.py, separated by a blank line:
def test_get_started_link(page: Page):
    page.goto("https://playwright.dev/")
    page.get_by_role("link", name="Get started").click()
    expect(page.get_by_role("heading", name="Installation")).to_be_visible()

What does this code do?

  • page.get_by_role("link", name="Get started") finds the link element by its accessible role and visible text. This is more resilient than CSS selectors because it matches how users actually see the page.
  • .click() simulates a real mouse click on that link, triggering navigation.
  • expect(page.get_by_role("heading", name="Installation")).to_be_visible() waits for the heading to appear on the new page and asserts it's visible. Playwright automatically waits for elements before asserting.
  • Save test_homepage.py.
  • Run your tests again to confirm both pass:
pytest

You should see 2 passed in the output.

Seeing 1 passed, 1 failed?

  • Make sure test_get_started_link is at the top level of the file, not nested inside another function.
  • Verify you have page: Page as the parameter. This tells pytest-playwright to inject the page fixture.
  • Check that the function name starts with test_. Pytest silently skips functions without this prefix.
  • My second Playwright test is failing but the first one passes. What's wrong?

✔️ Awesome, I've got everything!

Great. Double check you've saved test_homepage.py and move on to running your tests in verbose mode.

ⓧ I'd like to double check the full code

Here is the complete test_homepage.py file. Make sure yours matches exactly:

import re
from playwright.sync_api import Page, expect


def test_homepage_has_playwright_in_title(page: Page):
    page.goto("https://playwright.dev/")
    expect(page).to_have_title(re.compile("Playwright"))


def test_get_started_link(page: Page):
    page.goto("https://playwright.dev/")
    page.get_by_role("link", name="Get started").click()
    expect(page.get_by_role("heading", name="Installation")).to_be_visible()
Run your tests and observe the results

So far you've run plain pytest which shows a minimal pass/fail count. Verbose mode lists each test by name so you can see exactly what passed or failed.

Before you run this, how many individual test names do you expect to see listed in the output?

  • Run your tests in verbose mode:
pytest test_homepage.py -v

You should see both test_homepage_has_playwright_in_title PASSED and test_get_started_link PASSED listed individually in green.

Why use verbose mode?

Verbose mode names each test individually. When a test fails, you immediately see which specific test broke without needing to dig through logs. This becomes essential when your test suite grows beyond a handful of tests.

  • Now run your tests in headed mode to watch the browser in action:
pytest --headed

A Chromium browser window opens, navigates to the Playwright website, and closes. This happens once for each test.

Why does the browser open twice?

Each test gets its own isolated browser context. This means one test can never leave behind cookies or state that affects the next test. Isolation is what makes your tests reliable and order-independent.

Browser not opening?

  • Make sure you used --headed (with two dashes). A single dash causes a different error.
  • If the browser opens but closes too fast to see, that's expected. Playwright runs at full speed. The important thing is that your terminal still shows 2 passed.
  • The browser opens but my tests fail in headed mode. What's different?

Your first tests are passing and you've seen Playwright drive a real browser. Next up, you'll expand your test suite with navigation tests across multiple pages.

Expand Your Test Suite with Real Interactions

Your two tests in test_homepage.py prove Playwright can open a page and interact with elements. Both tests start and end on the same homepage.

A meaningful test suite covers navigation across different sections of a site. In this step, you'll create a second test file that clicks links to subpages and asserts both the URL and page content update correctly.

In this step, get ready to:
  • Create a navigation test file that verifies links and page URLs.
  • Run the full test suite across both files and confirm test isolation.
Create a navigation test file

Your existing test_get_started_link function uses page.get_by_role() to find a link by its accessible role and name, then clicks it. You'll apply this same pattern to test navigation to the documentation pages.

  • Create a new file called test_navigation.py in your project folder by running this command:
touch test_navigation.py
  • Confirm the file exists by running:
ls

You should see test_navigation.py alongside test_homepage.py in the output.

  • Open test_navigation.py in PyCharm and paste the following code:
import re
from playwright.sync_api import Page, expect


def test_python_docs_navigation(page: Page):
    # Navigate to the Playwright homepage
    page.goto("https://playwright.dev/")
    # Click the Docs link using its accessible role
    page.get_by_role("link", name="Docs").click()
    # Assert the URL updated to the docs intro page
    expect(page).to_have_url(re.compile(".*docs/intro"))


def test_page_has_get_started_heading(page: Page):
    # Navigate directly to the docs intro page
    page.goto("https://playwright.dev/docs/intro")
    # Assert the Installation heading is visible
    expect(page.get_by_role("heading", name="Installation")).to_be_visible()

What does this code do?

test_python_docs_navigation clicks the "Docs" link from the homepage and asserts the browser URL updates to match .*docs/intro. This verifies that clicking actually navigates to the expected page.

test_page_has_get_started_heading goes directly to the docs page by URL and checks that the "Installation" heading is visible. This tests the page content without relying on a click to get there.

  • Save test_navigation.py.
  • Run just the new file to confirm it works by running:
pytest test_navigation.py -v

You should see both test_python_docs_navigation and test_page_has_get_started_heading listed as PASSED.

Seeing a test failure?

  • Check that you spelled get_by_role("link", name="Docs") exactly. The name parameter is case-sensitive and must match the link text on the page.
  • Make sure you included import re at the top of the file. The re.compile() call needs it.
  • If you see a timeout error, your network may be slow. Run the test again. Playwright retries automatically but the default timeout may not be enough on very slow connections.

Help me debug my Playwright navigation test

✔️ Awesome, I've got everything!

Great. Double check you've saved test_navigation.py before moving on.

ⓧ I'd like to double check the full code

import re
from playwright.sync_api import Page, expect


def test_python_docs_navigation(page: Page):
    page.goto("https://playwright.dev/")
    page.get_by_role("link", name="Docs").click()
    expect(page).to_have_url(re.compile(".*docs/intro"))


def test_page_has_get_started_heading(page: Page):
    page.goto("https://playwright.dev/docs/intro")
    expect(page.get_by_role("heading", name="Installation")).to_be_visible()
Run the full test suite

You now have four tests split across two files. Playwright gives each test function its own fresh browser context, so tests never interfere with each other even when they navigate to different pages.

Why does each test get a fresh browser?

The page fixture from pytest-playwright creates an isolated browser context for every test function. One test's cookies, storage, and navigation state never leak into the next test.

Before you run the full suite, predict: how many tests do you expect to see in the output, and will they all pass?

  • Run pytest across all test files by running:
pytest -v

You should see four tests listed, all PASSED: two from test_homepage.py and two from test_navigation.py.

Not seeing four tests?

  • Both test files must start with test_ in their filename. Pytest only collects files matching this pattern.
  • Every test function must also start with test_. A function named check_navigation would be silently skipped.
  • Make sure you're running pytest -v from the same directory where both test files live.

Help me figure out why some tests are missing

Your test suite now covers real navigation and content assertions across multiple pages. Next up, you'll push this code to GitHub and discover what's missing when it comes to running these tests automatically.

Push to GitHub and See the Gap

Your test suite is passing. Four tests across two files prove that Playwright can navigate pages, click links, and assert content. The next question is: what happens when this code reaches a shared repository?

In this step, you'll push your project to GitHub and find out whether anything runs your tests automatically when code lands there.

In this step, get ready to:
  • Initialize a Git repository and create a .gitignore file.
  • Commit your project files and push them to GitHub.
  • Check the Actions tab to see what happened.
Initialize a Git repository and create a .gitignore

Before you can push code anywhere, you need a local Git repository to track your files.

  • Initialize a new Git repository in your project folder by running this command:
git init

You should see a message confirming that an empty Git repository was initialized.

Not every file in your project should be tracked by Git. Your virtual environment folder is large and machine-specific, and cache folders are generated automatically.

  • Create a new file called .gitignore in your project folder. In PyCharm, right-click the project root in the Project panel, select New, then File.
  • Name the file .gitignore and paste in the following content:
venv/
__pycache__/
.pytest_cache/
test-results/
*.pyc

What does this file do?

Each line tells Git to ignore a specific folder or file pattern. venv/ keeps your virtual environment out of the repository. __pycache__/ and *.pyc exclude Python's compiled bytecode files.

test-results/ excludes Playwright trace output (you'll see this folder later when tests run with tracing enabled). .pytest_cache/ excludes pytest's internal cache.

  • Save .gitignore.
  • Verify Git sees only the files you want tracked by running:
git status

You should see .gitignore, requirements.txt, test_homepage.py, and test_navigation.py listed as untracked files. The venv/ folder should NOT appear.

Seeing venv/ in the output?

Make sure you saved .gitignore in the project root (the same folder as your test files), not inside a subfolder. The filename must start with a dot.

help me fix my .gitignore so that venv/ is excluded from Git

✔️ Awesome, I've got everything!

Great. Make sure you've saved .gitignore and that git status only shows your four project files.

ⓧ I'd like to double check the full code

Your .gitignore should look exactly like this:

venv/
__pycache__/
.pytest_cache/
test-results/
*.pyc
Commit your code and push to GitHub

With Git tracking the right files, you need a remote repository on GitHub to push them to.

  • Open your browser and go to github.com.
  • In the upper-right corner, click the menu and select New repository.
  • Type playwright-tests in the Repository name field.
  • Select Public for the repository visibility.
  • Leave all other options unchecked (no README, no .gitignore, no license).
  • Click Create repository.

Why no README or .gitignore from GitHub?

You already have files locally. If GitHub generates its own files, pushing will fail because of conflicting histories. Starting with an empty remote avoids that conflict entirely.

GitHub now shows a page with instructions for pushing an existing repository. You'll use those commands next.

  • Stage and commit all your files by running these commands:
git add .
git commit -m "Add Playwright test suite"

You should see output listing the four files added and a confirmation of your commit.

  • Connect your local repository to GitHub and push by running these commands:
git branch -M main
git remote add origin [[REPO_URL="https://github.com/your-username/playwright-tests.git"]]
git push -u origin main

What do these commands do?

  • git branch -M main renames your current branch to main (ensuring it matches what GitHub expects).
  • git remote add origin links your local repository to the GitHub URL.
  • git push -u origin main uploads your commits to GitHub and sets main as the default branch to push to in the future.

You should see output ending with a line like Branch 'main' set up to track remote branch 'main' from 'origin'.

Push rejected or authentication error?

If Git asks for credentials, you may need to set up a personal access token or SSH key. GitHub no longer accepts passwords for git operations.

If the push is rejected because of existing remote content, make sure you did not initialize the repository with a README on GitHub.

help me fix a git push authentication or rejection error when pushing to GitHub

Check the Actions tab

Your code is on GitHub. Before you look at the result, think about this: you just pushed four test files and a requirements file. Do you think anything ran your tests automatically?

  • In your browser, navigate to your playwright-tests repository on GitHub.
  • Click the Actions tab at the top of the repository.

You'll see a message saying there are no workflows configured. No tests ran when you pushed your code. Anyone could push a change that breaks these tests, and nobody would know until someone manually ran pytest on their own machine.

Why is this a problem?

Locally passing tests only protect one developer on one machine. In a team environment, code gets merged from multiple people. Without automated testing on every push, broken code slips through silently.

This gap between "tests exist" and "tests run automatically" is exactly what a CI/CD pipeline solves. You'll close this gap in the next step using GitHub Actions.

You've identified the gap: tests pass locally, but nothing enforces them in the cloud. Next up, you'll close that gap by adding a GitHub Actions workflow that runs your tests on every push.

Add GitHub Actions CI/CD Pipeline

In the last step, you pushed your code to GitHub and discovered the gap: there is nothing running your tests automatically when code changes.

Now you will close that gap by adding a GitHub Actions workflow that runs your entire Playwright test suite on every push or pull request. When tests fail, trace files are saved as downloadable artifacts so you can debug without re-running locally.

In this step, get ready to:
  • Create a GitHub Actions workflow file that installs dependencies and runs your tests in the cloud.
  • Push the workflow and watch it execute automatically on GitHub.
  • Verify trace artifacts are uploaded for debugging.
Create the GitHub Actions workflow file

GitHub Actions workflows live in a special .github/workflows/ directory at the root of your repository. GitHub detects YAML files here and treats them as CI/CD pipeline definitions.

  • In PyCharm's Project tool window, right-click your project root folder.
  • Select New then Directory.
  • Type .github/workflows and press Enter. PyCharm creates the full nested directory structure for you.
  • Right-click the new workflows folder, select New then File.
  • Name the file playwright.yml and press Enter.
  • Paste the following workflow configuration into the empty file:
name: Playwright Tests

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    timeout-minutes: 60
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v6
    - name: Set up Python
      uses: actions/setup-python@v6
      with:
        python-version: '3.13'
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
    - name: Ensure browsers are installed
      run: python -m playwright install --with-deps
    - name: Run your tests
      run: pytest --tracing=retain-on-failure
    - uses: actions/upload-artifact@v5
      if: ${{ !cancelled() }}
      with:
        name: playwright-traces
        path: test-results/

What does this workflow do?

  • on: push / pull_request triggers the workflow automatically whenever you push code or open a pull request targeting the main branch.
  • runs-on: ubuntu-latest runs the job on a fresh Linux virtual machine provided free by GitHub.
  • actions/checkout@v6 clones your repository onto that machine so the code is available.
  • actions/setup-python@v6 installs Python 3.13 on the runner.
  • python -m playwright install --with-deps downloads the browser binaries plus OS-level dependencies the browsers need on Linux.
  • pytest --tracing=retain-on-failure runs your tests and only generates trace files when a test fails, keeping artifact size small.
  • actions/upload-artifact@v5 saves the test-results/ folder as a downloadable artifact, even if the job is cancelled.
  • Save playwright.yml.
  • Confirm the file appears in PyCharm's Project panel at .github/workflows/playwright.yml.

File not showing in the right place?

Make sure you created the directory as .github/workflows (with a leading dot). GitHub only detects workflow files in this exact path.

If you accidentally created github without the dot, right-click it and select Refactor then Rename to fix it.

Help me fix my workflow directory structure so GitHub Actions detects it

✔️ Awesome, I've got everything!

Great. Double check you have saved the file before moving on.

ⓧ I'd like to double check the full code

name: Playwright Tests

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    timeout-minutes: 60
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v6
    - name: Set up Python
      uses: actions/setup-python@v6
      with:
        python-version: '3.13'
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
    - name: Ensure browsers are installed
      run: python -m playwright install --with-deps
    - name: Run your tests
      run: pytest --tracing=retain-on-failure
    - uses: actions/upload-artifact@v5
      if: ${{ !cancelled() }}
      with:
        name: playwright-traces
        path: test-results/
Push the workflow and watch it run

The workflow only runs when GitHub detects it in your repository. Time to push it up.

  • Commit and push the new workflow file by running these commands in your terminal:
git add .github/workflows/playwright.yml
git commit -m "Add Playwright CI workflow"
git push
  • Open your GitHub repository in a browser.
  • Click the Actions tab.

Before you look at the result, predict: do you think your tests will pass on the first run in CI, or will something be different from your local environment?

  • Click on the Playwright Tests workflow run that appeared.
  • Watch the job steps execute. Each step you defined in the YAML appears as an expandable section in the log.

You should see a green checkmark next to the workflow run. All four of your tests pass in the CI environment.

Why does CI use Python 3.13 when I have 3.14 locally?

The CI runner uses Python 3.13 because that is the version specified in Playwright's official CI documentation. Both 3.13 and 3.14 meet the minimum requirement (Python 3.10+) for pytest-playwright, so your tests work in both.

Workflow not appearing or failing?

If you do not see a workflow run in the Actions tab, confirm your push succeeded by checking that .github/workflows/playwright.yml appears in your repository's file list on GitHub.

If the workflow fails, click on the failing step in the log. The most common issue is a typo in the YAML indentation. YAML uses spaces, not tabs.

Help me debug my failing Playwright Tests workflow

Verify trace artifacts are uploaded

The workflow is configured to upload trace files as artifacts whenever tests run. Traces capture a timeline of every browser action, which is essential for debugging failures that only happen in CI.

  • On the workflow run page, scroll down to the bottom of the summary.
  • Find the Artifacts section.
  • Confirm you see an artifact named playwright-traces listed.

What are trace artifacts for?

Trace files record every navigation, click, and network request your tests made. If a test fails only in CI (but passes locally), you can download the trace and open it in the Playwright Trace Viewer to see exactly what happened.

The --tracing=retain-on-failure flag means traces are only generated for failing tests. This keeps the artifact small when everything passes.

No artifact listed?

The artifact only appears after the workflow run completes. If the run is still in progress, wait for it to finish.

If the run completed but no artifact appears, check that the path: test-results/ line in your YAML matches exactly. A typo here means the upload step finds nothing to save.

Help me fix my missing playwright-traces artifact

Your tests now run automatically in the cloud every time you push code. No more manual testing. In the Secret Mission, you will extend this pipeline to run tests across multiple browsers in parallel.

Secret mission

Multi-Browser Testing

Your tests pass on Chromium, but what about Firefox and Safari? Real users browse with different engines. Extend your CI pipeline with a matrix strategy that runs your entire test suite across Chromium, Firefox, and WebKit in parallel.

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely on free resources. Your GitHub repository uses the free tier for Actions (2,000 minutes per month on public repos), and all other tools run locally.

Resources you used:

  • GitHub repository (includes the Actions workflow that runs on every push).
  • Local project folder (includes virtual environment, test files, and configuration).

Keep everything running

No action needed. Choose this if you're still actively building or want to keep your CI pipeline running.

  • Your repository stays on GitHub and tests run automatically on every push.
  • Public repositories have no ongoing cost for GitHub Actions within the free tier (2,000 minutes per month).
  • Playwright browser binaries remain installed on your local machine. They take up disk space but cost nothing.

Pause - I'll come back to this later

Disable the workflow to stop CI from consuming Actions minutes while keeping the repository and all your code intact.

  • Open your repository on GitHub.
  • Click the Actions tab.
  • In the left sidebar, click Playwright Tests to select the workflow.
  • Click the three-dot menu (kebab) near the top right and select Disable workflow.
  • Your tests will no longer run on push or pull request until you re-enable the workflow from the same menu.

Delete - I don't want to use this again

Remove all project resources completely. This cannot be undone.

Delete the GitHub repository:

  • Open your repository on GitHub.
  • Click Settings in the top navigation bar.
  • Scroll to the bottom of the General page and find the Danger Zone section.
  • Click Delete this repository and follow the confirmation prompts.

Delete the local project folder:

  • If your virtual environment is still active, deactivate it first by running:
deactivate
  • On macOS or Linux, remove the project folder by running:
cd ~/Desktop
rm -rf playwright-testing
  • On Windows (PowerShell), remove the project folder by running:
cd ~\Desktop
Remove-Item -Recurse -Force playwright-testing

Nice Work!

Nice Work!

You just built a complete automated testing pipeline from scratch. Your Playwright tests run in the cloud on every push, catching regressions before they reach production.

You've learned how to:

  • Build a Playwright test suite that navigates real websites, clicks links, and asserts page content is correct.
  • Create a GitHub Actions CI/CD pipeline that automatically runs your tests on every push and pull request.
  • Configure trace artifact uploads so you can debug test failures from CI without re-running locally.
  • Secret Mission: Extended your pipeline with a matrix strategy to run tests across Chromium, Firefox, and WebKit in parallel.

Ready to quiz yourself?