Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/ctimmerm/axios-mock-adapter

Axios adapter that allows to easily mock requests
https://github.com/ctimmerm/axios-mock-adapter

axios javascript mock mocking

Last synced: 14 days ago
JSON representation

Axios adapter that allows to easily mock requests

Awesome Lists containing this project

README

        

# axios-mock-adapter

Axios adapter that allows to easily mock requests

## Installation

Using npm:

`$ npm install axios-mock-adapter --save-dev`

It's also available as a UMD build:

- https://unpkg.com/axios-mock-adapter/dist/axios-mock-adapter.js
- https://unpkg.com/axios-mock-adapter/dist/axios-mock-adapter.min.js

axios-mock-adapter works on Node as well as in a browser, it works with axios v0.17.0 and above.

## Example

Mocking a `GET` request

```js
const axios = require("axios");
const AxiosMockAdapter = require("axios-mock-adapter");

// This sets the mock adapter on the default instance
const mock = new AxiosMockAdapter(axios);

// Mock any GET request to /users
// arguments for reply are (status, data, headers)
mock.onGet("/users").reply(200, {
users: [{ id: 1, name: "John Smith" }],
});

axios.get("/users").then(function (response) {
console.log(response.data);
});
```

Mocking a `GET` request with specific parameters

```js
const axios = require("axios");
const AxiosMockAdapter = require("axios-mock-adapter");

// This sets the mock adapter on the default instance
const mock = new AxiosMockAdapter(axios);

// Mock GET request to /users when param `searchText` is 'John'
// arguments for reply are (status, data, headers)
mock.onGet("/users", { params: { searchText: "John" } }).reply(200, {
users: [{ id: 1, name: "John Smith" }],
});

axios
.get("/users", { params: { searchText: "John" } })
.then(function (response) {
console.log(response.data);
});
```

When using `params`, you must match _all_ key/value pairs passed to that option.

To add a delay to responses, specify a delay amount (in milliseconds) when instantiating the adapter

```js
// All requests using this instance will have a 2 seconds delay:
const mock = new AxiosMockAdapter(axiosInstance, { delayResponse: 2000 });
```

You can restore the original adapter (which will remove the mocking behavior)

```js
mock.restore();
```

You can also reset the registered mock handlers with `resetHandlers`

```js
mock.resetHandlers();
```

You can reset both registered mock handlers and history items with `reset`

```js
mock.reset();
```

`reset` is different from `restore` in that `restore` removes the mocking from the axios instance completely,
whereas `reset` only removes all mock handlers that were added with onGet, onPost, etc. but leaves the mocking in place.

Mock a low level network error

```js
// Returns a failed promise with Error('Network Error');
mock.onGet("/users").networkError();

// networkErrorOnce can be used to mock a network error only once
mock.onGet("/users").networkErrorOnce();
```

Mock a network timeout

```js
// Returns a failed promise with Error with code set to 'ECONNABORTED'
mock.onGet("/users").timeout();

// timeoutOnce can be used to mock a timeout only once
mock.onGet("/users").timeoutOnce();
```

Passing a function to `reply`

```js
mock.onGet("/users").reply(function (config) {
// `config` is the axios config and contains things like the url

// return an array in the form of [status, data, headers]
return [
200,
{
users: [{ id: 1, name: "John Smith" }],
},
];
});
```

Passing a function to `reply` that returns an axios request, essentially mocking a redirect

```js
mock.onPost("/foo").reply(function (config) {
return axios.get("/bar");
});
```

Using a regex

```js
mock.onGet(/\/users\/\d+/).reply(function (config) {
// the actual id can be grabbed from config.url

return [200, {}];
});
```

Using variables in regex

```js
const usersUri = "/users";
const url = new RegExp(`${usersUri}/*`);

mock.onGet(url).reply(200, users);
```

Specify no path to match by verb alone

```js
// Reject all POST requests with HTTP 500
mock.onPost().reply(500);
```

Chaining is also supported

```js
mock.onGet("/users").reply(200, users).onGet("/posts").reply(200, posts);
```

`.replyOnce()` can be used to let the mock only reply once

```js
mock
.onGet("/users")
.replyOnce(200, users) // After the first request to /users, this handler is removed
.onGet("/users")
.replyOnce(500); // The second request to /users will have status code 500
// Any following request would return a 404 since there are
// no matching handlers left
```

Mocking any request to a given url

```js
// mocks GET, POST, ... requests to /foo
mock.onAny("/foo").reply(200);
```

`.onAny` can be useful when you want to test for a specific order of requests

```js
// Expected order of requests:
const responses = [
["GET", "/foo", 200, { foo: "bar" }],
["POST", "/bar", 200],
["PUT", "/baz", 200],
];

// Match ALL requests
mock.onAny().reply((config) => {
const [method, url, ...response] = responses.shift();
if (config.url === url && config.method.toUpperCase() === method)
return response;
// Unexpected request, error out
return [500, {}];
});
```

Requests that do not map to a mock handler are rejected with a HTTP 404 response. Since
handlers are matched in order, a final `onAny()` can be used to change the default
behaviour

```js
// Mock GET requests to /foo, reject all others with HTTP 500
mock.onGet("/foo").reply(200).onAny().reply(500);
```

Mocking a request with a specific request body/data

```js
mock.onPut("/product", { id: 4, name: "foo" }).reply(204);
```

Using an asymmetric matcher, for example Jest matchers

```js
mock
.onPost(
"/product",
{ id: 1 },
{
headers: expect.objectContaining({
Authorization: expect.stringMatching(/^Basic /),
})
}
)
.reply(204);
```

Using a custom asymmetric matcher (any object that has a `asymmetricMatch` property)

```js
mock
.onPost("/product", {
asymmetricMatch: function (actual) {
return ["computer", "phone"].includes(actual["type"]);
},
})
.reply(204);
```

`.passThrough()` forwards the matched request over network

```js
// Mock POST requests to /api with HTTP 201, but forward
// GET requests to server
mock
.onPost(/^\/api/)
.reply(201)
.onGet(/^\/api/)
.passThrough();
```

Recall that the order of handlers is significant

```js
// Mock specific requests, but let unmatched ones through
mock
.onGet("/foo")
.reply(200)
.onPut("/bar", { xyz: "abc" })
.reply(204)
.onAny()
.passThrough();
```

Note that `passThrough` requests are not subject to delaying by `delayResponse`.

If you set `onNoMatch` option to `passthrough` all requests would be forwarded over network by default

```js
// Mock all requests to /foo with HTTP 200, but forward
// any others requests to server
const mock = new AxiosMockAdapter(axiosInstance, { onNoMatch: "passthrough" });

mock.onAny("/foo").reply(200);
```

Using `onNoMatch` option with `throwException` to throw an exception when a request is made without match any handler. It's helpful to debug your test mocks.

```js
const mock = new AxiosMockAdapter(axiosInstance, { onNoMatch: "throwException" });

mock.onAny("/foo").reply(200);

axios.get("/unexistent-path");

// Exception message on console:
//
// Could not find mock for:
// {
// "method": "get",
// "url": "http://localhost/unexistent-path"
// }
```

As of 1.7.0, `reply` function may return a Promise:

```js
mock.onGet("/product").reply(function (config) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
if (Math.random() > 0.1) {
resolve([200, { id: 4, name: "foo" }]);
} else {
// reject() reason will be passed as-is.
// Use HTTP error status code to simulate server failure.
resolve([500, { success: false }]);
}
}, 1000);
});
});
```

Composing from multiple sources with Promises:

```js
const normalAxios = axios.create();
const mockAxios = axios.create();
const mock = new AxiosMockAdapter(mockAxios);

mock
.onGet("/orders")
.reply(() =>
Promise.all([
normalAxios.get("/api/v1/orders").then((resp) => resp.data),
normalAxios.get("/api/v2/orders").then((resp) => resp.data),
{ id: "-1", content: "extra row 1" },
{ id: "-2", content: "extra row 2" },
]).then((sources) => [
200,
sources.reduce((agg, source) => agg.concat(source)),
])
);
```

## History

The `history` property allows you to enumerate existing axios request objects. The property is an object of verb keys referencing arrays of request objects.

This is useful for testing.

```js
describe("Feature", () => {
it("requests an endpoint", (done) => {
const mock = new AxiosMockAdapter(axios);
mock.onPost("/endpoint").replyOnce(200);

feature
.request()
.then(() => {
expect(mock.history.post.length).toBe(1);
expect(mock.history.post[0].data).toBe(JSON.stringify({ foo: "bar" }));
})
.then(done)
.catch(done.fail);
});
});
```

You can clear the history with `resetHistory`

```js
mock.resetHistory();
```