mock-xmlhttprequest

XMLHttpRequest mock for testing

mock-xmlhttprequest

XMLHttpRequestmock for testing that provides a simple interface to simulate interactions with XMLHttpRequestwithout any outside dependency or interaction with the browser. It is meant as a drop-in replacement for XMLHttpRequestwhen testing code that depends on it.

This library implements the XMLHttpRequestinterface and handles requests and events as specified in the XMLHTTPRequest specificationwithout actually sending anything over the network. Mock response methodsand Hooksare provided to simulate responses, upload progress, etc. The mock response methods are higher level and automatically handle lower-level processing like emitting events and setting the readystateproperty.

Table of Contents

Installation

via npm (node package manager)

$ npm install mock-xmlhttprequest

Quick Start

const assert = require('assert');
const MockXMLHttpRequest = require('mock-xmlhttprequest');

// Install the server's XMLHttpRequest mock in the "global" context.
// "new XMLHttpRequest()" will then create a mock request to which the server will reply.
const server = MockXMLHttpRequest.newServer({
  get: ['/my/url', {
    // status: 200 is the default
    headers: { 'Content-Type': 'application/json' },
    body: '{ "message": "Success!" }',
  }],
}).install( /* optional context; defaults to global */ );

// Do something that send()s an XMLHttpRequest to '/my/url'
const result = MyModuleUsingXhr.someAjaxMethod();

// Assuming someAjaxMethod() returns the parsed JSON body
assert.equal(result.message, 'Success!');

// Restore the original XMLHttpRequest from the context given to install()
server.remove();

Low-Level Quick Start

An alternative usage pattern not using the mock server based only on the MockXhrclass. Mostly here for historical reasons because it predates the mock server.

const assert = require('assert');
const MockXMLHttpRequest = require('mock-xmlhttprequest');
const MockXhr = MockXMLHttpRequest.newMockXhr();

// Mock JSON response
MockXhr.onSend = (xhr) => {
  const responseHeaders = { 'Content-Type': 'application/json' };
  const response = '{ "message": "Success!" }';
  xhr.respond(200, responseHeaders, response);
};

// Install in the global context so "new XMLHttpRequest()" uses the XMLHttpRequest mock
global.XMLHttpRequest = MockXhr;

// Do something that send()s an XMLHttpRequest to '/my/url'
const result = MyModuleUsingXhr.someAjaxMethod();

// Assuming someAjaxMethod() returns the value of the 'result' property
assert.equal(result.message, 'Success!');

// Remove the mock class from the global context
delete global.XMLHttpRequest;

Features

Based on the XMLHTTPRequest specification, version '28 November 2018'.

Supported

  • events and states
  • open(), setRequestHeader(), send()and abort()
  • upload and download progress events
  • response status, statusText, headers and body
  • the timeout attribute (can be disabled) (since v4.0.0)
  • simulating a network error
  • simulating a request timeout (see MockXhr.setRequestTimeout())

Partial support

  • overrideMimeType(): throws when required, but has no other effect.
  • responseType: '', 'text'and 'json'are fully supported. Other responseTypevalues can also be used, but they will return the response body passed to setResponseBody()as-is in xhr.response.
  • responseXml: the response body is not converted to a document response. To get a document response, pass it directly as the response body in setResponseBody().

Not supported

  • synchronous requests (i.e. async== false)
  • parsing the URL and setting the usernameand passwordsince there are no actual HTTP requests
  • responseUrl(i.e. the final request URL with redirects) is not automatically set. This can be emulated in a request handler.

Usage

Mock Server

The mock server is the easiest way to define responses for one or more requests. Handlers can be registered for any HTTP method and URL without having to dig in the lower-level hooksof this library.

Basic Setup

The basic structure of tests using the mock server is:

const server = require('mock-xmlhttprequest').newServer( /* routes */ );
try {
  server.install( /* optional context; defaults to global */ );
  // Test code that creates XMLHttpRequests
} finally {
  // Don't do this before the test code is done creating XMLHttpRequests!
  server.remove();
}
  • install(context = global)installs the server's XMLHttpRequest mock in the given context (e.g. globalin node or windowin the browser).
  • remove()reverts what install()did.

For more control, you can also access the server's XMLHttpRequest mock class. This allows injecting it somewhere with custom code instead of using install():

  • server.xhrFactoryis a factory method to create XMLHttpRequest mock instances.
  • server.MockXhris the server's XMLHttpRequest mock class.

Usage example:

const server = require('mock-xmlhttprequest').newServer( /* routes */ );
const savedFactory = MyClass.xhrFactory;
try {
  MyClass.xhrFactory = server.xhrFactory;
  // Test code that creates XMLHttpRequests through MyClass.xhrFactory()
} finally {
  // Don't do this before the test code is done using the factory!
  MyClass.xhrFactory = savedFactory;
}

Routes

Routes are defined by these 3 elements:

When an XMLHttpRequest is sent, the server responds with the request handler of the first route matching the request method and URL. Note that route insertion order is important here. If no route is found for a request, no action is taken.

The route concept is loosely based on the Express framework.

HTTP Request Method

Any stringwith a valid HTTP request method is allowed. This includes standard methods like GET, POST, PUTand DELETE, but also other method names as well.

Request URL Matcher

This can be:

  • A string(e.g. '/get') in which case it must match exactly the request URL.
  • A RegExpagainst which the request URL is tested.
  • A Function(signature matches(url)) which must return true if the request URL matches.
Request Handler

This can be:

  • An objectwith the response properties. The default values are: { status: 200, headers: {}, body: null, statusText: 'OK' }. An empty object is also allowed here to accept all default values.
  • A Function(signature handler(xhr)) that calls the mock response methodsdirectly.
  • An array of objectand Functionrequest handlers. In this case, the first matching request gets the first handler, the second gets the second handler and so on. The last handler is reused if the number of matching requests exceeds the number of handlers in the array.

These handlers are equivalent:

const handlerObj = {};
const handlerFn = (xhr) => { xhr.respond(); };
const handlerArray = [{}];

Request handlers are invoked in a different call stack (using setTimeout()) than the one that called send()on the XMLHttpRequest. Therefore you will probably need to use your test framework's asynchronous test support (e.g. for Mocha: https://mochajs.org/#asynchronous-code) to complete the unit test.

MockXMLHttpRequest.newServer(routes = {})

Factory method to create a new server. The optional routesparameter allows defining routes directly at construction. Each property name in routescorresponds to an HTTP method and its value must be an array containing [url_matcher, request_handler].

Example:

const handlerFn = (xhr) => { xhr.respond(); };
newServer({
  get: ['/get', { status: 200 }],
  'my-method': ['/my-method', { status: 201 }],
  post: ['/post', [handlerFn, { status: 404 }]],
});

get(matcher, handler)

Add a routefor the GETHTTP method.

post(matcher, handler)

Add a routefor the POSTHTTP method.

put(matcher, handler)

Add a routefor the PUTHTTP method.

delete(matcher, handler)

Add a routefor the DELETEHTTP method.

addHandler(method, matcher, handler)

Add a routefor the methodHTTP method.

setDefaultHandler(handler)

Set a default request handler for requests that don't match any route.

setDefault404()

Return 404 responses for requests that don't match any route.

getRequestLog()

Returns the list of all requests received by the server. Each entry has { method, url, body, headers }. Can be useful for debugging or asserting the order and contents of the sent mock requests.

disableTimeout() and enableTimeout()

Controls whether setting the timeoutattribute of a mocked XMLHttpRequestactually triggers timeoutevents that cancel requests. This is enabled by default. See "The timeoutAttribute and Request Timeouts".

Mock response methods

These methods can be called on MockXhr(i.e. the XMLHttpRequestmock) instances.

uploadProgress(transmitted)

Fires a request upload progress event where transmittedis the number of bytes transmitted.

May only be called when the request body is not null and the upload is not complete. Can be followed by any other mock response method.

respond(status = 200, headers = {}, body = null, statusText = 'OK')

Complete response method which sets the response headers and body. Will fire the appropriate readystatechange, progress, load, etc. (upload) events. The state of the request will be set to DONE.

This is a shorthand for calling setResponseHeaders()and setResponseBody()in sequence.

No other mock response methods may be called after this one until open()is called.

setResponseHeaders(status = 200, headers = {}, statusText = 'OK')

Sets the response headers only. Will fire the appropriate readystatechange, progress, load, etc. (upload) events. Will set the request state to HEADERS_RECEIVED.

Should be followed by either downloadProgress(), setResponseBody(), setNetworkError()or setRequestTimeout().

downloadProgress(transmitted, length)

Fires a response progress event. Will set the request state to LOADING.

Must be preceded by setResponseHeaders().

setResponseBody(body = null)

Sets the response body. Calls [setResponseHeaders()](#setresponseheadersstatus--200-headers---statustext--ok if not already called. Will fire the appropriate readystatechange, progress, load, etc. (upload) events. The state of the request will be set to DONE.

No other mock response methods may be called after this one until open()is called.

setNetworkError()

Simulates a network error. Will set the request state to DONEand fire an errorevent (amongst other events).

No other mock response methods may be called after this one until open()is called.

setRequestTimeout()

Simulates a request timeout. Will set the request state to DONEand fire a timeoutevent (amongst other events).

No other mock response methods may be called after this one until open()is called.

Hooks

The hooks defined in this library can be set at these locations:

  • On an instance of MockXhr(i.e. of the XMLHttpRequestmock class).
  • On a "local" MockXhrmock subclass returned by require('mock-xmlhttprequest').newMockXhr().
  • Globally, directly on the MockXhrclass (from require('mock-xmlhttprequest').MockXhr). Note that each call to require('mock-xmlhttprequest')in a node process will return the same instance of MockXMLHttpRequest. This means that hooks set directly on MockXMLHttpRequest.MockXhrneed to be removed manually when no longer needed. This method is therefore not recommended.

MockXhr.onCreate(xhr)

Called when an instance of MockXhris created. This makes it possible to capture instances of XMLHttpRequestwhen they are constructed.

This hook is called inside the MockXhrconstructor.

const MockXMLHttpRequest = require('mock-xmlhttprequest');
const MockXhr = MockXMLHttpRequest.newMockXhr();

// Hook for all requests using the local mock subclass
MockXhr.onCreate = (xhr) => { /*...*/ };

// Global hook for all requests from all mocks
MockXMLHttpRequest.MockXhr.onCreate = (xhr) => { /*...*/ };

MockXhr.onSend(xhr)

Called when XMLHttpRequest.send()has done its processing and the test case should start using the mock reponse methods. In a real XMLHttpRequest, this would be where the actual http request takes place.

This callback is invoked in an empty call stack (using setTimeout()). Therefore you will probably need to use your test framework's asynchronous test support (e.g. for Mocha: https://mochajs.org/#asynchronous-code) to complete the unit test when using this.

const MockXMLHttpRequest = require('mock-xmlhttprequest');
const MockXhr = MockXMLHttpRequest.newMockXhr();

// Hook for all requests using the local mock subclass
MockXhr.onSend = (xhr) => { /*...*/ };

// Global hook for all requests from all mocks
MockXMLHttpRequest.MockXhr.onSend = (xhr) => { /*...*/ };

// Hook local to an instance of MockXhr
const xhr = new MockXhr();
xhr.onSend = (xhr) => { /*...*/ };

The timeoutAttribute and Request Timeouts

(since v4.0.0)

By default, setting the timeoutattribute of a MockXhrinstance triggers timeoutevents that cancel requests as described in the specification. This can be problematic in some tests and when debugging interactively since request timeouts are then not explicitly triggered by the test code. There are multiple ways to disable this behavior:

  • Set xhr.timeoutEnabled = falseon an MockXhrinstance to disable for that instance only.
  • Set MockXhr.timeoutEnabled = falsedirectly on the MockXhrclass to disable for all its instances.
  • Call server.disableTimeout()on a mock server to disable for all its MockXhrinstances.

When the timeoutattribute is disabled (and also when it's enabled), timeouts can be triggered programmatically using setRequestTimeout().

Run Unit Tests

$ npm test

Contributing

Contributors are welcome! See herefor more info.

License

ISC

HomePage

https://github.com/berniegp/mock-xmlhttprequest#readme

Repository

https+https://github.com/berniegp/mock-xmlhttprequest


上一篇:grpc-tools
下一篇:gulp-eval

相关推荐

  • 阿贾克斯XMLHttpRequest文件上传

    Sedat Başar(https://stackoverflow.com/users/739315/sedatba%c5%9far)提出了一个问题:Upload File With Ajax Xml...

    2 年前
  • 防止重定向XMLHttpRequest

    Zim(https://stackoverflow.com/users/30609/zim)提出了一个问题:Prevent redirection of Xmlhttprequest,或许与您遇到的问...

    2 年前
  • 通过 Swagger 定义自动生成 Mock 数据

    我最近的在做的项目是一个前后端分离的项目,前后端由不同的团队分别开发,并且前端的进度经常领先后端。这就意味着,当前端在开发一个新功能时,API 可能还没有准备好。不过,我们会先和后端先商议好 API ...

    10 个月前
  • 解析JSON的来自XmlHttpRequest.responseJSON

    FruitBreakchanux(https://stackoverflow.com/users/255718/fruitbreak)提出了一个问题:Parsing JSON from XmlHttp...

    2 年前
  • 获取API和XMLHttpRequest之间的区别是什么?

    Marcoilyabasiuk(https://stackoverflow.com/users/5769903/marco)提出了一个问题:What is the difference between...

    2 年前
  • 浅谈easy-mock 最好的备胎没有之一

    浅谈easymock 最好的备胎没有之一,本文由@IT·平头哥联盟首席填坑官∙苏南 分享(https://img.javascriptcn.com/f9b40fbbdca49cf9ef5d4821dc...

    2 年前
  • 有什么理由使用同步XMLHttpRequest?

    Darrell Brogdon(https://stackoverflow.com/users/55589/darrellbrogdon)提出了一个问题:Is there any reason to ...

    2 年前
  • 是会等于发生在XMLHttpRequest = 4?

    informatik01Huang(https://stackoverflow.com/users/814702/informatik01)提出了一个问题:Is onload equal to rea...

    2 年前
  • 日拱一卒-如何mock数据

    在项目的开发中,联调是家常便饭,而且也是比较费时间的一个环节。在前后端分离的项目当中,我们往往是先约定好接口与数据,再进行开发。这个时候,如果前端能自己启动一个服务,按照一定的规则生成假数据,那么联调...

    4 个月前
  • 推荐一个在线接口Mock工具fastmock

    fastmock可以让你在没有后端程序的情况下能真实地在线模拟ajax请求,你可以用fatmock实现项目初期纯前端的效果演示,也可以用fastmock实现开发中的数据模拟从而实现前后端分离。

    2 年前

官方社区

扫码加入 JavaScript 社区