How to Test Webhooks in CI
A webhook handler is just a POST route, so a test signs a sample payload and posts it to the endpoint.
Compute the provider's HMAC signature over a fixture payload, POST it with the signature header, then assert the handler returned success and did its side effect.
Steps
- Save a realistic sample payload as a fixture.
- Compute the HMAC signature over the raw body.
- POST it with the signature header and assert the response.
Workflow
.github/workflows/ci.yml
steps:
- run: |
npm start &
npx wait-on http://localhost:3000/health
- run: |
BODY=$(cat fixtures/order.created.json)
SIG="sha256=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$WEBHOOK_SECRET" | awk '{print $2}')"
curl -sf -X POST http://localhost:3000/webhooks \
-H "content-type: application/json" \
-H "x-signature: $SIG" \
--data "$BODY" -o /dev/null -w '%{http_code}' | grep -q 200
env:
WEBHOOK_SECRET: ${{ secrets.WEBHOOK_SECRET }}Gotchas
- Sign the exact raw bytes the handler verifies; reserializing JSON changes the signature.
- Test the rejection path too: send a bad signature and assert the handler returns 401.
Related guides
How to Handle Auth Tokens for API Tests in CIAuthenticate API tests in GitHub Actions by fetching a token at runtime or reading one from secrets, then pas…
How to Mock External APIs in CIStub third-party APIs during API tests in GitHub Actions with WireMock, Prism, MSW, or nock, so tests stay de…
How to Assert an API Response Matches a JSON Schema in CIValidate that an API response matches a JSON Schema in GitHub Actions with ajv or jsonschema, so a shape chan…