This directory contains all test files for the Webhook Debugger & Logger.
The test suite is organized into the following categories:
tests/unit/: Tests for individual modules and classes in isolation (e.g.,rate_limiter,config).tests/integration/: Tests verifying interactions between modules (e.g.,routes,middleware,lifecycle).tests/e2e/: Full end-to-end system tests covering real-world scenarios (e.g.,app.smoke,resilience,production.scenarios,webhook.lifecycle).tests/setup/: Shared helpers, mocks, and global setup logic.
Centralized mock registration. Import BEFORE any source code:
import { setupCommonMocks } from "../setup/helpers/mock-setup.js";
await setupCommonMocks({
axios: true,
apify: true,
dns: true,
db: true,
consts: true,
});apifyMock- Mock Apify ActoraxiosMock- Mock axiosdnsPromisesMock- Mock DNS resolutionssrfMock- Mock SSRF validationduckDbMock- Mock DuckDB instance/connectionconstsMock- Mocked application constantswebhookManagerMock- Mock for WebhookManagercreateMockWebhookManager()- WebhookManager mock factorycreateDatasetMock()- Dataset mock factoryfsPromisesMock- Mock fornode:fs/promiseslogRepositoryMock- Mock for LogRepositoryloggerMock- Mock for logger
createMockRequest()- Express Request mockcreateMockResponse()- Express Response mockcreateMockNextFunction()- Express NextFunction mockassertType<T>()- Type-safe casting helpergetLastAxiosCall(axios, method)- Get arguments of last axios callgetLastAxiosConfig(axios, method)- Get config object of last axios callwaitForCondition(condition, timeout, interval)- Poll for a condition (better than sleep)flushPromises(ticks)- Deterministic promise-queue drain helper
useMockCleanup()- Auto-clear mocks in beforeEachuseFakeTimers()- Auto-manage fake timersuseConsoleSpy()- Auto-manage console spies
setupTestApp()(app-utils.js) - Initialize app and supertest client; requires a realnode:fs/promises.mkdtemp()implementation because it allocates a uniqueAPIFY_LOCAL_STORAGE_DIRper bootresetDb()(db-hooks.js) - Clear DuckDB logs tablecreateStripeSignature(), etc. (signature-utils.js) - Webhook signature generatorscreateMiddlewareTestContext()(middleware-test-utils.js) - Middleware test setupdiscoverConstantModules()(constant-discovery.js) - Runtime-safe constant module discovery for ESM mocking
- Always use helpers instead of repeating setup code
- Import setupCommonMocks first in test files
- Use lifecycle helpers for beforeEach/afterEach patterns
- Avoid
@type {any}- useassertType<T>()or proper types - Keep tests isolated - use
useMockCleanup() - Place new tests in the appropriate subdirectory (
unit,integration, ore2e) - For lifecycle and worker-cleanup changes, add focused unit coverage for retry and failure paths first, then rerun
npm run test:stressto validate broader concurrency and shutdown behavior.
The following logs can appear during integration/e2e and coverage runs and are usually expected, not failures by themselves:
initialize() called again without a preceding shutdown()- Common when suites intentionally reinitialize app state across scenarios.
Shutting downwithTEST_COMPLETE- Expected teardown path in app harness and lifecycle tests.
Actor.pushData timeout after ...- Triggered intentionally in resilience/background-timeout paths.
- JSON parse warnings for malformed payloads
- Used by security/sanitation tests to verify fallback behavior.
Force exiting Jest...- Expected in coverage scripts that pass
--forceExitfor long-running suites.
- Expected in coverage scripts that pass
setupTestApp()resets the Jest module registry before importingsrc/main.jsso each integration test boot gets a fresh app instance instead of reusing previously registered routes or singleton runtime state.- The in-process integration harness still isolates
APIFY_LOCAL_STORAGE_DIRper test app boot; the module reset complements that filesystem isolation and prevents route/config leakage across repeated initialize/shutdown cycles in the same Jest worker. - In-process integration suites that call
setupTestApp()orstartIntegrationApp()should not enablesetupCommonMocks({ fs: true })unless they also provide a realmkdtemp()implementation. The harness now throws a clear error instead of silently accepting an invalid storage path. - Integration teardown also removes Actor event listeners and process signal handlers registered during app boot, so repeated lifecycle tests do not accumulate global listeners inside the same Jest worker.
- The spawned-process E2E harness treats child
closeevents as best-effort teardown signals so tests do not fail on benign close-listener race conditions during shutdown.
Treat these as failures only when they are accompanied by test assertion failures, non-zero coverage gate output, or unhandled exceptions.
# All tests
npm test
# Raw Jest entry (matches npm test internals)
npm run test:jest
# All Unit Tests
npm test tests/unit/
# All Integration Tests
npm test tests/integration/
# All E2E Tests
npm test tests/e2e/
# Specific file
npm test -- tests/unit/rate_limiter.test.js
# Watch mode
npm test -- --watch
# Coverage
npm test -- --coverage
# OR
npm run test:coverage
# Explicit staged coverage gates
npm run test:coverage:new-scopes
npm run coverage:check:new-scopes
npm run test:coverage:matrix
npm run coverage:check:matrix
# OR run all gates
npm run coverage:gate
# Note: coverage test commands use Jest --forceExit to guarantee
# automatic process termination in long-running integration/e2e suites.
# The scoped and full-matrix coverage commands also use --silent to
# reduce noisy logs and avoid terminal truncation in long runs.
# The default npm test command uses --detectOpenHandles and does not
# force-exit so open handles are surfaced during regular development.