GitHub Actions: baseline gate, step summary and PR comment
An example workflow for a project that uses playwright-ui-coverage. It:
- runs the Playwright tests with the baseline check (
baselineoption) and the step summary (githubSummary); - uploads
ui-coverage-report/as an artifact, so later runs on pull requests can compare with the one frommain; - on pull requests, downloads the
ui-coverage-reportartifact of the latest successful run onmain, runsplaywright-ui-coverage compare, and posts the markdown as a sticky comment (one comment per PR, updated on every push).
This file is documentation: copy the workflow into your project's .github/workflows/.
Reporter options
ts
// playwright.config.ts
reporter: [
['html', { open: 'never' }],
['playwright-ui-coverage/reporter', {
// Fail only on new untested elements; ui-coverage-baseline.json is committed.
baseline: 'ui-coverage-baseline.json',
// Append a summary to the job's page (only when $GITHUB_STEP_SUMMARY is set).
githubSummary: true,
}],
],Create the baseline once (npx playwright test with baseline: { file: 'ui-coverage-baseline.json', mode: 'update' }, or npx playwright-ui-coverage baseline update after a run) and commit it. Add *.next.json to .gitignore.
Workflow
yaml
# .github/workflows/e2e.yml
name: E2E
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
actions: read # download artifacts of other runs
pull-requests: write # sticky comment
jobs:
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
with:
node-version: 22
cache: npm
- run: npm ci
- run: npx playwright install --with-deps chromium
# Fails the job on failing tests, thresholds, or new untested elements
# (baseline). Keep going so the report is uploaded and the PR comment
# is posted either way; the last step fails the job.
- name: Playwright tests
id: tests
continue-on-error: true
run: npx playwright test
- uses: actions/upload-artifact@v5
if: always()
with:
name: ui-coverage-report
path: ui-coverage-report/
retention-days: 30
# The baseline with this run's improvements: download it, commit it as
# ui-coverage-baseline.json to ratchet.
- uses: actions/upload-artifact@v5
if: always()
with:
name: ui-coverage-baseline-next
path: ui-coverage-baseline.next.json
if-no-files-found: ignore
# ---- Pull requests: compare with main and comment ---------------------
- name: Download coverage.json from main
if: github.event_name == 'pull_request'
env:
GH_TOKEN: ${{ github.token }}
run: |
run_id=$(gh run list --repo "$GITHUB_REPOSITORY" --workflow e2e.yml --branch main \
--event push --status success --limit 1 --json databaseId --jq '.[0].databaseId')
if [ -n "$run_id" ]; then
gh run download "$run_id" --repo "$GITHUB_REPOSITORY" --name ui-coverage-report --dir base-report || true
fi
- name: Compare
if: github.event_name == 'pull_request'
run: |
if [ -f base-report/coverage.json ]; then
npx playwright-ui-coverage compare base-report/coverage.json ui-coverage-report/coverage.json --out ui-coverage-comment.md
else
# No run on main yet: post this run's summary instead.
npx playwright-ui-coverage summary ui-coverage-report/coverage.json --out ui-coverage-comment.md
fi
cat ui-coverage-comment.md >> "$GITHUB_STEP_SUMMARY"
# Creates the comment, or updates it: the markdown starts with
# <!-- playwright-ui-coverage -->, which is how the comment is found again.
- name: Sticky PR comment
if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository
env:
GH_TOKEN: ${{ github.token }}
PR: ${{ github.event.pull_request.number }}
run: |
id=$(gh api "repos/$GITHUB_REPOSITORY/issues/$PR/comments" --paginate \
--jq '[.[] | select(.body | startswith("<!-- playwright-ui-coverage -->"))][0].id // empty')
if [ -n "$id" ]; then
gh api --method PATCH "repos/$GITHUB_REPOSITORY/issues/comments/$id" -F body=@ui-coverage-comment.md > /dev/null
else
gh pr comment "$PR" --body-file ui-coverage-comment.md
fi
- name: Fail if the tests failed
if: steps.tests.outcome == 'failure'
run: exit 1Notes:
- Sticky comment with an action instead of
gh:marocchino/sticky-pull-request-commentworks too:with: { header: playwright-ui-coverage, path: ui-coverage-comment.md }. - Pull requests from forks get a read-only token, so the comment step is skipped for them (the condition above); the step summary still shows the comparison. To comment on fork PRs, post from a separate
workflow_runworkflow. - Links to the report: if you publish the HTML report (GitHub Pages, an artifact viewer…), pass
--report-url https://…/index.htmltocompare/summaryso view names link to it. - Sharded runs: run the shards with
--reporter=blob, merge withnpx playwright merge-reports --config merge.config.ts all-blob-reports(withbaselineandgithubSummaryin the merge config's reporter options), and do the steps above in the merge job. - Baseline vs. compare: the baseline check is the gate (it decides pass/fail against a committed file, so it works without artifacts);
compareis informational (what this PR changes compared withmain). Use either or both.