Nise Fake XHR and Server
Nise (偽) is a JavaScript library designed for faking XMLHttpRequest (XHR) and creating a fake server environment, primarily used in testing scenarios. It allows developers to intercept and control network requests made by their application without actually performing real HTTP calls. Extracted from the larger Sinon.JS library, Nise offers a lightweight alternative for users who only require XHR and server mocking functionalities, avoiding the overhead of the full Sinon.JS suite. The current stable version is 6.1.5, which was recently published as a patch. The project maintains an active, albeit slower, release cadence for minor and patch versions, driven by community needs and bug fixes. Its key differentiator is its focused scope and tight integration within the Sinon.JS testing ecosystem, providing a reliable and robust solution for simulating server interactions during unit and integration tests.
Common errors
-
TypeError: XMLHttpRequest is not a constructor
cause This error occurs when `new XMLHttpRequest()` is called in a Node.js environment that lacks a global `XMLHttpRequest` polyfill, or before `nise` has been initialized to provide its fake implementation.fixEnsure that a browser emulation layer (e.g., `jsdom`) is set up in your Node.js test environment, or that `fakeXhr.useFakeXMLHttpRequest()` or `fakeServer.create()` has been called to mock the global `XMLHttpRequest` object. -
Error: XHR has already been faked. Call `restore()` on the current fake XHR object before faking again.
cause You are attempting to call `fakeXhr.useFakeXMLHttpRequest()` or `fakeServer.create()` multiple times within the same context (e.g., without proper cleanup between tests) without first calling `restore()` on the previously active fake XHR instance.fixModify your test setup to ensure that `restore()` is invoked on the previously activated `fakeXhr` or `fakeServer` instance (e.g., in an `afterEach` or `afterAll` hook) before any new fakes are created. -
ReferenceError: require is not defined
cause This error typically occurs when an ES module using `import ... from 'nise'` is executed in a Node.js environment configured exclusively for CommonJS modules, or vice-versa, without appropriate transpilation or configuration.fixFor ES Modules, ensure your `package.json` contains `"type": "module"` and use `import` statements. For CommonJS, use `require` statements. Verify your Node.js environment and file extensions (`.js`, `.mjs`, `.cjs`) align with the module system you intend to use.
Warnings
- gotcha Faking global XHR objects via `fakeXhr.useFakeXMLHttpRequest()` or `fakeServer.create()` replaces the native XMLHttpRequest. It is crucial to call `restore()` on the returned instance after each test or test suite. Failing to do so can lead to unexpected behavior and hard-to-debug side effects in subsequent tests or other parts of your application.
- gotcha When using `fakeServer`, network requests are not automatically responded to by default. You must explicitly call `server.respond()` to process pending requests and send configured responses. This is important for controlling the flow of asynchronous operations in your tests.
- gotcha Nise's fake XHR functionality is primarily designed for browser-like environments. When used in Node.js, a global `XMLHttpRequest` polyfill (such as one provided by `jsdom`) must be present for Nise to effectively replace and control it. Without this, operations might fail or not behave as expected.
Install
-
npm install nise -
yarn add nise -
pnpm add nise
Imports
- fakeXhr
const fakeXhr = require('nise').fakeXhr;import { fakeXhr } from 'nise'; - fakeServer
const fakeServer = require('nise').fakeServer;import { fakeServer } from 'nise'; - FakeXMLHttpRequest
import { XMLHttpRequest } from 'nise';import { FakeXMLHttpRequest } from 'nise';
Quickstart
import { fakeXhr, fakeServer } from 'nise';
// 1. Using fakeXhr to replace the global XMLHttpRequest
let xhr: typeof XMLHttpRequest | undefined;
let capturedRequests: XMLHttpRequest[] = [];
function setupFakeXhr() {
xhr = fakeXhr.useFakeXMLHttpRequest();
xhr.onCreate = function (req) {
capturedRequests.push(req);
};
console.log('Fake XHR initialized.');
}
function teardownFakeXhr() {
if (xhr) {
xhr.restore();
capturedRequests = [];
console.log('Fake XHR restored.');
}
}
// 2. Using fakeServer for more complete control and automatic global replacement
let server: InstanceType<typeof fakeServer> | undefined;
function setupFakeServer() {
server = fakeServer.create();
// Configure a response for a GET request to /users
server.respondWith('GET', '/users', [
200, // HTTP Status Code
{ 'Content-Type': 'application/json' }, // Headers
JSON.stringify([{ id: 1, name: 'Alice' }]) // Response Body
]);
// Configure a response for a POST request to /users
server.respondWith('POST', '/users', [
201,
{ 'Content-Type': 'application/json' },
JSON.stringify({ id: 2, name: 'Bob' })
]);
console.log('Fake Server initialized.');
}
function teardownFakeServer() {
if (server) {
server.restore();
console.log('Fake Server restored.');
}
}
// --- Demonstration with fakeXhr ---
setupFakeXhr();
const req1 = new XMLHttpRequest();
req1.open('GET', '/data');
req1.send();
console.log(`Fake XHR captured request method: ${capturedRequests[0].method}, URL: ${capturedRequests[0].url}`);
teardownFakeXhr();
console.log('\n--- Demonstration with fakeServer ---\n');
// --- Demonstration with fakeServer ---
setupFakeServer();
// Make a GET request
const req2 = new XMLHttpRequest();
req2.open('GET', '/users');
req2.onload = function() {
console.log(`Fake Server GET response: ${req2.status} - ${req2.responseText}`);
};
req2.send();
server!.respond(); // Manually trigger server response
// Make a POST request
const req3 = new XMLHttpRequest();
req3.open('POST', '/users');
req3.onload = function() {
console.log(`Fake Server POST response: ${req3.status} - ${req3.responseText}`);
};
req3.setRequestHeader('Content-Type', 'application/json');
req3.send(JSON.stringify({ name: 'Bob' }));
server!.respond(); // Manually trigger server response
teardownFakeServer();