Skip to content

Testing & CI

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.

  • 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.example to .env.test and adjust credentials as needed.
Terminal window
cd apps/whatsapp-web-server
cp .env.test.example .env.test
# edit .env.test if your database host/port differ

The test harness seeds deterministic data via @faker-js/faker so repeat runs produce identical values.

CommandPurpose
pnpm testRun the full suite once.
pnpm test:watchRe-run affected tests on changes.
pnpm test:coverageRun with V8 coverage and emit reports (text, html, lcov, json).
pnpm test:uiLaunch Vitest’s UI explorer.

To target a specific file or pattern:

Terminal window
pnpm test src/utils/logger.test.ts
pnpm test --grep "webhook processor"
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.ts
  • test/setup.ts — loads .env.test, bootstraps the MSW mock server, and resets shared state between specs.
  • test/helpers/db.ts — supplies getTestDb, truncateAllTables, and a typed withTransaction helper 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.).

The whatsapp-web-server handles incoming webhooks from Evolution API instances. To test subscription flows without external services, the project provides two complementary approaches:

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)
})

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 notification
  • QRCODE_UPDATED — QR code generation for instance pairing
  • CONNECTION_UPDATE — Connection state changes (open/connecting/close)
  • MESSAGES_UPSERT — New or sent messages
  • MESSAGES_UPDATE — Message status updates (delivered/read)
  • MESSAGES_DELETE — Message deletion events
  • CONTACTS_UPSERT — Contact additions or updates
  • CONTACTS_UPDATE — Contact information changes
  • PRESENCE_UPDATE — Online/typing/recording status
  • CHATS_UPDATE — Chat metadata changes
  • CHATS_UPSERT — Chat creation or updates
  • GROUPS_UPSERT — Group creation or updates
  • GROUPS_UPDATE — Group metadata changes
  • GROUP_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.

For interactive testing and debugging, use the mock-webhook CLI tool:

Terminal window
# 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-update

Features:

  1. Interactive Mode — Choose from 14 Evolution API event types using arrow keys
  2. Direct Mode — Send specific webhooks instantly with flags (ideal for development iteration)
  3. Realistic Payloads — Automatically generates faker-based test data
  4. HTTP Delivery — POSTs to the running whatsapp-web-server instance
  5. Detailed Feedback — Shows payload, response, and propagation status

Available Direct Flags:

All 14 webhook types support direct sending:

Terminal window
--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 changes

Configuration:

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-here

Webhook Flow Diagram:

Example Session (Interactive Mode):

Terminal window
$ 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):

Terminal window
$ 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:

ErrorSolution
Connection refusedStart whatsapp-web-server: pnpm --filter whatsapp-web-server dev
401 UnauthorizedCheck WHATSAPP_WEB_SERVER_API_KEY matches server configuration
400 Bad RequestVerify payload schema matches Evolution API webhook types
Unknown event typeUse exact flag names: --messages-upsert (not --messages_upsert)

To test the complete subscription flow from webhook receipt to client notification:

  1. Start the serverpnpm --filter whatsapp-web-server dev
  2. Run the CLIpnpm tsx scripts/mock-webhook.ts
  3. Select event — Choose a webhook type (e.g., “Messages Upsert”)
  4. 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

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.

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:

  1. Change detectiondetect-changes emits an array of modified workspaces; the component joins the test matrix only when touched.
  2. Secret resolution — the job maps apps/whatsapp-web-server to the WHATSAPP_WEB_SERVER_TEST_DATABASE_URL secret, which populates DATABASE_URL at runtime.
  3. Execution — the workflow runs pnpm run test:coverage, writes coverage artifacts, ensures coverage/lcov.info exists, and uploads results to Codecov if the token is available.
  4. Reports — with CI=true, Vitest emits coverage/test-report.junit.xml, enabling the Codecov test-results action to surface granular outcomes.
SecretPurpose
CODECOV_TOKENAuthenticates coverage and test-result uploads.
WHATSAPP_WEB_SERVER_TEST_DATABASE_URLPostgreSQL 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.

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.

  • Missing database secret — the CI run will fail before executing tests; add WHATSAPP_WEB_SERVER_TEST_DATABASE_URL in the repository secrets panel.
  • Connection refused locally — ensure PostgreSQL is running on the port defined in .env.test or update the URI accordingly.
  • Coverage regressions — run pnpm test:coverage, open coverage/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.
  1. Add or update tests alongside the source file (e.g., feature.ts -> feature.test.ts).
  2. Prefer seeded fixture builders over ad-hoc objects to keep values deterministic.
  3. Use withTransaction or truncateAllTables to keep database state isolated.
  4. Mock Evolution API behavior via evolutionApiServer.use(...) for scenario-specific responses.
  5. Run pnpm test:coverage locally before opening a PR; the CI job will match this execution path.

With these building blocks, contributors can confidently expand the whatsapp-web-server surface area while keeping coverage and CI feedback loops fast.