workflow-tester

Find the payloads that break your n8n workflow before someone sends them. When a webhook arrives with a field set to null or an optional object missing, n8n turns the broken expression into undefined and shows no error. workflow-tester runs your workflow's expressions against those payloads and tells you which ones break and where. It runs offline, with no n8n instance.

workflow-tester finding an expression that resolves to undefined, then passing after a one-line fix

Installation

Requires Node.js 24 or newer.

Run it without installing:

npx workflow-tester --help

Add it to a project:

npm install --save-dev workflow-tester

Build from source:

git clone https://github.com/LudwigGerdes/workflow-tester.git
cd workflow-tester
pnpm install && pnpm build

Getting started

Set up a project:

npx workflow-tester init

This creates:

.workflow-tester/
├── README.md
└── tests/
    └── example.test.yaml

Download a sample sign-up workflow and a test file with three cases, then run them:

curl -L --create-dirs -o workflows/signup.json https://raw.githubusercontent.com/LudwigGerdes/workflow-tester/main/docs/demo/signup.json
curl -L -o .workflow-tester/tests/signup.test.yaml https://raw.githubusercontent.com/LudwigGerdes/workflow-tester/main/docs/demo/signup.test.yaml
npx workflow-tester run

Expected output:

workflows/signup.json
  ✗ no profile object, flat name — the ?? gotcha  1 expectation(s) fail
      ✗ node.Normalize.output[0].json.name: expected "Bob", got undefined
      ! "profile" is not produced here  at Normalize → assignments.assignments[1].value
      ! "plan" is not produced here  at Normalize → assignments.assignments[2].value
  ! no email at all  every expectation held
      ! "email" is not produced here  at Normalize → assignments.assignments[0].value
      ! "profile" is not produced here  at Normalize → assignments.assignments[1].value
      ! "plan" is not produced here  at Normalize → assignments.assignments[2].value
      ! "email" is not produced here  at Normalize → assignments.assignments[3].value
  ✓ pro user with nested profile

1 passed, 1 failed, 1 warned in 354ms

The first case fails because the workflow reads $json.body.profile.first_name when there is no profile.

Usage

Write a test by hand, in .workflow-tester/tests/:

workflow: ../../workflows/signup.json
cases:
  - id: flat-name
    when:
      trigger: webhook
      payload:
        email: bob@example.com
        name: Bob
    then:
      node.Normalize.output[0].json.name: Bob

Run every test:

workflow-tester run

Generate tests from the payloads GitHub or Stripe can send:

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

Turn a run you already made in n8n into a test:

workflow-tester capture workflows/invoice.json --execution execution.json

Report in a format your CI understands:

workflow-tester run --format junit