CI/CD & DEVOPSINTERMEDIATE

GitHub Actions for Playwright: Build Your First Automated CI Pipeline

Set up a production-ready GitHub Actions CI pipeline for Playwright: workflow YAML, triggers, Node.js setup, browser install, HTML reports, artifacts, secrets, and best practices.

iff Solution Academy July 23, 2026 22 min read Updated July 23, 2026
Playwright GitHub Actions CI/CD DevOps YAML Automation

Introduction

In the previous tutorials, we learned why CI/CD matters for Playwright automation and how Docker creates a consistent test execution environment. Now it is time to connect our Playwright framework to a real Continuous Integration pipeline.

In this tutorial, we will use GitHub Actions to automatically execute Playwright tests whenever code is pushed to a GitHub repository or a pull request is created.

Instead of manually opening a terminal and running:

bash
npx playwright test

GitHub Actions will perform the entire process for us.

The pipeline will:

  • Download the automation project
  • Install Node.js
  • Install project dependencies
  • Install Playwright browsers
  • Execute the test suite
  • Generate an HTML report
  • Upload the report as an artifact
  • Preserve debugging files when tests fail

By the end of this tutorial, you will have a working Playwright CI pipeline similar to the pipelines used by professional software development teams.

What Is GitHub Actions?

GitHub Actions is GitHub's built-in automation platform. It allows teams to create workflows that automatically build, test, package, and deploy applications.

A GitHub Actions workflow is defined using a YAML file stored inside the repository.

According to GitHub's official documentation, a workflow is a configurable automated process made up of one or more jobs. Each workflow is defined in a YAML configuration file.

A workflow can start when a specific event occurs, such as:

  • Code is pushed
  • A pull request is created
  • A pull request is updated
  • A release is published
  • A user starts the workflow manually
  • A scheduled time is reached

For Playwright automation, the most common triggers are:

text
Push to main branch

Pull request to main branch

Manual execution

Nightly scheduled execution

GitHub Actions is especially convenient because it is directly integrated with GitHub repositories. You do not need to configure a separate Jenkins server or maintain additional infrastructure to create your first pipeline.

Why Use GitHub Actions with Playwright?

Running Playwright tests locally is useful during development, but local execution does not protect the entire development team.

Consider this situation:

  • A developer creates a new feature.
  • The developer runs only a few tests locally.
  • The code is pushed to GitHub.
  • Another feature unexpectedly breaks.
  • The problem is discovered after deployment.

A CI pipeline helps prevent this situation.

Whenever code changes, GitHub Actions can automatically run the complete Playwright test suite. If a critical test fails, the workflow fails and the team can investigate the problem before merging or deploying the code.

Playwright officially supports execution in CI environments and provides sample GitHub Actions configurations. A standard setup installs dependencies, installs the required browsers, runs the tests, and generates an HTML report.

Understanding the GitHub Actions Structure

Before writing our workflow, let's understand the main GitHub Actions concepts.

A typical structure looks like this:

text
Workflow
   └── Job
         └── Step
               └── Action or Command

Workflow

A workflow is the complete automation process. For example: Playwright Test Pipeline. It may contain one or more jobs.

Job

A job is a group of steps that runs on a machine called a runner. For example: Run Playwright Tests. Another job could be: Deploy Application.

Step

A step is an individual task inside a job. Examples: Checkout repository, Install Node.js, Install dependencies, Run Playwright tests, Upload report.

Action

An action is a reusable automation component.

yaml
uses: actions/checkout@v4

This action downloads the repository code into the GitHub Actions runner.

Runner

A runner is the machine where the workflow executes. GitHub provides hosted runners for Ubuntu, Windows, and macOS. For most Playwright CI pipelines, Ubuntu is the preferred starting point because it is generally fast, widely supported, and suitable for headless browser execution.

Project Requirements

Before creating the pipeline, make sure your Playwright project contains the following files:

text
playwright-framework/
│
├── tests/
│   └── example.spec.ts
│
├── playwright.config.ts
├── package.json
├── package-lock.json
└── .gitignore

Your package.json should include Playwright as a development dependency. Example:

package.json
{
  "name": "playwright-framework",
  "version": "1.0.0",
  "scripts": {
    "test": "playwright test",
    "test:headed": "playwright test --headed",
    "report": "playwright show-report"
  },
  "devDependencies": {
    "@playwright/test": "^1.0.0",
    "typescript": "^5.0.0"
  }
}

Do not copy the sample version numbers blindly into an existing project. Your package.json and package-lock.json should use the versions currently installed and tested by your team.

Step 1: Create the Workflow Directory

GitHub Actions workflow files must be stored inside this directory:

text
.github/workflows/

From the project root, create the folders:

bash
mkdir -p .github/workflows

Then create a new file: .github/workflows/playwright.yml

Your project structure should now look like this:

text
playwright-framework/
│
├── .github/
│   └── workflows/
│       └── playwright.yml
│
├── tests/
├── playwright.config.ts
├── package.json
└── package-lock.json

The workflow filename can be different, but it must use the .yml or .yaml extension.

Step 2: Create the Basic Playwright Workflow

Add the following configuration to playwright.yml:

.github/workflows/playwright.yml
name: Playwright Tests

on:
  push:
    branches:
      - main

  pull_request:
    branches:
      - main

  workflow_dispatch:

jobs:
  playwright-tests:
    name: Run Playwright Tests
    runs-on: ubuntu-latest

    timeout-minutes: 30

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Install Playwright browsers
        run: npx playwright install --with-deps

      - name: Run Playwright tests
        run: npx playwright test

      - name: Upload Playwright report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-html-report
          path: playwright-report/
          retention-days: 14

This is a complete working CI pipeline. Let's understand every section.

Understanding the Workflow Name

The first line defines the workflow name:

yaml
name: Playwright Tests

This name appears in the Actions tab of the GitHub repository. Choose a clear and meaningful name, especially when the repository contains multiple workflows. For example: Playwright Tests, API Regression Tests, UI Smoke Tests, Production Deployment.

Understanding Workflow Triggers

The on section defines when the pipeline should start.

yaml
on:
  push:
    branches:
      - main

  pull_request:
    branches:
      - main

  workflow_dispatch:

Push Trigger

This starts the pipeline when code is pushed to the main branch.

Pull Request Trigger

This starts the pipeline when a pull request targets the main branch. This is extremely important in professional projects. Before code is merged, the Playwright tests can validate that the proposed changes have not broken critical application functionality.

Manual Trigger

workflow_dispatch allows an authorized user to start the workflow manually from the GitHub Actions page. Manual execution is useful when QA wants to rerun tests, a test environment has been refreshed, a deployment needs additional validation, or a previous failure was caused by temporary infrastructure problems.

Understanding the Job

The jobs section contains one job named playwright-tests. The identifier is used internally by GitHub Actions. The readable job name is set with the name field. The job runs on an Ubuntu runner using runs-on: ubuntu-latest.

GitHub creates a temporary virtual machine for the workflow, executes the job, and removes the machine after completion. This means every pipeline run starts with a clean environment.

Why Set a Timeout?

We added timeout-minutes: 30. This prevents a broken or hanging test suite from running indefinitely. A workflow might become stuck because of an unavailable test environment, a server that never responds, a test waiting for an incorrect condition, a browser process that does not close, or a network-related problem.

A timeout protects your CI resources and makes failures easier to identify. The correct timeout depends on the size of your test suite. A smoke suite may need only 10 minutes, while a large regression suite may need significantly more time.

Step 3: Checkout the Repository

The first workflow step is:

yaml
- name: Checkout repository
  uses: actions/checkout@v4

The GitHub runner begins as a clean machine. It does not automatically contain your repository files. The checkout action downloads the repository code so the remaining commands can access tests, configuration files, page objects, API clients, test data, and package files.

Without this step, commands such as npm ci and npx playwright test would not find the project.

Step 4: Install Node.js

yaml
- name: Set up Node.js
  uses: actions/setup-node@v4
  with:
    node-version: 22
    cache: npm

Playwright for TypeScript and JavaScript requires Node.js. The Node.js version used in CI should match the version supported by your project. A professional team may define the version in .nvmrc, package.json, Dockerfile, and the GitHub Actions workflow. Keeping the Node.js version consistent reduces differences between local and CI execution.

The line cache: npm enables npm dependency caching. GitHub's Node.js workflow documentation supports caching npm dependencies through the setup-node action. Caching can make later workflow runs faster because required package data may be restored instead of downloaded again. Caching does not replace dependency installation. The workflow must still run npm ci.

Step 5: Install Project Dependencies

yaml
- name: Install dependencies
  run: npm ci

You may be familiar with npm install. However, npm ci is generally preferred inside CI pipelines. It installs dependencies based on the exact versions recorded in package-lock.json. This provides more predictable execution.

The workflow should fail if the lock file and package.json are not synchronized. That is useful because inconsistent dependency files can produce different results on different machines. For reliable CI execution, commit both package.json and package-lock.json. Do not add package-lock.json to .gitignore.

Step 6: Install Playwright Browsers

yaml
- name: Install Playwright browsers
  run: npx playwright install --with-deps

Playwright tests require browser binaries such as Chromium, Firefox, and WebKit. The --with-deps option also installs required Linux system dependencies.

If your project only uses Chromium, you can reduce installation time by installing only that browser:

yaml
- name: Install Chromium
  run: npx playwright install --with-deps chromium

However, install all browsers when the framework is expected to perform cross-browser validation.

Step 7: Run the Playwright Tests

yaml
- name: Run Playwright tests
  run: npx playwright test

This uses the configuration from playwright.config.ts. A basic configuration might look like this:

playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',
  fullyParallel: true,
  forbidOnly: Boolean(process.env.CI),
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 2 : undefined,
  reporter: [
    ['list'],
    ['html', { outputFolder: 'playwright-report', open: 'never' }]
  ],
  use: {
    baseURL: process.env.BASE_URL || 'https://example.com',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure'
  },
  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] }
    }
  ]
});

The setting forbidOnly: Boolean(process.env.CI) prevents accidentally committed tests containing test.only() from passing through the pipeline while skipping the rest of the suite.

The line retries: process.env.CI ? 2 : 0 enables retries in CI. Retries can help identify intermittent failures, but they should not be used to hide unstable tests. A test that regularly passes only after retrying should be investigated.

Step 8: Upload the HTML Report

yaml
- name: Upload Playwright report
  if: always()
  uses: actions/upload-artifact@v4
  with:
    name: playwright-html-report
    path: playwright-report/
    retention-days: 14

The important condition is if: always(). Without this condition, the report upload step may be skipped when the test command fails. But the report is often most valuable when tests fail. The always() condition tells GitHub Actions to attempt the upload whether the test step passes or fails.

The report is uploaded as a workflow artifact named playwright-html-report. Artifacts are files created during a workflow that can be stored and reviewed after the job completes.

How to Download the Playwright Report

After the workflow finishes:

  • Open the GitHub repository.
  • Select the Actions tab.
  • Open the Playwright workflow.
  • Select the latest workflow run.
  • Scroll to the Artifacts section.
  • Download playwright-html-report.
  • Extract the downloaded ZIP file.
  • Open index.html.

You can also open the report locally using:

bash
npx playwright show-report playwright-report

Upload Debugging Artifacts

The HTML report is useful, but enterprise teams often preserve additional debugging files. Playwright may generate screenshots, videos, trace files, test attachments, error context, and console output. These files are commonly stored inside test-results/.

Add another upload step:

yaml
- name: Upload test results
  if: failure()
  uses: actions/upload-artifact@v4
  with:
    name: playwright-test-results
    path: test-results/
    retention-days: 14
    if-no-files-found: ignore

This step runs only when the workflow fails. The option if-no-files-found: ignore prevents the artifact step from failing when the folder does not exist or contains no files.

Passing Environment Variables

Most real Playwright frameworks need environment-specific values such as Base URL, API URL, Username, Password, and Authentication token.

A non-sensitive value can be defined directly in the workflow:

yaml
- name: Run Playwright tests
  run: npx playwright test
  env:
    BASE_URL: https://qa.example.com

Sensitive values should not be hardcoded. Store secrets in GitHub via Repository → Settings → Secrets and variables → Actions → New repository secret.

Suppose you create TEST_USERNAME and TEST_PASSWORD. Use them like this:

yaml
- name: Run Playwright tests
  run: npx playwright test
  env:
    BASE_URL: https://qa.example.com
    TEST_USERNAME: ${{ secrets.TEST_USERNAME }}
    TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }}

Inside the Playwright test, access them through process.env:

typescript
const username = process.env.TEST_USERNAME;
const password = process.env.TEST_PASSWORD;
Never print passwords, API keys, tokens, or other secrets in test logs.

Running Only Smoke Tests in Pull Requests

A full regression suite may take too long to run for every pull request. A common enterprise strategy is: Pull request → Smoke tests, Main branch push → Full regression tests, Nightly schedule → Complete cross-browser regression.

You can use a test tag:

typescript
test('user can log in @smoke', async ({ page }) => {
  // Test implementation
});

Then run only smoke tests:

yaml
- name: Run smoke tests
  run: npx playwright test --grep "@smoke"

Later in this series, we will create more advanced workflows with separate jobs, environments, browser matrices, and sharding.

Common GitHub Actions Problems

Browser Dependencies Are Missing

Error: Host system is missing dependencies to run browsers. Solution:

bash
npx playwright install --with-deps

Package Lock File Is Missing

Error: npm ci can only install with an existing package-lock.json. Solution: run npm install locally, then commit package-lock.json.

Tests Pass Locally but Fail in CI

Possible causes include hardcoded local URLs, missing secrets, different Node.js versions, tests depending on local files, incorrect time-zone assumptions, tests sharing state, insufficient waiting or synchronization, and the application being unavailable from the runner. Use traces, screenshots, videos, and reports to investigate.

Report Is Not Uploaded After Failure

Make sure the artifact step includes if: always().

Pipeline Is Too Slow

Possible improvements include installing only required browsers, caching npm dependencies, running smoke tests for pull requests, using parallel execution, using test sharding, avoiding unnecessary setup, and reusing authenticated state safely. We will cover matrices, parallel execution, and sharding in later tutorials.

Enterprise Best Practices

For a professional Playwright GitHub Actions pipeline:

  • Use npm ci instead of npm install.
  • Keep Node.js versions consistent.
  • Never hardcode credentials.
  • Store sensitive values in GitHub Secrets.
  • Upload reports even when tests fail.
  • Preserve traces, screenshots, and videos.
  • Use meaningful workflow and job names.
  • Add execution timeouts.
  • Prevent committed test.only() with forbidOnly.
  • Separate smoke and regression execution.
  • Investigate flaky tests instead of relying on retries.
  • Protect the main branch with required status checks.
  • Keep workflow files inside version control.
  • Review action versions periodically.
  • Use the minimum repository permissions required by the workflow.

The pipeline should be treated as production code. It needs proper naming, maintainability, security, documentation, and code review.

Complete Pipeline Flow

Our first GitHub Actions pipeline now follows this process:

text
Developer Pushes Code
          │
          ▼
GitHub Detects the Change
          │
          ▼
GitHub Actions Starts
          │
          ▼
Create Ubuntu Runner
          │
          ▼
Checkout Repository
          │
          ▼
Install Node.js
          │
          ▼
Restore npm Cache
          │
          ▼
Install Dependencies
          │
          ▼
Install Playwright Browsers
          │
          ▼
Execute Playwright Tests
          │
          ▼
Generate HTML Report
          │
          ▼
Upload Report and Debugging Files
          │
          ▼
Display Pass or Fail Status

This is the foundation of an enterprise Playwright CI/CD pipeline.

Key Takeaways

GitHub Actions transforms your Playwright framework from a locally executed test project into an automated quality gate. Every push and pull request can now be validated through a consistent process. The runner installs the required dependencies, installs Playwright browsers, executes the tests, generates reports, and preserves debugging artifacts.

This gives the development team fast feedback and reduces the chance that broken functionality will be merged into the main branch.

You also learned how to create a GitHub Actions workflow, configure push, pull-request, and manual triggers, run the workflow on an Ubuntu runner, install Node.js, cache npm dependency data, install packages with npm ci, install Playwright browsers and Linux dependencies, execute Playwright tests, upload HTML reports, preserve screenshots, videos, and traces, pass environment variables, read credentials from GitHub Secrets, and troubleshoot common CI failures.

However, this pipeline currently executes a single standard test job. Real enterprise projects often need different configurations for development, QA, staging, and production environments.

In the next tutorial, we will build a multiple-environment Playwright pipeline that can switch base URLs, API endpoints, credentials, and configuration values without changing the test code. That will take our framework one step closer to a scalable, production-ready CI/CD solution.

Get Playwright tutorials in your inbox

Weekly tips, real-world examples, and framework patterns – no spam, unsubscribe anytime.

Playwright Framework Series

View all →
  1. 1Getting Started with Playwright: Installation, Setup, and Your First Test
  2. 2Playwright Locators: The Complete Guide with Real-World Examples
  3. 3Playwright Actions: Complete Guide to Click, Fill, Hover, Keyboard, Mouse & File Upload
  4. 4Playwright Assertions: The Complete Guide with Real-World Examples
  5. 5Playwright Auto Waiting: The Complete Guide with Real-World Examples
  6. 6Playwright Fixtures: The Complete Guide with Real-World Examples
  7. 7Playwright Browser Context & Multiple Tabs: The Complete Guide with Real-World Examples
  8. 8Playwright Authentication & Session Management: Complete Guide with Enterprise Examples
  9. 9Playwright Network Interception & API Mocking: Complete Guide with Real-World Examples
  10. 10Playwright Page Object Model (POM): The Complete Guide with Enterprise Examples
  11. 11Page Object Model with Playwright: A Practical Guide
  12. 12How to Build a Robust Professional Playwright Framework from Scratch (Step-by-Step)
  13. 13Building an Enterprise Playwright Framework from Scratch

API Testing Series

View all →
  1. 1Playwright API Testing: The Complete Guide with Real-World Examples
  2. 2Part 1 : Playwright API Testing Tutorial: Build Enterprise-Level API Automation Framework
  3. 3Part 2: Playwright API Testing Tutorial: Setting Up Project & Sending Your First API Request
  4. 4Part 3: Mastering CRUD Operations in Playwright API Testing
  5. 5Part 4: Authentication in Playwright API Testing (Bearer Token, JWT, API Key & Reusable Fixtures)
  6. 6Part 5: Building an Enterprise-Level Playwright API Automation Framework
  7. 7Part 6: API Models, Schema Validation & Test Data Management in Playwright
  8. 8Part 7: Custom Fixtures, Hooks, Logging & Parallel Execution in Playwright API Testing
  9. 9Part 8: Building a Production-Ready Playwright API Framework (Environment Management, CI/CD, Reporting & Best Practices)
  10. 10Part 9: Advanced Playwright API Testing Techniques for Enterprise Automation
  11. 11Part 10: Building a Complete Enterprise Playwright API Automation Framework (Final Part)
  12. 12API Testing with Playwright: Request Context, Auth, and Assertions

Recommended Next Articles