Generating tests from GitHub and Stripe payloads

GitHub and Stripe publish a schema for every webhook they send. workflow-tester uses those schemas to build the payloads your workflow is likely to meet: a field set to null, an optional object left out, an empty string.

1. Add a contract

A contract says which events a workflow's trigger receives.

workflow-tester contracts add workflows/issue-triage.json --vendor github --events issues-opened

Expected output:

workflows/issue-triage.contract.yaml
  vendor  github @ 1.1.4
  events  issues-opened
  shape   ../.workflow-tester/contracts/github.issues-opened.schema.json

This creates:

workflows/
└── issue-triage.contract.yaml
.workflow-tester/
└── contracts/
    ├── github.issues-opened.examples.json
    └── github.issues-opened.schema.json

The sample workflow is docs/demo/issue-triage.json.

Event names

VendorNames look likeExample
GitHubThe event plus its actionissues-opened, pull-request-opened
StripeStripe's own namesinvoice.paid, charge.refunded

List a vendor's event names with workflow-tester vendors events github. A wrong name is rejected before anything is written, and the error lists the names that exist.

contracts add rejecting an unknown event and succeeding on retry

The contract file

version: 1
trigger: Webhook
source:
  kind: vendor
  vendor: github
  events:
    - issues-opened
shape:
  schema: ../.workflow-tester/contracts/github.issues-opened.schema.json
  examples: ../.workflow-tester/contracts/github.issues-opened.examples.json

# overrides:
#   required: []
#   never: []
#   only: []

overrides is the only part you edit by hand.

OverrideTakesEffect
requiredPathsNever leave these fields out, even when the schema says they are optional
neverPathsLeave these fields, and everything under them, unchanged
onlyEvent namesGenerate cases for these events only

Paths are dotted, with [] for every element of an array and [n] for one.

2. Generate the cases

workflow-tester gen

Expected output:

workflows/issue-triage.json → github.issues-opened: 14 case(s) — 14 added, 0 retired, 0 unchanged (budget 14 for 4 nodes, 486 discarded)

Cases are written to .workflow-tester/cases/. Commit them.

What gets generated

Each case is a real vendor example with one or two things changed.

KindChange
optional-absentAn optional field is left out
nullable-nullA nullable field is null
oneOf-branchAnother branch of a oneOf
enum-valueAnother allowed value
array-cardinalityAn empty array, or one with several items
format-edgeAn empty string, unicode, 0, -1, a very large number

Only fields your workflow reads are varied.

3. Run them

workflow-tester run --only generated

run --only generated on GitHub issue payloads

On the sample workflow this ends with 10 passed, 3 failed, 1 warned. The workflow reads issue.assignee.login, and GitHub sends assignee: null when nobody is assigned. It also finds that issue.user can be null.

Keep a failing case

workflow-tester explain 11df5e3da2dee888
workflow-tester promote 11df5e3da2dee888 --name missing-assignee
CommandWhat it does
explain <caseId>Prints the case as a complete test file, payload included, with the result of its last run
promote <caseId>Copies the case into .workflow-tester/tests/ with a then: block to fill in, and stops gen from retiring it

Supported vendors

workflow-tester vendors list

Expected output:

vendor    coverage       spec version          events
github    schema         1.1.4                 10 of 270
stripe    schema         2026-08-26.dahlia     7 of 265
slack     nothing        —                     —

Slack publishes no schema for its event payloads. For Slack, or for a webhook of your own, write tests by hand.