[Update v1.46] Is it possible to run only Playwright Tests that changed in GitHub actions on a pull request?
Good news everyone! This is now possible to do without any external scripts. It is all baked into the Playwright CLI.
Original solution
If you've been subscribed for some time you may have remembered the original solution. It included getting a list of the file names by running a narly git diff
command and piping the results to grep
and tr
commands. Storing those file names to a CHANGED
environment variable, and passing that into the npx playwright test ${{ env.CHANGED }}
.
Updated solution
There was a flaw with my approach that I just accepted as I didn't see an easy way to solve the problem. I was only checking and building the CHANGED list of tests run from the *.spec
files. This list didn't include any page object files, helpers, fixtures, or data factory files. This was a known risk in my case, but with the built in playwright command they have solved this problem. See version 1.46 release notes below.
New CLI option --only-changed
will only run test files that have been changed since the last git commit or from a specific git "ref". This will also run all test files that import any changed files.
Running pre-commit and post-commit
One thing to note with this solution, the command --only-changed
by itself will only run files that have been changed, but not yet committed. This is important as you commit files to your local branch this command will not pick up those test changes after committed.
In order to pick up changes on committed files you will need to pass in a reference branch to check against. --only-changed=main
for example will check your local git changes and do a diff against the main branch and run those changes.
Example on playwright-api-test-demo
Let's update our playwright-api-test-demo repo with the changes both in our package.json
file to create a new npm script npm run changed
.
// package.json
...
"scripts": {
...
"changed": "npx playwright test --only-changed"
},
We'll also update our on-pr-files-changed.yml
file removing all the old CHANGED
logic we previously implemented. The main thing we are adding is the --only-changed=origin/$GITHUB_BASE_REF
. Using the $GITHUB_BASE_REF
here instead of main
as the branch will prevent an error I was receiving when running in CI when I was using --only-changed=origin/main
as the release notes demonstrated. The specific error I received is below.
Error: Cannot detect changed files for --only-changed mode:
git diff main --name-only
fatal: ambiguous argument 'main': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
Error: Error: Cannot detect changed files for --only-changed mode: git diff main --name-only
fatal: ambiguous argument 'main': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
The changes that worked for me were adding the fetch-depth: 0 (the default is 1) and adding the --only-changed flag in my npx playwright test command.
name: Changed Files Playwright API Checks
on:
pull_request:
branches:
- main
...
jobs:
playwright-automation-checks:
...
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
...
- name: Run Playwright tests
run: |
npx playwright test --only-changed=origin/$GITHUB_BASE_REF
....
The full example can be found below.
// on-pr-files-changed.yml
name: Changed Files Playwright API Checks
on:
pull_request:
branches:
- main
permissions:
contents: write
pages: write
id-token: write
jobs:
playwright-automation-checks:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
timeout-minutes: 10
runs-on: ubuntu-latest
env:
BASE_URL: ${{ github.event.inputs.base_url }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-node@v3
with:
node-version: 16
- name: Cache node_modules
uses: actions/cache@v3
id: node-modules-cache
with:
path: |
node_modules
key: modules-${{ hashFiles('package-lock.json') }}
- run: npm ci --ignore-scripts
if: steps.node-modules-cache.outputs.cache-hit != 'true'
- name: Get installed Playwright version
id: playwright-version
run: echo "PLAYWRIGHT_VERSION=$(node -e "console.log(require('./package-lock.json').dependencies['@playwright/test'].version)")" >> $GITHUB_ENV
- name: Cache playwright binaries
uses: actions/cache@v3
id: playwright-cache
with:
path: |
~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }}
- run: npx playwright install --with-deps
if: steps.playwright-cache.outputs.cache-hit != 'true'
- run: npx playwright install-deps
if: steps.playwright-cache.outputs.cache-hit != 'true'
- name: Run lint
run: npm run lint
- name: Run prettier
run: npm run prettier
- name: Set BASE_URL if not passed in
if: env.BASE_URL == null
run: |
echo "BASE_URL=https://automationintesting.online/" >> $GITHUB_ENV
- name: Run Playwright tests
run: |
echo "The github event is: ${{ github.event_name }}"
URL=${{ env.BASE_URL }} npx playwright test --grep-invert @unsatisfactory --reporter=github --workers=1 --only-changed=origin/$GITHUB_BASE_REF
Using only-changed on monorepos
One thing to note in my research Pramod Yadav (go give him a follow on LinkedIn) reported a Bug in the GitHub Issues section of the Playwright repository. He attempted to implement this within a monorepo and found there were some extra steps to get things working. Specifically adding git config --global --add safe.directory '*'
as a command that is run after checking out the code and before the playwright test execution.
name: Changed Files Playwright API Checks
on:
pull_request:
branches:
- main
...
jobs:
playwright-automation-checks:
...
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Mark repo as safe
run: git config --global --add safe.directory '*'
...
- name: Run Playwright tests
run: |
npx playwright test --only-changed=origin/$GITHUB_BASE_REF
....
Thanks for reading! If you found this helpful, reach out and let me know on LinkedIn or consider buying me a cup of coffee. If you want more content delivered to you in your inbox subscribe below, and be sure to leave a ❤️ to show some love.