Skip to content
Content

Playwright PR Approval Automation

image
January 19, 2026
I introduced a new GitHub Actions workflow that automatically detects and runs only newly added Playwright test definitions whenever a pull request is opened or updated. This workflow provides fast, targeted feedback on newly written Playwright tests without the overhead of a full regression run. It is a useful addition to the CI pipeline but has known limitations around environment configuration, diff parsing accuracy, and test isolation. Use it as an early warning system alongside, not as a replacement for full test suite execution. The workflow triggers on pull_request and merge_group events and runs two independent jobs: A fast gate that runs ESLint and TypeScript type checking on every PR. This catches syntax errors, type mismatches, and style violations before any tests execute. Timeout: 10 minutes. This is the core of the new flow. It works in four stages:
  1. Full checkout -- The repository is cloned with fetch-depth: 0 (complete git history) so the workflow can compute an accurate diff between the PR base and head commits.
  2. Diff computation -- A git diff -U0 is run between base_sha...head_sha, filtered to only e2e/**/*.spec.ts and e2e/**/*.test.ts files.
  3. AWK-based selector extraction -- An AWK script parses the unified diff and emits file:lineNumber pairs for every added line that matches a Playwright test definition pattern. Recognized patterns include:
    • test(
    • test.only(, test.skip(, test.fixme(
    • test.describe(
    • test.describe.serial(, test.describe.parallel(
    • test.describe.only(, test.describe.skip(, test.describe.fixme(
  4. Targeted execution -- The extracted file:line selectors are passed directly to npx playwright test, so only the newly added tests run. If no new test definitions are detected, the job logs a skip message and exits cleanly.
A Playwright HTML report is uploaded as a build artifact (retained for 14 days) regardless of pass/fail outcome.
Only the tests you actually wrote in the PR are executed. The full regression suite is not triggered, which keeps CI times short and focused. A newly written test that fails due to a bad selector, missing fixture, or flawed assertion is caught immediately -- not days later in a scheduled regression run. Authors do not need to remember to run their new tests locally or specify which tests to run. The workflow handles detection and execution automatically. Playwright's file:line selector format means only the exact test definitions that were added are executed, not the entire file. This avoids running unrelated tests that happen to live in the same spec file. The lint-typecheck job provides sub-minute feedback on basic code quality, independent of the slower Playwright job. If lint fails, the author knows immediately without waiting for browser tests. The upload-artifact step runs with if: always(), so even on failure the HTML report is available for debugging.
A newly added test may pass in isolation but fail when run alongside existing tests (shared state, database fixtures, parallel conflicts). This workflow does not catch ordering-dependent failures because i'm a firm believer that every test should be independent with test data and conditions created in before and after steps. The diff parser uses regex patterns to detect test definitions. Edge cases can produce false positives or false negatives:
  • False positive: A comment containing test( would be detected as a test.
  • False negative: A test definition split across multiple lines (e.g., template literal in the test name) may not be detected if the test( call is not on the added line.
  • Renamed tests: If a test is renamed (deleted + added), it is treated as a new test.
The git diff base_sha...head_sha (three-dot) syntax computes the diff from the merge base. If the target branch has advanced significantly, the diff may include changes that are not directly part of the PR, potentially picking up test definitions from other merged branches. The workflow runs tests once. Playwright's config does set retries: 1 when CI=true, but there is no dedicated flaky-test quarantine or re-run mechanism at the workflow level yet. The 30-minute timeout is generous for a few new tests, but a PR that adds dozens of spec files with many test cases could hit this limit, especially with browser installation time included.
Ensure the repository has the required secrets and environment variables set in GitHub Actions settings. Without these, tests will crash on startup. This workflow runs only new tests. It does not run existing tests that may be broken by your code changes. Continue running the full regression suite (test.yml, prod.yml) on a schedule or before releases. Treat this workflow as an early signal, not a complete validation. To ensure the AWK parser detects your tests, write test definitions in the standard single-line format:
// Detected correctly
test('should add item to cart', async ({ page }) => {

// Detected correctly
test.describe('Checkout flow', () => {

// May NOT be detected -- test( is not on the added line
test(
  'should add item to cart',
  async ({ page }) => {
The workflow prints all detected file:line selectors before executing. Review the Compute selectors for newly added tests step output to verify the correct tests were identified. If something looks wrong, the AWK logic may need adjustment. When tests fail, download the playwright-report artifact from the Actions run summary. The HTML report includes screenshots, traces (on failure), and detailed error messages. Do not merge a PR with failing new tests unless there is a documented reason and a follow-up plan. New tests run in the CI environment without other tests running alongside them. If your test depends on state set up by another test (e.g., a user created in a previous spec), it will fail. Design tests to be self-contained with their own setup and teardown. Each PR trigger installs Playwright browsers (Chromium, WebKit, Firefox), which is a non-trivial download. For repositories with high PR volume, consider caching the browser binaries using actions/cache to reduce both time and bandwidth costs. The playwright.config.ts sets forbidOnly: true when CI=true. If you accidentally commit a test.only(, the entire Playwright run will fail. The workflow will detect test.only( definitions, but Playwright will refuse to run them.