Skip to content

GitHub Actions

This page gives you a GitHub Actions job that runs after your deploy, triggers every active test in a Plainwright project through the CI webhook, waits for the batch to finish, and fails the workflow when the gate fails. Quarantined tests never fail it, and the server takes retries and human overrides into account.

  1. In Plainwright, open the project’s Settings → General → Run from CI (you need to be an admin) and copy the webhook secret. The project ID is the UUID at the end of the webhook URL.

  2. In GitHub, open the repository’s Settings → Secrets and variables → Actions and add three repository secrets:

    Secret Example
    PLAINWRIGHT_URL https://plainwright.example.com (a trailing slash is fine)
    PLAINWRIGHT_PROJECT_ID 74a76eba-773d-42a7-8f4a-165e386b0e8f
    PLAINWRIGHT_WEBHOOK_SECRET the secret from step 1
  3. Optional: to test a staging or preview environment instead of the project’s base URL, add a repository variable (not a secret) named PLAINWRIGHT_ENVIRONMENT_ID with the environment’s ID.

  4. Add one of the workflows below as .github/workflows/plainwright.yml, and put your deploy steps where the comment says.

Short and easy to adapt. curl and jq are preinstalled on ubuntu-latest.

.github/workflows/plainwright.yml
name: Deploy and test with Plainwright
on:
push:
branches: [main]
workflow_dispatch:
jobs:
deploy-and-test:
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
# … your deploy steps go here …
- name: Run Plainwright tests and wait for the gate
env:
PLAINWRIGHT_URL: ${{ secrets.PLAINWRIGHT_URL }}
PLAINWRIGHT_PROJECT_ID: ${{ secrets.PLAINWRIGHT_PROJECT_ID }}
PLAINWRIGHT_WEBHOOK_SECRET: ${{ secrets.PLAINWRIGHT_WEBHOOK_SECRET }}
PLAINWRIGHT_ENVIRONMENT_ID: ${{ vars.PLAINWRIGHT_ENVIRONMENT_ID }}
run: |
set -euo pipefail
BASE="${PLAINWRIGHT_URL%/}"
AUTH="X-Webhook-Secret: $PLAINWRIGHT_WEBHOOK_SECRET"
BODY=$(jq -n --arg by "github · $GITHUB_REPOSITORY@${GITHUB_SHA::7}" \
--arg env "${PLAINWRIGHT_ENVIRONMENT_ID:-}" \
'{triggered_by: $by} + (if $env == "" then {} else {environment_id: $env} end)')
RESP=$(curl -fsS -X POST "$BASE/api/runs/webhook/$PLAINWRIGHT_PROJECT_ID" \
-H "$AUTH" -H "Content-Type: application/json" -d "$BODY")
COUNT=$(jq '.run_ids | length' <<<"$RESP")
if [ "$COUNT" -eq 0 ]; then echo "No active tests, nothing to gate."; exit 0; fi
STATUS_URL=$(jq -r .status_url <<<"$RESP")
echo "Queued $COUNT runs · batch $(jq -r .batch_id <<<"$RESP")"
GATE=pending
for i in $(seq 1 120); do # 120 × 15 s = 30 minutes
REPORT=$(curl -fsS "$BASE$STATUS_URL" -H "$AUTH")
GATE=$(jq -r .gate <<<"$REPORT")
[ "$GATE" != "pending" ] && break
jq -r '.summary | "… \(.passed) passed · \(.failed) failed · \(.pending) running"' <<<"$REPORT"
sleep 15
done
{
echo "### Plainwright gate: ${GATE^^}"
echo
echo "| Result | Kind | Test |"
echo "| --- | --- | --- |"
jq -r '.runs[] | "| \(.gate | ascii_upcase)\(if .quarantined then " (quarantined)" else "" end) | \(.kind) | [\(.name)](\(.url)) |"' <<<"$REPORT"
} >> "$GITHUB_STEP_SUMMARY"
case "$GATE" in
pass) echo "Quality gate passed." ;;
fail) echo "::error title=Plainwright::Quality gate failed"; exit 1 ;;
*) echo "::error title=Plainwright::Timed out waiting for the gate"; exit 1 ;;
esac
  • The job fails when the gate fails, and also when the server can’t be reached, the secret is wrong (403) or the batch takes longer than the timeout.
  • A job summary (the workflow run’s Summary page) with one row per test: result, kind and a link to the run in Plainwright. Run links are built from the server’s APP_BASE_URL, so set it to your public URL.
  • Step outputs (full workflow): batch_id, gate (pass, fail or timeout), passed and failed. Read them in later steps as steps.gate.outputs.gate.
  • Triggered by on each run reads github · <owner>/<repo>@<short sha>, so you can find the commit from the run page.
Change How
Wait longer Full workflow: PLAINWRIGHT_TIMEOUT_S (default 1800). Compact: the seq 1 120 loop count. Keep the job’s timeout-minutes above it.
Poll less often Full workflow: PLAINWRIGHT_POLL_S (default 15, minimum 5). Compact: sleep 15.
Another browser or device Add browser (firefox, webkit) or device (iphone, pixel, ipad) to the JSON body. See Browsers and devices.
Run on pull requests Add pull_request: under on:. Pull requests from forks don’t get repository secrets, so the step can’t trigger tests for them.
Run after a separate deploy workflow Use on: workflow_run with workflows: ["Deploy"] and types: [completed], or on: deployment_status.
Re-run only the failures Rerun failed needs a user token rather than the webhook secret: POST /api/reliability/project/{id}/rerun-failed?batch_id=<batch>. See Quarantine and re-run.
Symptom Fix
HTTP 403 Invalid secret The secret is wrong or was rotated in Plainwright. Copy it again from Run from CI.
HTTP 404 Project not found PLAINWRIGHT_PROJECT_ID is wrong.
Could not reach Plainwright, or curl: (6) / curl: (7) The URL isn’t reachable from the runner. Check DNS, HTTPS and firewalls.
HTTP 503 The server’s job queue (Redis) is down. Check the stack on the server.
The gate stays pending until the timeout No worker is picking up runs, or the tests are slow. Check that workers are running (Scaling workers) and raise the timeout.
Every UI test fails with the same error Open the cause in Triage. A wrong environment URL or an expired AI provider key often shows up this way.