HTTP server mocking and expectations library for Node.js testing environments
67
This document covers nock's recording functionality, which captures real HTTP traffic and converts it into fixtures that can be replayed in tests.
The recorder provides methods to capture HTTP traffic and convert it to nock definitions.
interface Recorder {
rec(options?: boolean | RecorderOptions): void;
clear(): void;
play(): string[] | Definition[];
}
const recorder: Recorder;
function restore(): void;recorder.rec(options?: boolean | RecorderOptions): void;Start recording HTTP traffic:
const nock = require("nock");
// Start recording with default options
nock.recorder.rec();
// Make real HTTP requests - these will be recorded
const response = await fetch("https://api.example.com/users");
const data = await response.json();
// Stop recording and get the recorded fixtures
const fixtures = nock.recorder.play();
console.log(fixtures);// Record with logging enabled
nock.recorder.rec(true);
// Record without logging
nock.recorder.rec(false);interface RecorderOptions {
dont_print?: boolean;
output_objects?: boolean;
enable_reqheaders_recording?: boolean;
logging?: (content: string) => void;
use_separator?: boolean;
}Control whether recorded fixtures are automatically logged to console:
// Don't print fixtures automatically (default: false)
nock.recorder.rec({ dont_print: true });
// Make requests...
const fixtures = nock.recorder.play(); // Get fixtures manuallyControl the format of recorded fixtures:
// Output as JavaScript objects (default: false, outputs as strings)
nock.recorder.rec({ output_objects: true });
// Make requests...
const fixtures = nock.recorder.play();
// fixtures will be Definition[] instead of string[]Include request headers in recorded fixtures:
nock.recorder.rec({ enable_reqheaders_recording: true });
// The recorded fixtures will include the headers sent in requestsExample output with headers:
nock("https://api.example.com")
.get("/users")
.matchHeader("authorization", "Bearer token123")
.matchHeader("user-agent", "Node.js")
.reply(200, [{ id: 1, name: "Alice" }]);Provide a custom logging function:
const fs = require("fs");
nock.recorder.rec({
logging: (content) => {
// Write to file instead of console
fs.appendFileSync("./recorded-fixtures.js", content + "\n");
}
});Add separators between recorded fixtures:
nock.recorder.rec({ use_separator: true });
// Output will include separator comments between fixtures:
// <<<<<<-- cut here -->>>>>>recorder.clear(): void;Clear all recorded fixtures without stopping recording:
nock.recorder.rec();
// Make some requests...
console.log(nock.recorder.play().length); // e.g., 3
// Clear recorded data
nock.recorder.clear();
console.log(nock.recorder.play().length); // 0
// Continue recording new requests...recorder.play(): string[] | Definition[];Get recorded fixtures and optionally stop recording:
// Get fixtures as strings (default)
const stringFixtures = nock.recorder.play();
console.log(stringFixtures[0]);
// Output: 'nock("https://api.example.com").get("/users").reply(200, [...]);'
// Get fixtures as objects
nock.recorder.rec({ output_objects: true });
// Make requests...
const objectFixtures = nock.recorder.play();
console.log(objectFixtures[0]);
// Output: { scope: "https://api.example.com", method: "GET", path: "/users", ... }function restore(): void;Stop recording and restore original HTTP behavior:
nock.recorder.rec();
// Make requests...
// Stop recording and restore normal HTTP
nock.restore();
// HTTP requests will now behave normally (not recorded)When using output_objects: true, recordings return Definition objects:
interface Definition {
scope: string | RegExp;
path: string | RegExp;
port?: number | string;
method?: string;
status?: number;
body?: RequestBodyMatcher;
reqheaders?: Record<string, RequestHeaderMatcher>;
response?: ReplyBody;
headers?: ReplyHeaders;
options?: Options;
}nock.recorder.rec({ output_objects: true });
// Make a request
await fetch("https://api.example.com/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "Alice" })
});
const definitions = nock.recorder.play();
console.log(definitions[0]);
// Output:
// {
// scope: "https://api.example.com:443",
// method: "POST",
// path: "/users",
// body: '{"name":"Alice"}',
// status: 201,
// response: '{"id":1,"name":"Alice"}',
// headers: { "content-type": "application/json" }
// }
// Convert back to nock interceptors
const scopes = nock.define(definitions);const nock = require("nock");
const fs = require("fs");
async function recordAPIInteractions() {
// Start recording with comprehensive options
nock.recorder.rec({
output_objects: true,
enable_reqheaders_recording: true,
dont_print: true
});
try {
// Make real API calls
const response1 = await fetch("https://api.example.com/users");
const users = await response1.json();
const response2 = await fetch("https://api.example.com/users/1");
const user = await response2.json();
const response3 = await fetch("https://api.example.com/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "Bob" })
});
const newUser = await response3.json();
} finally {
// Get recorded fixtures
const definitions = nock.recorder.play();
// Save to file
const fixtures = JSON.stringify(definitions, null, 2);
fs.writeFileSync("./test/fixtures/api-fixtures.json", fixtures);
// Stop recording
nock.restore();
}
}const nock = require("nock");
const fixtures = require("./fixtures/api-fixtures.json");
describe("API Tests with Recorded Fixtures", () => {
beforeEach(() => {
// Load recorded fixtures
nock.define(fixtures);
});
afterEach(() => {
nock.cleanAll();
});
it("should get users list", async () => {
// This will use the recorded response
const response = await fetch("https://api.example.com/users");
const users = await response.json();
expect(Array.isArray(users)).toBe(true);
});
});// Only record in development mode
if (process.env.NODE_ENV === "development") {
nock.recorder.rec({
output_objects: true,
logging: (content) => {
console.log("Recorded fixture:", content);
}
});
}nock.recorder.rec({ output_objects: true });
// Make various requests...
const allDefinitions = nock.recorder.play();
// Filter to only record API calls to specific domain
const apiDefinitions = allDefinitions.filter(def =>
def.scope.includes("api.example.com")
);
// Save filtered definitions
nock.define(apiDefinitions);const processedFixtures = [];
nock.recorder.rec({
output_objects: true,
dont_print: true,
logging: (content) => {
// Process each fixture as it's recorded
try {
const definition = JSON.parse(content);
// Remove sensitive headers
if (definition.reqheaders) {
delete definition.reqheaders.authorization;
delete definition.reqheaders.cookie;
}
// Sanitize response data
if (definition.response && typeof definition.response === "string") {
const response = JSON.parse(definition.response);
if (response.email) {
response.email = "user@example.com"; // Sanitize email
}
definition.response = JSON.stringify(response);
}
processedFixtures.push(definition);
} catch (e) {
// Handle non-JSON fixtures
processedFixtures.push(content);
}
}
});// jest.setup.js
const nock = require("nock");
// Global setup for recording
global.startRecording = (options = {}) => {
nock.recorder.rec({
output_objects: true,
dont_print: true,
...options
});
};
global.stopRecording = () => {
const fixtures = nock.recorder.play();
nock.restore();
return fixtures;
};
// jest.teardown.js
afterEach(() => {
if (nock.recorder.play().length > 0) {
nock.restore();
}
nock.cleanAll();
});const nock = require("nock");
describe("API Tests", () => {
let recordedFixtures = [];
before(() => {
// Start recording for entire test suite
nock.recorder.rec({ output_objects: true });
});
after(() => {
// Save all recorded fixtures
recordedFixtures = nock.recorder.play();
nock.restore();
// Optionally save to file
if (process.env.SAVE_FIXTURES) {
const fs = require("fs");
fs.writeFileSync(
"./test/recorded-fixtures.json",
JSON.stringify(recordedFixtures, null, 2)
);
}
});
// Individual tests...
});enable_reqheaders_recording: trueclear() periodically or filter recordingsnock.recorder.rec({
logging: (content) => {
console.log("Recording:", content);
// Debug the structure
if (content.startsWith("{")) {
try {
const parsed = JSON.parse(content);
console.log("Parsed definition:", parsed);
} catch (e) {
console.log("Failed to parse:", e.message);
}
}
}
});Install with Tessl CLI
npx tessl i tessl/npm-nockdocs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10