XHR-Mock Edit
This is a utility for mocking XMLHttpRequest. It’s useful for testing, or prototyping while your backend is still being built.
It works in NodeJS and in the browser, and is compatible with:
It may also work with other libraries built on XMLHttpRequest.
Standard compliant (http://xhr.spec.whatwg.org/).
For more information, go to the XHR-Mock GitHub Page.
Installation Edit
With a Bundler
If you are using a bundler like Webpack or Browserify install xhr-mock
using yarn
or npm
:
yarn add --dev xhr-mock
Now import xhr-mock
and start using it in your scripts:
import mock from 'xhr-mock';
Without a Bundler
If you aren’t using a bundler like Webpack or Browserify then add this script to your HTML:
<script src="https://unpkg.com/xhr-mock/dist/xhr-mock.js"></script>
You can now start using the global, XHRMock
, in your scripts!
Example Edit
./createUser.js
demonstrates a use case of XMLHttpRequest.
Axios, jQuery, Superagent or another package can also be used instead of the native XMLHttpRequest object.
- A new XMLHttpRequest is created called
xhr
. - the
.onreadystatechange
function is created for when the client receives the response from the server xhr.open
initializes the request to the url.xhr.setRequestHeader
sets the value of of the header, ‘Content-Type’ to JSON.xhr.send
sends the request body to the server.
./createUser.test.js
, shows unit tests using xhr-mock
which replaces XMLHttpRequest
with MockXMLHttpRequest
.
mock.post
registers the url andPOST
method to the request handler.createUser
method is called passing the parameter “John”.XHRMock
processes the request to the url, and:- If the value of the request header is in JSON,
- If the request data is equal to “John”,
- The response
"id": "abc-123"
is returned.
// createUser serves as the client.
export default function createUser(reqdata) {
return new Promise((resolve, reject) => {
// we create a new XMLHttpRequest object.
const xhr = new XMLHttpRequest();
// the onreadystatechange function is for receiving the response and checking the status.
xhr.onreadystatechange = () => {
if (xhr.readyState == XMLHttpRequest.DONE) {
if (xhr.status === 201) {
try {
resolve(JSON.parse(xhr.responseText).data);
} catch (error) {
reject(error);
}
} else if (xhr.status) {
try {
reject(JSON.parse(xhr.responseText).error);
} catch (error) {
reject(error);
}
} else {
eject(new Error('An error ocurred whilst sending the request.'));
}
}
};
// initializes the request to the url using the POST method, sets the request header value in JSON, and sends the request.
xhr.open('post', '/api/user');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({data: reqdata}));
});
}
// Tests the code with the mock request and response.
import mock from 'xhr-mock';
import createUser from './createUser';
describe('createUser()', () => {
// replaces the real XHR object with the mock XHR object before each test.
beforeEach(() => mock.setup());
// puts the real XHR object back and clears the mock after each test.
afterEach(() => mock.teardown());
it('should send the data as JSON', async () => {
expect.assertions(2);
// mock sets up the request function and registers the request from the client (createUser) to the request handler. If the request header is in JSON, and the request body is equal to "John," the response is returned: "id":"abc-123".
mock.post('/api/user', (req, res) => {
expect(req.header('Content-Type')).toEqual('application/json');
expect(req.body()).toEqual('{"data":{"name":"John"}}');
return res.status(201).body('{"data":{"id":"abc-123"}}');
});
// makes the requests as the client.
await createUser({name: 'John'});
});
it('should resolve with some data when status=201', async () => {
expect.assertions(1);
mock.post('/api/user', {
status: 201,
reason: 'Created',
body: '{"data":{"id":"abc-123"}}'
});
const user = await createUser({name: 'John'});
expect(user).toEqual({id: 'abc-123'});
});
it('should reject with an error when status=400', async () => {
expect.assertions(1);
mock.post('/api/user', {
status: 400,
reason: 'Bad request',
body: '{"error":"A user named \\"John\\" already exists."}'
});
try {
const user = await createUser({name: 'John'});
} catch (error) {
expect(error).toMatch('A user named "John" already exists.');
}
});
});
XHRMock Edit
Methods used to mock the XMLHttpRequest
object:
.setup()
- description:
- Replaces the global XMLHttpRequest object with the MockXMLHttpRequest.
.teardown()
- description:
- Restores the global
XMLHttpRequest
object to its original state.
- Restores the global
.reset()
- description:
- Forgets all the request handlers.
.get( url | regex , mock )
- description:
- Registers mock as a factory function by passing it as a parameter to the .get function. When XHRMock receives GET request, it then uses the registered mock function to process the request. If the request is as expected, the mock returns a response. For greater detail, look at the source code.
- parameters:
- the url is passed into the function as either a string or a
RegExp
object. - mock is a factory function,
MockFunction
, passed into the .get function as a parameter.
- the url is passed into the function as either a string or a
.post( url | regex , mock )
- description:
- Registers mock as a factory function by passing it as a parameter to the .post function. When XHRMock receives POST request, it then uses the registered mock function to process the request. If the request is as expected, the mock returns a response. For greater detail, look at the source code.
- parameters:
- the url is passed into the function as either a string or a
RegExp
object. - mock is a factory function,
MockFunction
, passed into the .post function as a parameter.
- the url is passed into the function as either a string or a
.patch( url | regex , mock )
- description:
- Registers mock as a factory function by passing it as a parameter to the .patch function. When XHRMock receives PATCH request, it then uses the registered mock function to process the request. If the request is as expected, the mock returns a response. For greater detail, look at the source code.
- parameters:
- the url is passed into the function as either a string or a
RegExp
object. - mock is a factory function,
MockFunction
, passed into the .patch function as a parameter.
- the url is passed into the function as either a string or a
.delete( url | regex , mock )
- description:
- Registers mock as a factory function by passing it as a parameter to the .delete function. When XHRMock receives DELETE request, it then uses the registered mock function to process the request. If the request is as expected, the mock returns a response. For greater detail, look at the source code.
- parameters:
- the url is passed into the function as either a string or a
RegExp
object. - mock is a factory function,
MockFunction
, passed into the .delete function as a parameter.
- the url is passed into the function as either a string or a
.use( method , url | regex , mock )
- description:
- The .use function includes a method. .use registers mock as a factory function by passing it as a parameter to the .use function. When XHRMock receives USE request, it then uses the registered mock function to process the request. If the request is as expected, the mock returns a response. For greater detail, look at the source code.
- parameters:
- the method is passed as a string.
- the url is passed into the function as either a string or a
RegExp
object. - mock is a factory function,
MockFunction
, passed into the .use function as a parameter.
.use( mock )
- description:
- Registers mock as a factory function to create mock responses for every request that passes through it. Url or method is not distinguished.
- parameters:
- mock is a factory function,
MockFunction
, passed into the .use function as a parameter.
- mock is a factory function,
.error( fn )
- description:
- Logs errors thrown by handlers.
- parameters:
- function
MockXMLHttpRequest Edit
MockXMLHttpRequest replaces XMLHttpRequest object.
For xhr-mock.setup()
and xhr-mock.teardown()
refer to XHRMock.
MockRequest
.method() : requestMethod
- description:
- Gets the request method.
- return:
- method: returns method as a string in one of the following:
DELETE
,GET
,HEAD
,OPTIONS
,POST
, orPUT
.
- method: returns method as a string in one of the following:
.url() : MockURL
- description:
- Gets the request MockURL object.
- return:
- MockURL object.
.header( name , value )
- description:
- Sets the request header’s name and value.
- parameters:
- name : string
- value: string
.header( name ) : value
- description:
- Gets a request header and returns the value as a string, or
null
if no header has been set.
- Gets a request header and returns the value as a string, or
- parameters:
- name: string
- return:
- value: string or
null
- value: string or
.headers() : requestHeaders
- description:
- Gets the request headers and returns the value as an object.
- return:
- headers: object
.headers( requestHeaders )
- description:
- Sets the request headers.
- parameters:
- headers: object
.body() : requestBody
- description:
- Gets the request body.
- return:
- body: string
.body( requestBody )
- description:
- Sets the request body.
- parameters:
- body: string
MockResponse
.status() : value
- description:
- Gets the response status.
- return:
- value: number
.status( code )
- description:
- Sets the response status.
- parameters:
- code: number
.reason() : responseReason
- description:
- Gets the response reason.
- return:
- reason: string
.reason( phrase )
- description:
- Set the response reason.
- parameters:
- phrase: string
.header( name , value )
- description:
- Sets a response header.
- parameters:
- name: string
- value: string
.header( name ) : value
- description:
- Gets a response header and returns the value as a string or
null
- Gets a response header and returns the value as a string or
- parameters:
- name: string
- return:
- value: string or
null
- value: string or
.headers() : responseHeaders
- description:
- Get the response headers.
- return:
- headers: object
.headers( responseHeaders )
- description:
- Set the response headers.
- parameters:
- headers: object
.body() : responseBody
- description:
- Get the response body.
- return:
- body: string
.body( ResponseBody )
- description:
- Set the response body.
- parameters:
- body: string
MockFunction Edit
MockFunction
- description:
- function object used by XHRMock object for processing requests.
- parameters:
- req: MockRequest object.
- res: MockResponse object.
- return:
- MockResponse object or
undefined
.
- MockResponse object or
MockURL Edit
MockUrl
.protocol
- property .protocol is a string and not required.
.username
- property .username is a string and not required.
.password
- property .password is a string and not required.
.host
- property .host is a string and not required.
.path
- property .path is a string and not required.
.port
- property .port is a number and is not required.
.query
- {[name: string]: string};
.hash
- property .hash is a string and is not required.
.toString()
- method .toString formats and returns the url as a string
Simulate progress Edit
Sets the Content-Length
header and sends a body. xhr-mock
will emit ProgressEvent
s.
import mock from 'xhr-mock';
mock.setup();
mock.post('/', {});
const xhr = new XMLHttpRequest();
xhr.upload.onprogress = event => console.log(event.loaded, event.total);
xhr.open('POST', '/');
xhr.setRequestHeader('Content-Length', '12');
xhr.send('Hello World!');
import mock from 'xhr-mock';
mock.setup();
mock.get('/', {
headers: {'Content-Length': '12'},
body: 'Hello World!'
});
const xhr = new XMLHttpRequest();
xhr.onprogress = event => console.log(event.loaded, event.total);
xhr.open('GET', '/');
xhr.send();
Simulate timeout Edit
Returns a Promise
that never resolves or rejects.
A number of major libraries don’t use the timeout
event and use setTimeout()
instead. Therefore, in order to mock timeouts in major libraries, we have to wait for the specified amount of time.
import mock from 'xhr-mock';
mock.setup();
mock.get('/', () => new Promise(() => {}));
const xhr = new XMLHttpRequest();
xhr.timeout = 100;
xhr.ontimeout = event => console.log('timeout');
xhr.open('GET', '/');
xhr.send();
Simulate error Edit
Returns a Promise
that rejects. If you want to test a particular error you use one of the pre-defined error classes.
import mock from 'xhr-mock';
mock.setup();
mock.get('/', () => Promise.reject(new Error()));
const xhr = new XMLHttpRequest();
xhr.onerror = event => console.log('error');
xhr.open('GET', '/');
xhr.send();
Proxy requests Edit
If you want to mock some requests, but not all of them, you can proxy unhandled requests to a real server.
import mock, {proxy} from 'xhr-mock';
mock.setup();
// mock specific requests.
mock.post('/', {status: 204});
// proxy unhandled requests to the real servers.
mock.use(proxy);
// this request will receive a mocked response.
const xhr1 = new XMLHttpRequest();
xhr1.open('POST', '/');
xhr1.send();
// this request will receive the real response.
const xhr2 = new XMLHttpRequest();
xhr2.open('GET', 'https://jsonplaceholder.typicode.com/users/1');
xhr2.send();
Delay requests Edit
Requests can be delayed using our handy delay
utility.
import mock, {delay} from 'xhr-mock';
mock.setup();
// delays the request for three seconds.
mock.post('/', delay({status: 201}, 3000));
One-off requests Edit
Requests can be made on one off occasions using our handy once
utility.
import mock, {once} from 'xhr-mock';
mock.setup();
// the response will only be returned the first time a request is made.
mock.post('/', once({status: 201}));