The Node.js client starts, controls, and stops a Mockly process from your JavaScript or TypeScript tests.
npm install --save-dev @dever-labs/mockly-driver
# or
yarn add --dev @dever-labs/mockly-driverThe Mockly binary is downloaded automatically for your platform when you run npm install. You can also trigger it manually:
npx mockly-installimport { MocklyServer } from '@dever-labs/mockly-driver'
const server = await MocklyServer.ensure()
await server.addMock({
id: 'get-user',
request: { method: 'GET', path: '/users/1' },
response: {
status: 200,
body: JSON.stringify({ id: 1, name: 'Alice' }),
headers: { 'Content-Type': 'application/json' },
},
})
// Point your service under test at server.httpBase
const res = await fetch(`${server.httpBase}/users/1`)
await server.stop()| Method | Description |
|---|---|
MocklyServer.ensure(opts?) |
Downloads the binary if not present, then starts the server. Recommended for most cases. |
MocklyServer.create(opts?) |
Starts using an already-installed binary. Throws if the binary is not found. |
Both retry up to 3 times on ephemeral port conflicts.
const server = await MocklyServer.ensure({
// Pre-load scenarios at startup
scenarios: [
{
id: 'payment-fail',
name: 'Payment Failure',
patches: [
{ mock_id: 'charge', status: 503, body: '{"error":"unavailable"}' },
],
},
],
// Override install location
binDir: '/opt/mockly',
})// Add a mock
await server.addMock({
id: 'get-orders',
request: {
method: 'GET',
path: '/orders',
headers: { Authorization: 'Bearer *' },
},
response: {
status: 200,
body: '[{"id":1}]',
headers: { 'Content-Type': 'application/json' },
delay: '100ms',
},
})
// Remove a mock
await server.deleteMock('get-orders')// Activate a pre-configured scenario
await server.activateScenario('payment-fail')
// Deactivate it
await server.deactivateScenario('payment-fail')// Add latency and override status codes on all requests
await server.setFault({
enabled: true,
delay: '500ms',
status_override: 503,
error_rate: 0.5, // 50% of requests
})
// Remove the fault
await server.clearFault()// Reset all dynamic mocks, active scenarios, and faults; keeps startup config
await server.reset()
// Kill the process
await server.stop()// tests/integration.test.ts
import { MocklyServer } from '@dever-labs/mockly-driver'
let server: MocklyServer
beforeAll(async () => {
server = await MocklyServer.ensure()
})
afterAll(async () => {
await server.stop()
})
beforeEach(async () => {
await server.reset() // isolate each test
})
test('returns user from mock', async () => {
await server.addMock({
id: 'get-user',
request: { method: 'GET', path: '/users/1' },
response: { status: 200, body: '{"id":1,"name":"Alice"}' },
})
const res = await fetch(`${server.httpBase}/users/1`)
expect(res.status).toBe(200)
})
test('handles 503 via scenario', async () => {
await server.addMock({
id: 'charge',
request: { method: 'POST', path: '/charge' },
response: { status: 200, body: '{"ok":true}' },
})
await server.activateScenario('payment-fail')
const res = await fetch(`${server.httpBase}/charge`, { method: 'POST' })
expect(res.status).toBe(503)
})// vitest.config.ts
import { defineConfig } from 'vitest/config'
export default defineConfig({ test: { globalSetup: './tests/setup.ts' } })
// tests/setup.ts
import { MocklyServer } from '@dever-labs/mockly-driver'
let server: MocklyServer
export async function setup() {
server = await MocklyServer.ensure()
process.env.MOCK_BASE = server.httpBase
}
export async function teardown() {
await server.stop()
}| Property | Description |
|---|---|
server.httpBase |
Base URL of the mock HTTP server, e.g. http://127.0.0.1:45123 |
server.apiBase |
Base URL of the management API, e.g. http://127.0.0.1:45124 |
server.httpPort |
Numeric HTTP port |
server.apiPort |
Numeric API port |
Mockly also ships a Docker-backed Node.js / TypeScript testcontainers module: @dever-labs/mockly-testcontainers.
Use it instead of the driver when you want Docker-managed lifecycle, no local binary download, and the same container image in local tests and CI.
npm i -D @dever-labs/mockly-testcontainers testcontainersimport assert from 'node:assert/strict'
import { MocklyContainerBuilder } from '@dever-labs/mockly-testcontainers'
const container = await new MocklyContainerBuilder().start()
try {
await container.addMock({
id: 'get-user',
request: { method: 'GET', path: '/users/1' },
response: { status: 200, body: '{"id":1}' },
})
const response = await fetch(`${container.getHttpBase()}/users/1`)
assert.equal(response.status, 200)
assert.equal(await response.text(), '{"id":1}')
} finally {
await container.stop()
}MocklyContainerBuilder.withInlineConfig(yaml)StartedMocklyContainer.getHttpBase()/getApiBase()addMock,deleteMock,resetactivateScenario,deactivateScenariosetFault,clearFault
- Node 18+
- Docker
See clients/node-testcontainers/README.md for the full module reference.