Run Playwright API Tests in CI: GitHub Actions, Allure and JUnit
Tests that only run on your laptop protect nobody. The real value of an API suite appears when it runs automatically on every pull request, blocks broken builds, and publishes a report the whole team can read. In this final lesson of Module 6 you’ll run the Playwright API framework in GitHub Actions with secrets, tags, sharding and type-checking, produce HTML, JUnit and Allure reports, and see the equivalent Jenkins pipeline.
npm ci, type-check with npx tsc --noEmit, run npx playwright test with environment variables from the CI secret store, and upload playwright-report/ (HTML), results/junit.xml and allure-results/ as artifacts. Use tags (--grep @smoke) for fast PR checks, sharding (--shard=1/4) to split long suites across machines, retries for rare network blips and forbidOnly to block test.only. Pure API tests don’t need browsers installed.What a Good API Test Pipeline Does
- Triggers on pull requests, merges to main, a nightly schedule and manual runs.
- Installs exact dependency versions (
npm ciwith a lockfile). - Type-checks the test code (Playwright doesn’t).
- Runs the right subset: smoke on PRs, full regression nightly or on merge.
- Fails the build on test failures (non-zero exit code).
- Publishes reports as artifacts and test results in the CI UI.
- Keeps secrets secret: credentials from the secret store, never in Git or logs.
Prepare the Project for CI
Scripts in package.json keep commands identical locally and in CI:
{
"scripts": {
"typecheck": "tsc -p tsconfig.json --noEmit",
"test": "playwright test",
"test:smoke": "playwright test --grep @smoke",
"report": "playwright show-report"
}
}
Tag your critical tests. The tag syntax (Playwright 1.42+):
import { test, expect } from '@playwright/test';
test('health is up', { tag: ['@smoke', '@health'] }, async ({ request }) => { await expect(await request.get('health')).toBeOK(); });
The config from the framework lesson already sets forbidOnly, retries and workers when process.env.CI is set; GitHub Actions and most CI tools set CI=true automatically.
GitHub Actions Workflow
Save as .github/workflows/api-tests.yml:
name: API tests
on:
pull_request:
push:
branches: [main]
schedule:
- cron: '30 1 * * *' # nightly 01:30 UTC (07:00 IST)
workflow_dispatch:
jobs:
api-tests:
runs-on: ubuntu-latest
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
shard: [1, 2] # split the suite across 2 machines
env:
API_BASE_URL: ${{ vars.API_BASE_URL }}
ADMIN_USER: ${{ secrets.ADMIN_USER }}
ADMIN_PASS: ${{ secrets.ADMIN_PASS }}
VIEWER_USER: ${{ secrets.VIEWER_USER }}
VIEWER_PASS: ${{ secrets.VIEWER_PASS }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- run: npm ci
- run: npm run typecheck
# Pull requests run the smoke subset; everything else runs the full suite
- name: Run tests
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
npx playwright test --grep @smoke --shard=${{ matrix.shard }}/2
else
npx playwright test --shard=${{ matrix.shard }}/2
fi
- uses: actions/upload-artifact@v4
if: always()
with:
name: report-shard-${{ matrix.shard }}
path: |
playwright-report/
results/junit.xml
allure-results/
retention-days: 14
Notes on the important lines:
- No
npx playwright install: pure API tests don’t launch browsers, which saves a minute or more per job. Add it back when the suite includes UI tests. varsvssecrets: non-sensitive values (base URL) as repository variables; passwords and tokens as secrets (masked in logs).if: always()uploads reports even when tests fail, which is exactly when you need them.fail-fast: falselets every shard finish so you see all failures.
Create secrets under Settings → Secrets and variables → Actions. Practice API credentials are public, but use secrets anyway to build the habit.
Sharding: Split Long Suites
--shard=1/4 runs the first quarter of tests, 2/4 the second, and so on. Run each shard on a separate CI machine in parallel. Locally, the framework from this module splits into 28 and 27 tests with --shard=1/2 and --shard=2/2. To combine shard results into one HTML report, use the blob reporter in each shard and npx playwright merge-reports in a final job:
# in each shard
npx playwright test --shard=1/4 --reporter=blob
# in a final job, after downloading all blob-report folders into all-blob-reports/
npx playwright merge-reports --reporter=html ./all-blob-reports
Reports: HTML, JUnit and Allure
| Reporter | Config | Use |
|---|---|---|
| list / line / dot | ['list'] | Console output in CI logs |
| HTML | ['html', { open: 'never' }] | Interactive report with steps, attachments, retries |
| JUnit | ['junit', { outputFile: 'results/junit.xml' }] | Test results tab in Jenkins, Azure DevOps, GitLab; GitHub via test-reporter actions |
| Allure | ['allure-playwright'] | Rich dashboards, history and trends, categories |
| blob | ['blob'] | Mergeable results from shards |
Adding Allure
npm install -D allure-playwright
# run with the Allure reporter (or add ['allure-playwright'] to the reporter list in the config)
npx playwright test --reporter=line,allure-playwright
# generate and open the report (needs the Allure command-line tool, which requires Java)
npx allure generate allure-results --clean -o allure-report
npx allure open allure-report
The allure-playwright reporter writes JSON result files into allure-results/; we verified it produced one result file per test for this framework. Allure’s history and trend charts need the previous report’s history folder copied into allure-results before generating, which hosted setups (Allure TestOps, or a GitHub Pages workflow) do for you.
Jenkins Pipeline
Many service companies run Jenkins. The same steps in a declarative Jenkinsfile:
pipeline {
agent { docker { image 'node:22' } }
environment {
API_BASE_URL = 'https://qa.example.com/api/v1/'
ADMIN = credentials('qa-admin') // creates ADMIN_USR and ADMIN_PSW
}
triggers { cron('H 1 * * *') }
stages {
stage('Install') { steps { sh 'npm ci' } }
stage('Typecheck') { steps { sh 'npm run typecheck' } }
stage('Test') {
steps {
sh 'ADMIN_USER=$ADMIN_USR ADMIN_PASS=$ADMIN_PSW npx playwright test'
}
}
}
post {
always {
junit 'results/junit.xml'
archiveArtifacts artifacts: 'playwright-report/**', allowEmptyArchive: true
}
}
}
Jenkins’ junit step turns the JUnit XML into test trends and per-test history. More details are in the Playwright Jenkins lesson and the GitHub Actions tutorial.
Keeping CI Green (and Trustworthy)
- Flaky tests: track tests that pass on retry (HTML report marks them “flaky”); fix or quarantine with
test.fixme()plus a ticket. Never just raise retries. - Environment health first: a setup project that logs in also acts as a health gate; if it fails, the run stops with one clear error.
- Test data hygiene: unique data and cleanup so parallel CI jobs don’t collide.
- Fast feedback: smoke on PRs in under 5 minutes; heavier suites on merge or nightly.
- Notifications: send failures to the team’s Slack or Teams channel with a link to the report.
- Ownership: a failing pipeline is everyone’s priority, not “QA’s problem”.
Module 6 Recap
| Lesson | You can now… |
|---|---|
| APIRequestContext | Configure Playwright for APIs and avoid the baseURL trap |
| CRUD tests | Write independent, parallel-safe CRUD suites with service objects |
| Assertions & schemas | Assert deeply and validate contracts with Zod and Ajv |
| Authentication | Handle Basic, API key and Bearer auth with setup projects and role fixtures |
| Data-driven | Generate tests from arrays, JSON and CSV |
| Framework design | Explain and build a layered framework |
| CI (this lesson) | Run it all in GitHub Actions or Jenkins with reports |
The full framework from this module (55 tests including setup) passes against the live practice API. Next, Module 7 turns these skills into five portfolio projects.
Interview Questions: CI/CD for API Tests
How do you run Playwright API tests in CI/CD?
Install dependencies with npm ci, type-check, run npx playwright test with environment variables from the CI secret store, publish HTML and JUnit (and optionally Allure) reports as artifacts, and let the non-zero exit code fail the pipeline.
Do API tests need browsers installed in CI?
No. APIRequestContext doesn’t use browsers, so npx playwright install can be skipped for pure API suites, which speeds up pipelines.
What is sharding in Playwright?
Splitting the test suite into parts with –shard=x/y and running each part on a separate machine in parallel. Blob reports from shards can be merged into one HTML report with merge-reports.
How do you run only smoke tests on pull requests?
Tag smoke tests (tag: ‘@smoke’ or @smoke in titles) and run npx playwright test –grep @smoke in the PR workflow, with the full suite on merge or nightly.
How do you handle secrets in GitHub Actions?
Store them as repository or environment secrets, expose them to the job as environment variables (${{ secrets.NAME }}), never echo them, and keep non-sensitive config in variables.
What reports do you generate and why?
Playwright’s HTML report for debugging with steps and attachments, JUnit XML for the CI tool’s test results and trends, and Allure for dashboards and history when stakeholders need them.
How do you deal with flaky tests in CI?
Detect them from retry data, investigate causes (shared data, timing, rate limits, environment), fix them, and temporarily quarantine with test.fixme and a ticket. Retries are a safety net, not a fix.
What does forbidOnly do?
It fails the run if any test or describe uses .only, preventing a focused test accidentally committed from silently skipping the rest of the suite in CI.
Why add a type-check step if tests already run?
Playwright transpiles TypeScript without checking types, so type errors can hide until they cause runtime bugs. tsc –noEmit catches them early.
How would you integrate API tests with Jenkins?
Use a Jenkinsfile with stages for install, type-check and test, inject credentials with credentials(), run tests in a Node Docker agent, then publish results with the junit step and archive the HTML report in the post section.