Testing & CI
How to run, extend, and debug the whatsapp-web-server test suite plus its CI integration.
Overview
The whatsapp-web-server workspace ships with a Vitest-based suite that exercises the Fastify entry points, webhook processor, utilities, and supporting helpers. All files currently sit at 100% statements, branches, lines, and functions. This page explains how to reproduce that locally, extend it with confidence, and how the repository CI runs the suite.
Local Environment
- Node.js: 22 (match the version pinned by the repo CI).
- Package manager:
pnpm, using the workspace lockfile. - Database: PostgreSQL instance dedicated to tests. The default connection string is
postgresql://postgres:postgres@127.0.0.1:5543/whatsapp_web_server_test. - Environment file: copy
.env.test.exampleto.env.testand adjust credentials as needed.
cd apps/whatsapp-web-server
cp .env.test.example .env.test
# edit .env.test if your database host/port differThe test harness seeds deterministic data via @faker-js/faker so repeat runs produce identical values.
Test Commands
| Command | Purpose |
|---|---|
pnpm test | Run the full suite once. |
pnpm test:watch | Re-run affected tests on changes. |
pnpm test:coverage | Run with V8 coverage and emit reports (text, html, lcov, json). |
pnpm test:ui | Launch Vitest’s UI explorer. |
To target a specific file or pattern:
pnpm test src/utils/logger.test.ts
pnpm test --grep "webhook processor"Project Structure
apps/whatsapp-web-server/
├── src/
│ ├── handlers/
│ ├── plugins/
│ ├── services/
│ └── utils/
├── test/
│ ├── helpers/
│ │ ├── db.ts
│ │ ├── evolution-api-mock.ts
│ │ ├── fixtures.ts
│ │ └── assertions.ts
│ └── setup.ts
└── vitest.config.tsKey Helpers
test/setup.ts— loads.env.test, bootstraps the MSW mock server, and resets shared state between specs.test/helpers/db.ts— suppliesgetTestDb,truncateAllTables, and a typedwithTransactionhelper that always rolls back.test/helpers/evolution-api-mock.ts— MSW handlers covering instance management, messaging, contact fetches, and error scenarios, matching the Evolution API contract.test/helpers/fixtures.ts— deterministic builders for instances, contacts, messages, chats, groups, webhooks, QR codes, and credentials.test/helpers/assertions.ts— domain-focused matchers (JID formatting, webhook responses, timestamps, etc.).
Webhook Subscription Testing
The whatsapp-web-server handles incoming webhooks from Evolution API instances. To test subscription flows without external services, the project provides two complementary approaches:
MSW Webhook Handlers (Automated Testing)
Located in test/msw/webhook-handlers.ts, these MSW handlers intercept webhook HTTP requests during Vitest test runs:
import { webhookHandlers } from '../test/msw'
import { server } from '../src/mocks/server'
// In your test file
test('processes messages.upsert webhook', async () => {
// The MSW server is already configured in test/setup.ts
const response = await fetch('http://localhost/api/webhook/messages.upsert/test-instance', {
method: 'POST',
body: JSON.stringify(webhookPayload)
})
expect(response.ok).toBe(true)
})Webhook Payload Factories
All webhook payloads are generated using deterministic faker-based factories in test/msw/webhook-payload-factories.ts:
import { webhookFactories, configureSeed } from '../test/msw/webhook-payload-factories'
// Generate a deterministic payload
configureSeed(12345)
const messagesUpsertPayload =
webhookFactories[EvolutionWebhookEventType.MESSAGES_UPSERT]('test-instance')
// Override specific fields
const customPayload = webhookFactories[EvolutionWebhookEventType.MESSAGES_UPSERT]('test-instance', {
data: {
message: { conversation: 'Custom message text' }
}
})Available Factory Functions:
APPLICATION_STARTUP— Evolution API startup notificationQRCODE_UPDATED— QR code generation for instance pairingCONNECTION_UPDATE— Connection state changes (open/connecting/close)MESSAGES_UPSERT— New or sent messagesMESSAGES_UPDATE— Message status updates (delivered/read)MESSAGES_DELETE— Message deletion eventsCONTACTS_UPSERT— Contact additions or updatesCONTACTS_UPDATE— Contact information changesPRESENCE_UPDATE— Online/typing/recording statusCHATS_UPDATE— Chat metadata changesCHATS_UPSERT— Chat creation or updatesGROUPS_UPSERT— Group creation or updatesGROUPS_UPDATE— Group metadata changesGROUP_PARTICIPANTS_UPDATE— Group membership changes
All factories follow the type definitions in src/types/evolution-webhooks.ts and are validated with 25+ Vitest tests in test/msw/webhook-payload-factories.test.ts.
Mock Webhook CLI (Manual Testing)
For interactive testing and debugging, use the mock-webhook CLI tool:
# Interactive mode - arrow-key selection
cd apps/whatsapp-web-server
pnpm mock:webhook
# Direct mode - for quick iteration (no interaction needed)
pnpm mock:webhook --messages-upsert
pnpm mock:webhook --qrcode-updated
pnpm mock:webhook --connection-updateFeatures:
- Interactive Mode — Choose from 14 Evolution API event types using arrow keys
- Direct Mode — Send specific webhooks instantly with flags (ideal for development iteration)
- Realistic Payloads — Automatically generates faker-based test data
- HTTP Delivery — POSTs to the running whatsapp-web-server instance
- Detailed Feedback — Shows payload, response, and propagation status
Available Direct Flags:
All 14 webhook types support direct sending:
--application-startup # Evolution API startup notification
--qrcode-updated # QR code generation for pairing
--connection-update # Connection state changes
--messages-upsert # New or sent messages
--messages-update # Message status updates
--messages-delete # Message deletion events
--contacts-upsert # Contact additions/updates
--contacts-update # Contact information changes
--presence-update # Online/typing/recording status
--chats-update # Chat metadata changes
--chats-upsert # Chat creation/updates
--groups-upsert # Group creation/updates
--groups-update # Group metadata changes
--group-participants-update # Group membership changesConfiguration:
The tool uses .env file automatically when invoked via pnpm mock:webhook:
# apps/whatsapp-web-server/.env
WHATSAPP_WEB_SERVER_URL=http://localhost:3001/webhooks/evolution
WHATSAPP_WEB_SERVER_API_KEY=your-api-key-hereWebhook Flow Diagram:
Example Session (Interactive Mode):
$ pnpm mock:webhook
🔧 WhatsApp Webhook Mock CLI
============================
This tool sends mock webhook payloads to whatsapp-web-server for testing.
Target URL: http://localhost:3001/webhooks/evolution
? Select a webhook event to send:
❯ Messages Upsert - New message received or sent
📤 Sending messages.upsert webhook to http://localhost:3001/webhooks/evolution/messages-upsert...
📦 Payload:
{
"event": "messages.upsert",
"instance": "mock-instance",
"data": {
"key": {
"remoteJid": "5511987654321@s.whatsapp.net",
"fromMe": false,
"id": "3EB0C4F4B6E8..."
},
"message": {
"conversation": "Hello, world!"
},
"messageTimestamp": 1697654321
},
"sender": "5511987654321@s.whatsapp.net"
}
✅ Webhook delivered successfully!
� Response:
{
"success": true,
"message": "messages.upsert webhook processed successfully",
"timestamp": "2025-10-14T02:50:08.123Z"
}
�💡 The webhook has been processed by whatsapp-web-server and should propagate to the client via WebSocket.Example Session (Direct Mode):
$ pnpm mock:webhook --messages-upsert
🚀 Direct send: messages.upsert
📤 Sending messages.upsert webhook to http://localhost:3001/webhooks/evolution/messages-upsert...
✅ Webhook delivered successfully!Troubleshooting:
| Error | Solution |
|---|---|
Connection refused | Start whatsapp-web-server: pnpm --filter whatsapp-web-server dev |
401 Unauthorized | Check WHATSAPP_WEB_SERVER_API_KEY matches server configuration |
400 Bad Request | Verify payload schema matches Evolution API webhook types |
Unknown event type | Use exact flag names: --messages-upsert (not --messages_upsert) |
Testing Subscription Flow End-to-End
To test the complete subscription flow from webhook receipt to client notification:
- Start the server —
pnpm --filter whatsapp-web-server dev - Run the CLI —
pnpm tsx scripts/mock-webhook.ts - Select event — Choose a webhook type (e.g., "Messages Upsert")
- Verify propagation — Check that the WebSocket client receives the event
This workflow validates:
- Webhook endpoint authentication
- Payload validation and parsing
- Event emission from WebhookProcessor
- WebSocket propagation to connected clients
- Client-side subscription handling
Coverage & Thresholds
Vitest enforces per-file thresholds from vitest.config.ts:
- Lines, statements, functions, branches ≥ 95%
Because the suite currently exercises every branch, the actual coverage sits at 100% across all tracked files. Exclusions intentionally skip test files, generated outputs, configuration files, TRPC wiring, and schema definitions.
The HTML report (coverage/index.html) highlights any future regressions, while coverage/lcov.info powers Codecov uploads.
CI Integration
The primary workflow lives in .github/workflows/ci.yml and uses reusable change-detection/matrix jobs to limit work to touched workspaces. whatsapp-web-server participates in the test-coverage job with these characteristics:
- Change detection —
detect-changesemits an array of modified workspaces; the component joins the test matrix only when touched. - Secret resolution — the job maps
apps/whatsapp-web-serverto theWHATSAPP_WEB_SERVER_TEST_DATABASE_URLsecret, which populatesDATABASE_URLat runtime. - Execution — the workflow runs
pnpm run test:coverage, writes coverage artifacts, ensurescoverage/lcov.infoexists, and uploads results to Codecov if the token is available. - Reports — with
CI=true, Vitest emitscoverage/test-report.junit.xml, enabling the Codecov test-results action to surface granular outcomes.
Required Secrets
| Secret | Purpose |
|---|---|
CODECOV_TOKEN | Authenticates coverage and test-result uploads. |
WHATSAPP_WEB_SERVER_TEST_DATABASE_URL | PostgreSQL connection string used during CI runs. |
Any additional service-specific secrets (Redis, Evolution API, etc.) can be wired in via the same switch statement in the workflow if future tests need them.
Temporary Debug Mode
During debugging sessions we occasionally disable non-test jobs in ci.yml by wrapping their if: expressions with false. When doing so, remember to restore the original conditions before merging to keep the pipeline comprehensive.
Troubleshooting
- Missing database secret — the CI run will fail before executing tests; add
WHATSAPP_WEB_SERVER_TEST_DATABASE_URLin the repository secrets panel. - Connection refused locally — ensure PostgreSQL is running on the port defined in
.env.testor update the URI accordingly. - Coverage regressions — run
pnpm test:coverage, opencoverage/index.html, and address highlighted lines or adjust exclusions only if intentional. - MSW mismatch — if a request is not intercepted, double-check the handler URL and HTTP method in
evolution-api-mock.ts. - Flaky timers — hook timeouts default to 30 seconds in
vitest.config.ts; raise them for slower integration specs.
Extending the Suite
- Add or update tests alongside the source file (e.g.,
feature.ts→feature.test.ts). - Prefer seeded fixture builders over ad-hoc objects to keep values deterministic.
- Use
withTransactionortruncateAllTablesto keep database state isolated. - Mock Evolution API behavior via
evolutionApiServer.use(...)for scenario-specific responses. - Run
pnpm test:coveragelocally before opening a PR; the CI job will match this execution path.
Related Resources
ci.ymlworkflow — Full matrix-based pipeline description.- Evolution API mock reference:
test/helpers/evolution-api-mock.ts - DB helper reference:
test/helpers/db.ts
With these building blocks, contributors can confidently expand the whatsapp-web-server surface area while keeping coverage and CI feedback loops fast.