NexisChat Docs
WhatsApp Web Server

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.example to .env.test and adjust credentials as needed.
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.

Test Commands

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:

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.ts

Key Helpers

  • 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.).

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

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

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

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

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)

Testing Subscription Flow End-to-End

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

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:

  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.

Required Secrets

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.

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_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.

Extending the Suite

  1. Add or update tests alongside the source file (e.g., feature.tsfeature.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.