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

response-definition.mddocs/

Response Definition

This document covers how to define mock responses for intercepted HTTP requests using nock's Interceptor interface.

Basic Response Definition

The primary method for defining responses is the reply method, which has several overloads for different use cases.

interface Interceptor {
  reply(responseCode?: number, body?: ReplyBody, headers?: ReplyHeaders): Scope;
  reply(
    replyFn: (uri: string, body: Body) => ReplyFnResult | Promise<ReplyFnResult>
  ): Scope;
  reply(
    replyFnWithCallback: (
      uri: string,
      body: Body,
      callback: (err: NodeJS.ErrnoException | null, result: ReplyFnResult) => void
    ) => void
  ): Scope;
  reply(
    statusCode: number,
    replyBodyFn: (uri: string, body: Body) => ReplyBody | Promise<ReplyBody>,
    headers?: ReplyHeaders
  ): Scope;
  reply(
    statusCode: number,
    replyBodyFnWithCallback: (
      uri: string,
      body: Body,
      callback: (err: NodeJS.ErrnoException | null, result: ReplyBody) => void
    ) => void,
    headers?: ReplyHeaders
  ): Scope;
}

Static Responses

// Basic 200 OK response
nock("https://api.example.com")
  .get("/users")
  .reply(200);

// With response body
nock("https://api.example.com")
  .get("/users")
  .reply(200, [{ id: 1, name: "Alice" }]);

// With custom headers
nock("https://api.example.com")
  .get("/users")
  .reply(200, [{ id: 1, name: "Alice" }], {
    "Content-Type": "application/json",
    "X-Total-Count": "1"
  });

// Different status codes
nock("https://api.example.com")
  .post("/users")
  .reply(201, { id: 2, name: "Bob" });

nock("https://api.example.com")
  .get("/users/999")
  .reply(404, { error: "User not found" });

Dynamic Responses

Use functions to generate responses based on the request:

// Function returning response data
nock("https://api.example.com")
  .get(/\/users\/(\d+)/)
  .reply(200, (uri, requestBody) => {
    const id = uri.match(/\/users\/(\d+)/)[1];
    return { id: parseInt(id), name: `User ${id}` };
  });

// Function returning full response
nock("https://api.example.com")
  .post("/users")
  .reply((uri, requestBody) => {
    const user = JSON.parse(requestBody);
    if (!user.name) {
      return [400, { error: "Name is required" }];
    }
    return [201, { ...user, id: Math.floor(Math.random() * 1000) }];
  });

// Async function support
nock("https://api.example.com")
  .get("/users")
  .reply(async (uri, requestBody) => {
    // Simulate async operation
    await new Promise(resolve => setTimeout(resolve, 100));
    return [200, { message: "Users loaded asynchronously" }];
  });

Callback-Style Dynamic Responses

For more complex scenarios requiring callback-style responses:

nock("https://api.example.com")
  .get("/users")
  .reply(function(uri, requestBody, callback) {
    // 'this' refers to the interceptor context
    const req = this.req;
    
    // Simulate async operation
    setTimeout(() => {
      callback(null, [200, { users: [], requestId: req.headers["x-request-id"] }]);
    }, 100);
  });

Response Body Types

type ReplyBody = string | Record<string, any> | Buffer | ReadStream;

Nock supports various response body types:

JSON Objects

nock("https://api.example.com")
  .get("/user")
  .reply(200, { id: 1, name: "Alice", active: true });

Plain Text

nock("https://api.example.com")
  .get("/status")
  .reply(200, "Server is healthy");

Buffer Data

const imageBuffer = Buffer.from("fake-image-data");
nock("https://api.example.com")
  .get("/image.png")
  .reply(200, imageBuffer, { "Content-Type": "image/png" });

Stream Data

const fs = require("fs");
const stream = fs.createReadStream("./test-data.json");

nock("https://api.example.com")
  .get("/large-dataset")
  .reply(200, stream, { "Content-Type": "application/json" });

Error Responses

Reply with Error

Generate network-level errors instead of HTTP error responses:

replyWithError(errorMessage: string | object): Scope;
// String error message
nock("https://api.example.com")
  .get("/users")
  .replyWithError("Network timeout");

// Error object
nock("https://api.example.com")
  .get("/users")
  .replyWithError({
    code: "ECONNREFUSED",
    message: "Connection refused"
  });

// This will cause the HTTP request to fail with the specified error

Reply with File

Respond with the contents of a file:

replyWithFile(statusCode: number, fileName: string, headers?: ReplyHeaders): Scope;
nock("https://api.example.com")
  .get("/config")
  .replyWithFile(200, "./test-fixtures/config.json", {
    "Content-Type": "application/json"
  });

Response Headers

type ReplyHeaders = 
  | Record<string, ReplyHeaderValue>
  | Map<string, ReplyHeaderValue>
  | ReplyHeaderValue[];

type ReplyHeaderValue = string | string[] | ReplyHeaderFunction;

type ReplyHeaderFunction = (
  req: ClientRequest,
  res: IncomingMessage,
  body: string | Buffer
) => string | string[];

Static Headers

// Object format
nock("https://api.example.com")
  .get("/users")
  .reply(200, [], {
    "Content-Type": "application/json",
    "X-Total-Count": "0"
  });

// Array format (key-value pairs)
nock("https://api.example.com")
  .get("/users")
  .reply(200, [], [
    "Content-Type", "application/json",
    "X-Total-Count", "0"
  ]);

// Map format
const headers = new Map();
headers.set("Content-Type", "application/json");
headers.set("X-Total-Count", "0");

nock("https://api.example.com")
  .get("/users")
  .reply(200, [], headers);

Multiple Values

// Multiple values for same header
nock("https://api.example.com")
  .get("/users")
  .reply(200, [], {
    "Set-Cookie": ["session=abc123", "theme=dark"]
  });

Dynamic Headers

nock("https://api.example.com")
  .get("/users")
  .reply(200, [], {
    "Content-Type": "application/json",
    "X-Request-Time": (req, res, body) => new Date().toISOString(),
    "X-Body-Length": (req, res, body) => body.length.toString()
  });

Response Timing

Control the timing of responses to simulate network latency or slow servers.

Basic Delay

delay(ms: number): this;
// Delay response by 1 second
nock("https://api.example.com")
  .get("/users")
  .delay(1000)
  .reply(200, []);

Advanced Delay Options

delay(opts: { head?: number; body?: number }): this;
// Separate delays for headers and body
nock("https://api.example.com")
  .get("/users")
  .delay({
    head: 100, // Delay headers by 100ms
    body: 500  // Delay body by additional 500ms
  })
  .reply(200, []);

Deprecated Delay Methods

These methods are deprecated but still supported:

delayBody(timeMs: number): this;
delayConnection(timeMs: number): this;
// Deprecated - use delay() instead
nock("https://api.example.com")
  .get("/users")
  .delayConnection(200)
  .delayBody(300)
  .reply(200, []);

Repetition Control

Control how many times an interceptor can be matched.

interface Interceptor {
  times(newCounter: number): this;
  once(): this;
  twice(): this;
  thrice(): this;
  optionally(flag?: boolean): this;
}

Specific Repetition Counts

// Match exactly 3 times
nock("https://api.example.com")
  .get("/users")
  .times(3)
  .reply(200, []);

// Convenience methods
nock("https://api.example.com")
  .get("/status")
  .once() // Same as .times(1)
  .reply(200, "OK");

nock("https://api.example.com")
  .get("/health")
  .twice() // Same as .times(2)
  .reply(200, "Healthy");

nock("https://api.example.com")
  .get("/ping")
  .thrice() // Same as .times(3)
  .reply(200, "Pong");

Optional Interceptors

// This interceptor is optional for scope.done() checks
nock("https://api.example.com")
  .get("/optional-endpoint")
  .optionally()
  .reply(200, "Optional response");

// Can also be toggled
nock("https://api.example.com")
  .get("/conditional")
  .optionally(process.env.NODE_ENV === "test")
  .reply(200, "Conditional response");

Response Function Context

When using function-based replies, the function receives a context with additional information:

interface ReplyFnContext extends Interceptor {
  req: ClientRequest & {
    headers: Record<string, string>;
  };
}
nock("https://api.example.com")
  .post("/users")
  .reply(function(uri, requestBody) {
    // 'this' provides access to the request context
    const contentType = this.req.headers["content-type"];
    const userAgent = this.req.headers["user-agent"];
    
    return [200, {
      message: "User created",
      metadata: {
        contentType,
        userAgent,
        timestamp: Date.now()
      }
    }];
  });

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