Tips > Reliability & Performance

Build a Test Harness Workflow That Validates Your Main Workflow

For critical workflows that must not break, build a separate "test harness" workflow that sends known input to your main workflow's webhook, captures the out...

TipIntermediate2 min read

For critical workflows that must not break, build a separate "test harness" workflow that sends known input to your main workflow's webhook, captures the output, and verifies it matches expected results. Run this test harness after every change to the main workflow and on a schedule to catch regressions.

Real-world example: Your main workflow receives an order via webhook, processes it, and responds with a confirmation. The test harness sends a known order and checks the response.

{
  "nodes": [
    {
      "name": "Schedule Trigger",
      "type": "Schedule Trigger",
      "note": "Run tests daily at 06:00"
    },
    {
      "name": "Test Case 1 - Standard Order",
      "type": "HTTP Request",
      "parameters": {
        "method": "POST",
        "url": "https://n8n.example.com/webhook/order-processor",
        "sendBody": true,
        "bodyParameters": {
          "order_id": "TEST-001",
          "customer_email": "test@example.com",
          "items": [
            {"sku": "WIDGET-A", "quantity": 2, "price": 19.99}
          ]
        },
        "options": {
          "timeout": 30000
        }
      }
    },
    {
      "name": "Validate Response",
      "type": "Code",
      "note": "Check that the response matches expected output"
    },
    {
      "name": "Alert on Failure",
      "type": "Slack",
      "note": "Send alert if validation fails"
    }
  ]
}
```text
```javascript title="Code Node: Validate Response"
const response = $input.first().json;
const errors = [];

// Check HTTP status
if (response.statusCode !== 200) {
  errors.push(`Expected status 200, got ${response.statusCode}`);
}

// Check response body structure
const body = typeof response.body === 'string'
  ? JSON.parse(response.body)
  : response.body;

if (!body.confirmation_id) {
  errors.push("Missing confirmation_id in response");
}

if (body.status !== "processed") {
  errors.push(`Expected status "processed", got "${body.status}"`);
}

if (body.total !== 39.98) {
  errors.push(`Expected total 39.98, got ${body.total}`);
}

// Return test result
if (errors.length > 0) {
  return [{
    json: {
      test: "FAILED",
      errors: errors,
      response: body,
      timestamp: new Date().toISOString()
    }
  }];
} else {
  return [{
    json: {
      test: "PASSED",
      confirmation_id: body.confirmation_id,
      timestamp: new Date().toISOString()
    }
  }];
}
```text
> **Tip: Multiple Test Cases**
>
> Add parallel branches from the Schedule Trigger, each sending a different test case: standard order, empty cart, invalid SKU, duplicate order ID. Route all results through a final Merge node that compiles the test report.

A test harness turns workflow validation from a manual process into an automated check, catching regressions before they affect real users.

**Related:** [Always Set an Error Workflow on Every Production Workflow](../error-handling-and-reliability/01-always-set-an-error-workflow-on-every-production-workflow.md) | [Break Large Workflows into Sub-Workflows](../workflow-architecture/01-break-large-workflows-into-sub-workflows.md)

Want this running in your stack?

I build production n8n and Cloudflare automation for teams — the same engineering behind HarperFlow. Fixed-price, escrow-protected, US-based.