HTTP server mocking and expectations library for Node.js testing environments
67
This document covers the core functionality for creating scopes and intercepting HTTP requests with nock.
The main nock function creates a scope that defines the base URL and configuration for intercepting requests.
function nock(basePath: string | RegExp | Url | URL, options?: Options): Scope;basePath: The base URL, hostname, or pattern to intercept. Can be:
"https://api.example.com"/api\.example\.com/new URL("https://api.example.com")options: Optional configuration for the scope// Basic hostname interception
const scope = nock("https://api.example.com");
// Intercept all subdomains
const scope = nock(/.*\.example\.com/);
// With options
const scope = nock("https://api.example.com", {
allowUnmocked: true,
encodedQueryParams: true
});The Scope provides methods for intercepting different HTTP verbs.
interface Scope extends NodeJS.EventEmitter {
get(uri: string | RegExp | ((uri: string) => boolean), requestBody?: RequestBodyMatcher, options?: Options): Interceptor;
post(uri: string | RegExp | ((uri: string) => boolean), requestBody?: RequestBodyMatcher, options?: Options): Interceptor;
put(uri: string | RegExp | ((uri: string) => boolean), requestBody?: RequestBodyMatcher, options?: Options): Interceptor;
head(uri: string | RegExp | ((uri: string) => boolean), requestBody?: RequestBodyMatcher, options?: Options): Interceptor;
patch(uri: string | RegExp | ((uri: string) => boolean), requestBody?: RequestBodyMatcher, options?: Options): Interceptor;
merge(uri: string | RegExp | ((uri: string) => boolean), requestBody?: RequestBodyMatcher, options?: Options): Interceptor;
delete(uri: string | RegExp | ((uri: string) => boolean), requestBody?: RequestBodyMatcher, options?: Options): Interceptor;
options(uri: string | RegExp | ((uri: string) => boolean), requestBody?: RequestBodyMatcher, options?: Options): Interceptor;
}uri: The path portion of the URL to match. Can be:
"/users/123"/\/users\/\d+/(uri) => uri.includes("users")requestBody: Optional body matcher for POST/PUT/PATCH requestsoptions: Optional interceptor-specific options// GET request
nock("https://api.example.com")
.get("/users")
.reply(200, [{ id: 1, name: "Alice" }]);
// POST request with body matching
nock("https://api.example.com")
.post("/users", { name: "Bob", email: "bob@example.com" })
.reply(201, { id: 2, name: "Bob", email: "bob@example.com" });
// Dynamic path matching
nock("https://api.example.com")
.get(/\/users\/\d+/)
.reply(200, (uri) => {
const id = uri.split("/").pop();
return { id: parseInt(id), name: `User ${id}` };
});
// Function-based URI matching
nock("https://api.example.com")
.get((uri) => uri.includes("search"))
.reply(200, { results: [] });For custom HTTP methods or more control over interception:
intercept(
uri: string | RegExp | ((uri: string) => boolean),
method: string,
requestBody?: RequestBodyMatcher,
options?: Options
): Interceptor;// Custom HTTP method
nock("https://api.example.com")
.intercept("/data", "PURGE")
.reply(204);
// Case-insensitive method
nock("https://api.example.com")
.intercept("/users", "get") // lowercase also works
.reply(200, []);Scopes can be configured with default behaviors that apply to all interceptors in that scope.
defaultReplyHeaders(headers: ReplyHeaders): this;Set headers that will be included in all responses from this scope.
const scope = nock("https://api.example.com")
.defaultReplyHeaders({
"Content-Type": "application/json",
"X-API-Version": "1.0"
});
scope.get("/users").reply(200, []); // Will include the default headerspersist(flag?: boolean): this;Makes the scope persistent, meaning interceptors can be matched multiple times.
// Persist all interceptors in this scope
const scope = nock("https://api.example.com")
.persist()
.get("/users")
.reply(200, []);
// This interceptor can now be called multiple timesreplyContentLength(): this;
replyDate(d?: Date): this;Automatically add Content-Length and Date headers to responses.
const scope = nock("https://api.example.com")
.replyContentLength()
.replyDate(new Date("2023-01-01"))
.get("/users")
.reply(200, []);interface Scope {
done(): void;
isDone(): boolean;
pendingMocks(): string[];
activeMocks(): string[];
}done(): Asserts that all interceptors in this scope have been satisfied. Throws if any are pending.isDone(): Returns true if all interceptors in this scope have been satisfiedpendingMocks(): Returns array of string descriptions of pending interceptors in this scopeactiveMocks(): Returns array of string descriptions of active interceptors in this scopeconst scope = nock("https://api.example.com")
.get("/users")
.reply(200, [])
.post("/users")
.reply(201, { id: 1 });
console.log(scope.isDone()); // false
console.log(scope.pendingMocks()); // ["GET https://api.example.com:443/users", "POST https://api.example.com:443/users"]
// After making the GET request
console.log(scope.pendingMocks()); // ["POST https://api.example.com:443/users"]
// After making both requests
scope.done(); // Passes without throwinginterface Options {
allowUnmocked?: boolean;
reqheaders?: Record<string, RequestHeaderMatcher>;
badheaders?: string[];
filteringScope?: (scope: string) => boolean;
encodedQueryParams?: boolean;
}allowUnmocked: Allow requests to this scope that don't match any interceptor to pass through to the real serverreqheaders: Require specific headers to be present in requestsbadheaders: Headers that must NOT be present in requestsfilteringScope: Function to filter/transform the scope string for matchingencodedQueryParams: Whether query parameters should be matched in encoded form// Allow unmatched requests to pass through
const scope = nock("https://api.example.com", { allowUnmocked: true })
.get("/users")
.reply(200, []);
// Require authentication header
const scope = nock("https://api.example.com", {
reqheaders: {
authorization: "Bearer token123"
}
});
// Reject requests with certain headers
const scope = nock("https://api.example.com", {
badheaders: ["x-debug-mode"]
});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