CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-nock

HTTP server mocking and expectations library for Node.js testing environments

67

0.98x
Overview
Eval results
Files

recording-playback.mddocs/

Recording and Playback

This document covers nock's recording functionality, which captures real HTTP traffic and converts it into fixtures that can be replayed in tests.

Recording Interface

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;

Basic Recording

Start Recording

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);

Simple Boolean Options

// Record with logging enabled
nock.recorder.rec(true);

// Record without logging
nock.recorder.rec(false);

Recording Options

interface RecorderOptions {
  dont_print?: boolean;
  output_objects?: boolean;
  enable_reqheaders_recording?: boolean;
  logging?: (content: string) => void;
  use_separator?: boolean;
}

Don't Print Option

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 manually

Output Objects Option

Control 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[]

Enable Request Headers Recording

Include request headers in recorded fixtures:

nock.recorder.rec({ enable_reqheaders_recording: true });

// The recorded fixtures will include the headers sent in requests

Example 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" }]);

Custom Logging

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");
  }
});

Use Separator

Add separators between recorded fixtures:

nock.recorder.rec({ use_separator: true });

// Output will include separator comments between fixtures:
// <<<<<<-- cut here -->>>>>>

Managing Recordings

Clear Recordings

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...

Play Recordings

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", ... }

Restore Original HTTP

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)

Definition Objects

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;
}

Working with Definition Objects

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);

Complete Recording Workflow

Record and Generate Test Fixtures

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();
  }
}

Load and Use Recorded Fixtures

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);
  });
});

Advanced Recording Patterns

Conditional Recording

// Only record in development mode
if (process.env.NODE_ENV === "development") {
  nock.recorder.rec({
    output_objects: true,
    logging: (content) => {
      console.log("Recorded fixture:", content);
    }
  });
}

Filtering Recorded Requests

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);

Recording with Custom Processing

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);
    }
  }
});

Integration with Test Frameworks

Jest Integration

// 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();
});

Mocha Integration

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...
});

Troubleshooting Recording

Common Issues

  1. Headers not recorded: Use enable_reqheaders_recording: true
  2. Binary data issues: Ensure proper encoding for binary responses
  3. Too many fixtures: Use clear() periodically or filter recordings
  4. Sensitive data: Always sanitize recorded fixtures before saving

Debugging Recording

nock.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-nock

docs

fixture-testing.md

global-management.md

index.md

recording-playback.md

request-interception.md

request-matching.md

response-definition.md

tile.json