- Nx 22.7 monorepo (pnpm 11.1, TypeScript 5.9, Node 24) - apps/api: NestJS 11 (CJS conforme CODING-RULES.md PGD-DB-004) - apps/web: React 19 + Vite 8 (ESM) - libs/shared/api-interface: Zod contract base - Docker Compose dev: Postgres 18, Valkey 8, MinIO, Mailpit - WDS artifacts: - design-artifacts/A-Product-Brief/ (5 docs canônicos + 16 dialogs) - design-artifacts/B-Trigger-Map/ (hub + 4 personas + feature impact) - Stack canon: STACK.md v2.2 + CODING-RULES.md v2.0 + brand.md - AGENTS.md + README.md como entrada para devs/agentes Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3.1 KiB
3.1 KiB
Webhook Testing Fundamentals
Principle
Webhook delivery is eventually consistent — your application fires HTTP callbacks asynchronously after events occur. Tests must poll until the expected webhook arrives or time out. The @seontechnologies/playwright-utils webhook module provides deterministic polling, typed matchers, rich timeout diagnostics, and cleanup strategies safe under fullyParallel: true.
Rationale
Webhook tests fail for four structural reasons:
- Eventually consistent: Webhook delivery happens asynchronously — you cannot assert immediately after triggering an event
- Parallel journal pollution: When multiple workers share the same mock server, a fast worker's teardown can delete records a slow worker is still polling
- Opaque timeouts: A bare timeout tells you only that the webhook didn't arrive — it shows you nothing about what did arrive
- Cleanup drift: Resetting the full journal in
afterEachcreates a race condition underfullyParallel: true
The playwright-utils approach:
- Polling via
recurse: Uses Playwright'sexpect.pollunder the hood — retries with configurable timeout and interval until a match is found - Typed matchers:
matchField,matchPartial,matchPredicate— all must pass (AND semantics); matchers never throw on missing paths - Rich timeout errors:
WebhookTimeoutErrorcarriestotalReceived,receivedWebhooks, andmatcherDetailsso you can see what arrived vs. what was expected - Isolation via
startedAt: EachWebhookRegistryinstance records its creation timestamp; polling only fetches webhooks received after that point, preventing leakage from prior tests - Two cleanup strategies:
full-reset(resets entire journal) andmatched-only(deletes only matched webhooks — parallel-safe when the provider supports delete-by-ID, e.g. WireMock)
When to Use Webhook Tests
| Scenario | Use webhook tests |
|---|---|
| Application publishes events to external subscribers | ✅ Required |
| Event-driven architecture with Kafka/event bus → webhook delivery | ✅ Required |
| Payment, order, or notification side effects via webhooks | ✅ Required |
| Testing that a webhook was NOT delivered | ✅ Verify via timeout |
| Polling a status endpoint for eventual consistency | ❌ Use recurse directly |
| Frontend receiving push notifications (WebSocket) | ❌ Different mechanism |
Related Fragments
webhook-module-setup.md— Fixture wiring and cleanup strategieswebhook-template-matchers.md— matchField, matchPartial, matchPredicatewebhook-waiting-querying.md— waitFor, waitForCount, getReceived, drain patternwebhook-timeout-error.md— WebhookTimeoutError debuggingwebhook-providers.md— WireMock, MockServer, Mockoon, custom providerwebhook-risk-guidance.md— Risk-based guidance for TA and TD capabilities