Nock Back
Nock Back records HTTP interactions to fixture files and replays them in later test runs.
Setup
Set the fixture directory and mode before loading fixtures. Nock Back defaults to dryrun mode.
import nock from 'nock'
const nockBack = nock.back
nockBack.fixtures = './nockFixtures'
nockBack.setMode('record')Setup Properties
nockBack.fixtures: path to fixture directorynockBack.setMode(): the mode to use
Record and Replay a Fixture
In record mode, a missing fixture is recorded and written when nockDone() is called. In the default dryrun mode, an existing fixture is replayed, but a missing fixture is not recorded; unmatched requests are allowed to reach the network.
The promise API returns nockDone and a context with the loaded scopes:
const { nockDone, context } = await nockBack('example.json')
try {
await fetch('https://api.example.test/users')
context.assertScopesFinished()
} finally {
nockDone()
}The callback API is also available. Inside a regular (non-arrow) callback, this is the same context object:
nockBack('example.json', function (nockDone) {
fetch('https://api.example.test/users').finally(() => {
this.assertScopesFinished()
nockDone()
})
})Context
The context has these members:
scopes: the Nock scopes loaded from the fixture (empty when the fixture is being recorded)isLoaded: whether an existing fixture was loadedassertScopesFinished(): throws if any loaded interceptor was not usedquery(): returns a description of every loaded interceptor (see Inspecting and Verifying Fixtures)
Per-Fixture Options
Pass an options object as the second argument:
before: called for each fixture definition before it is converted to a scopeafter: called for each scope after it is createdafterRecord: receives recorded definitions and returns the definitions to write, or a string containing custom fixture contentrecorder: options passed to the recorder
Example: Normalize a Request Body
function normalizeScope(scope) {
scope.filteringRequestBody((body, aRecordedBody) => {
if (typeof body !== 'string' || typeof aRecordedBody !== 'string') {
return body
}
const recordedBodyResult = /timestamp:([0-9]+)/.exec(aRecordedBody)
if (recordedBodyResult) {
const recordedTimestamp = recordedBodyResult[1]
return body.replace(
/(timestamp):([0-9]+)/g,
(match, key, value) => `${key}:${recordedTimestamp}`,
)
} else {
return body
}
})
}
nockBack('exampleFixture.json', {
after: normalizeScope,
})Modes
To set the mode call nockBack.setMode(mode) or run the tests with the NOCK_BACK_MODE environment variable set before loading nock. If the mode needs to be changed programmatically, the following is valid: nockBack.setMode(nockBack.currentMode)
wild: send requests to the network without replaying or recording fixturesdryrun: the default; replay an existing fixture, allow network requests, and do not recordrecord: replay an existing fixture, or record requests to create it when it is missingupdate: remove the existing fixture and record a replacementlockdown: replay a fixture and block unmatched network requests without recording
Inspecting and Verifying Fixtures
context.query() returns the interceptor definitions loaded from a fixture. Each entry has method, uri, basePath, path, queries, counter, body, statusCode, and optional. It shows what the fixture contains; it does not by itself verify which requests your code made. context.assertScopesFinished() checks that all required interceptors from the loaded fixture were used.
INFO
context.query() is only populated for fixtures that were loaded for playback.
Use fixture inspection alongside normal assertions on the code under test:
import assert from 'node:assert/strict'
import nock from 'nock'
const { nockDone, context } = await nock.back('http-interaction.json')
try {
const response = await fetch('https://api.example.test/create/thing', {
method: 'POST',
})
assert.equal(response.status, 201)
context.assertScopesFinished()
const definitions = context.query()
assert.ok(definitions.some(({ method, path }) => method === 'POST' && path === '/create/thing'))
} finally {
nockDone()
}