# Testing Policy (mandatory)

A build or change is NOT done until the workflow has been EXECUTED on the
user's instance and the execution INSPECTED node by node.
`awesomate_n8n_deploy {action:'validate'}` checks structure, not behaviour —
a passing validate plus a green final status is never "tested".

Applies to: new builds (SKILL.md Phase 5), the upgrade loop (test the draft
AND re-verify after promote), and any fix to a failing workflow. Only
exception: the user explicitly waives testing for that specific task.

## How a test runs

There is no manual or pin-data execution on this platform. E2E = activate +
production webhook + poll executions:

1. Get approval to go live, then
   `awesomate_n8n_deploy {action:'activate', workflowId}` — production
   webhooks only respond while the workflow is active.
2. `awesomate_n8n_test {workflowId, payload}` — fires the PRODUCTION webhook
   with the `X-Awesomate-Test` header; returns the webhook response plus the
   `executionId` it caused. Real side effects DO run: emails actually send.
   Address them to the user's own email, prefix subjects `[TEST]`, use
   obviously fake data (`test+<runId>@…`, "TEST SUBMISSION"), and tell the
   user before firing. Non-email side effects (CRM writes, payments, SMS):
   STOP and ask first.
3. Inspect: `awesomate_n8n_executions {executionId, debug: true}` — read the
   node list, per-node output, and which branches ran. When consent is off,
   debug data is unavailable and the call falls back to the non-debug
   detail (final status + failing node only) — state that in the report;
   you inspected less than usual.

A green final status is not inspection. Do not enable
`saveExecutionProgress` to get richer data — the hub enforces it FALSE
(write-amplification incident); `debug: true` is the inspection path.

## Fixtures (payload classes)

The payload passed to `awesomate_n8n_test` is the POST body — the workflow
sees it at `$json.body`. Run at minimum one of each class:

| Class | Payload |
|---|---|
| happy-path | Realistic valid input, obviously fake values |
| empty | `{}` / missing fields entirely |
| malformed | Wrong types, missing required fields, junk strings |
| error-`<api>` | Input that drives a named upstream API to a realistic error (nonexistent id → 404, bad enum → 400) — one per external dependency |

Quota: `limits` from `awesomate_n8n_context` caps daily test fires. Plan
the fixture set before burning tests; a 429 `quota_exceeded` means the
day's cap — tell the user, never retry-loop.

## Error-path testing (required, minimum 3)

1. Failed upstream call (error-`<api>` fixture)
2. Empty payload
3. Malformed payload

Verify `onError` branches ACTUALLY ROUTE: in the execution's node list,
confirm the error path's nodes ran and the post-failure happy-path nodes
did not. Final status alone proves nothing — an execution whose error
branch routed can still finish green.

## Multi-trigger gotcha

`awesomate_n8n_test` reaches the webhook trigger only. A schedule (or any
non-webhook) branch NEVER runs from a test fire — it is untested unless
exercised deliberately:

- Draft phase: temporarily wire the branch behind a webhook trigger via
  `awesomate_n8n_deploy {action:'update_draft'}`, test-fire it, then
  REMOVE the temporary trigger before promote.
- Never promote or leave live a workflow carrying a temporary test
  trigger — it is a world-callable production URL.
- If the branch cannot be exercised this way, list it under "needs human"
  in the report. Do not report it as tested.

## What Claude cannot verify → human checklist

List explicitly, per test run:

- Real side effects landing (the `[TEST]` email in their inbox, the CRM
  record, the SMS)
- OAuth/credential-gated calls that could not be exercised
- External services actually pointing at the production webhook URL
- Schedule/non-webhook branches that never fired (see above)

Ask the user to confirm each ("check your inbox for [TEST] …") and record
their answer in the report.

## Test Report (required in every handoff)

```
## Test Report — <workflow> @ <instance>
Executed: <executionIds + payload class for each>
Inspection: debug / non-debug fallback (consent off)
Passed: <node paths verified, outputs checked>
Error paths: <fixture → which branch routed → result>
Not verifiable by Claude (needs human): <list + why>
Post-test state: restored ✔ (checklist below)
```

## Post-test state restore

- [ ] Temporary test triggers/nodes removed from drafts
- [ ] Test drafts deactivated; deleted via
      `awesomate_n8n_deploy {action:'delete_draft'}` unless the user wants
      them kept
- [ ] `[TEST]` rows written to datatables during tests cleaned up
      (`awesomate_n8n_datatable_write {action:'delete_rows'}`)
- [ ] Live workflow's activation state matches what the user expects
- [ ] After a promote: the ORIGINAL production URL re-verified with a test
      fire (promote preserves webhookIds — the old URL must still respond)
- [ ] User told which `[TEST]` artifacts (emails, records) to expect and
      discard
