WireMock Captain
WireMock Captain is a Node.js library (supporting TypeScript and JavaScript) designed to simplify integration testing of HTTP APIs by providing a programmatic interface to the WireMock simulator. Currently at version 4.1.3, this library is actively maintained and used in commercial products, emphasizing a stable release cadence. Its core differentiator lies in offering a native TypeScript/JavaScript experience for configuring and interacting with the Java-based WireMock service, which typically runs in a Docker container. This approach bypasses the limitations of in-process mocks (which often lack real-world accuracy) and the complexities of testing against live non-production service instances, providing a fast, full-featured, and debuggable solution for API mocking without requiring Java tooling for the test runner.
Common errors
-
connect ECONNREFUSED 127.0.0.1:8080
cause WireMock Docker container is not running or is not accessible on the specified host and port (e.g., `http://localhost:8080`).fixStart the WireMock Docker container: `docker run -itd --rm -p 8080:8080 --name my-mocked-service wiremock/wiremock:3.9.1`. Verify the `wiremockEndpoint` in your tests matches the running WireMock service. -
TypeError: Class constructor WireMock cannot be invoked without 'new'
cause Attempted to call `WireMock` as a function (e.g., `WireMock(endpoint)`) instead of instantiating it with `new`.fixInstantiate the `WireMock` class using the `new` keyword: `const mock = new WireMock(wiremockEndpoint);`. -
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: ...wiremock-captain/dist/index.js
cause Attempting to import `wiremock-captain` using CommonJS `require()` syntax in an ESM-only context, or in a project configured for ESM.fixUpdate your import statements to use ES module syntax: `import { WireMock } from 'wiremock-captain';`. Ensure your `package.json` has `"type": "module"` if you intend to use ESM globally, or name your files `.mjs`.
Warnings
- gotcha WireMock Captain requires an external WireMock instance to be running, typically in a Docker container (e.g., `docker run -p 8080:8080 wiremock/wiremock:3.9.1`). It does not bundle or manage the WireMock server itself. Failure to start WireMock will result in connection errors.
- breaking The underlying WireMock Java library (which WireMock Captain interacts with) has undergone significant changes in its 4.x beta releases, including breaking API changes, refactoring of core dependencies, and changes to HTTP header normalization. While WireMock Captain abstracts many of these, direct interactions with WireMock's API via its JSON DSL or specific features might require adjustments.
- gotcha The library specifies Node.js engine requirement `>=22.11.0`. Using older Node.js versions might lead to compatibility issues or unexpected runtime errors, particularly with modern JavaScript features or module resolution.
Install
-
npm install wiremock-captain -
yarn add wiremock-captain -
pnpm add wiremock-captain
Imports
- WireMock
const { WireMock } = require('wiremock-captain');import { WireMock } from 'wiremock-captain'; - IWireMockRequest
import { IWireMockRequest } from 'wiremock-captain';import type { IWireMockRequest } from 'wiremock-captain'; - IWireMockResponse
import { IWireMockResponse } from 'wiremock-captain';import type { IWireMockResponse } from 'wiremock-captain';
Quickstart
import { WireMock } from 'wiremock-captain';
import axios from 'axios'; // Example HTTP client
describe('API Integration Test with WireMock Captain', () => {
const wiremockEndpoint = 'http://localhost:8080';
let mock: WireMock;
// Ensure WireMock Docker container is running before tests
// docker run -itd --rm -p 8080:8080 --name mocked-service wiremock/wiremock:3.9.1
beforeAll(() => {
mock = new WireMock(wiremockEndpoint);
});
beforeEach(async () => {
await mock.resetAll(); // Clear all previous stubs and scenarios
});
afterAll(async () => {
await mock.resetAll();
// Optionally, stop the WireMock container if managed by the test runner
// e.g., using 'docker stop mocked-service'
});
test('should mock a GET request and receive the predefined response', async () => {
const request = {
method: 'GET',
endpoint: '/api/resource/123',
headers: { 'Accept': 'application/json' }
};
const mockedResponse = {
status: 200,
body: { id: '123', name: 'Mocked Resource' },
headers: { 'Content-Type': 'application/json' }
};
await mock.register(request, mockedResponse);
const response = await axios.get(`${wiremockEndpoint}/api/resource/123`);
expect(response.status).toBe(200);
expect(response.data).toEqual({ id: '123', name: 'Mocked Resource' });
// Verify WireMock received the request (optional but good practice)
const receivedRequests = await mock.getAllRequests();
expect(receivedRequests.length).toBe(1);
expect(receivedRequests[0].url).toContain('/api/resource/123');
});
test('should handle a POST request with specific body matching', async () => {
const postRequest = {
method: 'POST',
endpoint: '/api/items',
body: { item: 'new item' }
};
const postResponse = {
status: 201,
body: { message: 'Item created' },
headers: { 'Content-Type': 'application/json' }
};
await mock.register(postRequest, postResponse);
const response = await axios.post(`${wiremockEndpoint}/api/items`, { item: 'new item' });
expect(response.status).toBe(201);
expect(response.data).toEqual({ message: 'Item created' });
});
});