ctimmerm / axios-mock-adapter Goto Github PK
View Code? Open in Web Editor NEWAxios adapter that allows to easily mock requests
License: MIT License
Axios adapter that allows to easily mock requests
License: MIT License
Hi, my current project has a baseUrl for our Axios instance, and the mocking is not working.
After check axios-mock-adapter source code. It seems like when u add url matcher, it doesn't add axios baseUrl in the handlers array.
Axios will merge the url and baseUrl before call the actual adapter, So I think you should consider about this.
//line 7 on index.js
function adapter() {
var url = config.url.slice(config.baseURL ? config.baseURL.length : 0);
var handler = utils.findHandler(this.handlers, config.method, url);
I got code like this
method.js
export function deleteImageFromServer(id){
return axios.post('http://localhost:8000/'+'delete', {id:id})
}
home.spec.js
import {deleteImageFromServer} from './method'
import MockAdapter from 'axios-mock-adapter'
import axios from 'axios'
import {expect} from 'chai'
describe('deleteImageFromServer', function () {
it('should delete image', function () {
let mock = new MockAdapter(axios)
mock.onPost('http://localhost:8000/delete').reply(function(){
return [200, 'success']
})
deleteImageFromServer(1).then( (r) =>{
expect(r.data).to.equal('success')
})
})
})
I don't know why the intercept never happens.
Looks like the mock adapter is not mutating the config by changing "/path/here?param1=value" to include:
params: {
param1: value
}
I came up with a workaround, but it is kind of sloppy. Importing the url
module and doing this on many calls:
.......
mockAdapter.onGet(/\/path\/here\/?(|\?.*)).reply((config) => {
const parsedUrl = url.parse(url.resolve(config.baseURL, config.url), true, true);
config.params = parsedUrl.query;
.......
Hello,
I am using axios-mock-adapter with big sucees. Thank you very much for it.
However, recently I'been forced to change my app so it can be served from a subdomain.
This forced me to edit all mockup definitions, adding a base path to all of them.
It would be ideally to be able to define a baseUrl like axios allows.
thanks and regards
This the recent change on master, the use of timeout()
returns an UNKNOWN_ERROR instead of a TIMEOUT_ERROR
{
duration: 1,
problem: 'UNKNOWN_ERROR',
ok: false,
status: null,
headers: null,
...
}
Axios supports cancel a request with config.cancelToken
. Its adapters have code to handle cancellation also. Can we add this ability to this library? https://github.com/mzabriskie/axios/blob/master/lib/adapters/http.js#L211
I saw that the findHandler
does not handle the request options as object
axios-mock-adapter/src/utils.js
Line 25 in 817ccd0
that the cause why this doesn't works
mock.onGet('/foo').reply(200, {
foo: 'bar'
});
return instance.get({ url: '/foo' }).then(function(response) {
expect(response.status).to.equal(200);
expect(response.data.foo).to.equal('bar');
});
Here the opt
is not handled as object
axios-mock-adapter/src/handle_request.js
Line 20 in 817ccd0
when i use passThrough feature,the passThrough request will trigger axios response interceptor twice.
Is there a way that we can customize the response? For example, I would like to change the name of data to json in the response to match our actual data. Anyway currently available to do that or is this something you would consider adding?
Great library! Working great for most of my tests.
On this occasion I'm trying to test my async login actions in redux as follows:
action:
export const submitLoginData = (data, location) => dispatch => {
dispatch(loggingIn());
return axios({
method: 'get',
url: '/api/authorize',
auth: {
username: data.email,
password: data.password
}
})
etc.
test:
let postData = {
email: 'Joe',
password: 'Bloggs'
};
let responseData = {
token: 'foo'
};
mock.onGet('/api/authorize')
.reply(200, responseData);
store = mockStore();
return store.dispatch(actions.submitLoginData(postData, '/'))
.then(() => {
actual = store.getActions();
expected = [
{ type: actions.LOGGING_IN },
{ type: actions.LOGIN_SUCCESS }
];
expect(actual).to.eql(expected);
done();
});
However I'm getting a 404 error. Could this be because I need to configure the route to correctly respond to HTTP basic auth? Has anyone achieved this previously?
Should have typescript definition files in the repository
Repro:
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter'
const mock = new MockAdapter(axios);
mock.onPost('/myurl').reply(200, {});
axios('/myurl', { method: 'POST' })
Expected: interceptor to work properly
Actual:
TypeError: Cannot read property 'find' of undefined
Culprit appears to be index.js line 4. If I change the http method to post
instead of POST
everything works as expected
I had side effects between tests because of the mocks. I had 2 files on the following model:
import axios from 'axios'
import MockAdapter from 'axios-mock-adapter'
const mock = new MockAdapter(axios)
describe('eventsActions', () => {
afterEach(() => {
mock.reset()
})
describe('changePreferences', () => {
it('should call /api/users/preferences and dispatch events', (done) => {
mock.onPost('/api/users/preferences')
.reply(200)
...
When run alone, each file end with success but when run together, the calls to one url are 404.
I suspected a side effect due to poor cleaning and I looked at the tests on this repo. My tests now works by removing the afterEach and adding
beforeEach(() => {
mock = new MockAdapter(axios)
})
So, problem solved, but I am curious. Is this the intended use ? When am I supposed to use reset() and restore() ?
Thank you
Question: Is there a method to mock a network failure, say if the browser was offline trying to connect to an online resource?
There's any way to specify request headers and match against them? I need to do it in order to return proper data based on X-CSRF-TOKEN.
Hi, I don't know what I'm doing wrong but every time I try to mock axios it raises this exception:
TypeError: Cannot set property 'handlers' of undefined
at reset (node_modules/axios-mock-adapter/src/index.js:23:17)
at MockAdapter (node_modules/axios-mock-adapter/src/index.js:31:9)
Digging into the source code I can see that it's happening when creating a new mock, my code is like this:
import Axios from 'axios';
import mockAdapter from 'axios-mock-adapter';
...
const httpMock = mockAdapter(Axios); // here it raises the exception
httpMock.onGet('/providers').reply(200, ['Provider1', 'Provider2', 'Provider3']);
Thanks in advance
Tracked down the issue to https://github.com/ctimmerm/axios-mock-adapter/pull/32/files#diff-2b4ca49d4bb0a774c4d4c1672d7aa781R32
The problem is that method is all uppercase
Hi,
Trying to write an onPost that checks the arguments passed, but not having any luck. Dug through your source code, but what would be really helpful would be at least one example in the README of using arguments in the request:
My Code
Axios.post('/api/estimate', {
_id: '123'
})
This "works" but doesn't check arguments:
mockServer.onPost('/api/estimate').reply(200, { text: 'stuff to reply with' })
This doesn't work:
mockServer.onPost('/api/estimate', {
_id: '123'
}).reply(200, { text: 'stuff to reply with' })
Also doesn't work
mockServer.onPost('/api/estimate', {
request:
_id: '123'
}
}).reply(200, { text: 'stuff to reply with' })
Also doesn't work
mockServer.onPost('/api/estimate', {
body:
_id: '123'
}
}).reply(200, { text: 'stuff to reply with' })
Etc. You get the idea. Would be really helpful if you could provide just one simple example... Thank you!
hi
Writing test code
describe('MemberAction', () => {
beforeEach(() => {
mock = new MockAdapter(axios, {delayResponse:10 });
const middlewares = [ thunk ];
mockStore = configureMockStore(middlewares);
store = mockStore({ actions: [] })
});
describe('member Join',()=>{
beforeEach(() => {
mock.onPost(`/account/actors/23/set_student_member/`,{"human_name":"child","is_male":true,"birthday":"2014-10-30"}).reply(200, setStudentMemberRes)
}
it(('regist join')=>{
//call post /account/actors/23/set_student_member/
})
})
}
Error: Request failed with status code 404
config:
{ adapter: null,
transformRequest: { '0': [Function: transformRequest] },
transformResponse: { '0': [Function: transformResponse] },
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-CSRFToken',
maxContentLength: -1,
validateStatus: [Function: validateStatus],
headers:
{ Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json;charset=utf-8' },
withCredentials: true,
method: 'post',
url: '/account/actors/23/set_student_member/',
data: '{"human_name":"child","is_male":false,"birthday":"2016-11-29"}' },
Is anything expected?
Is there any reason why no exists this option?
Thanks
Hi Team,
I have a click function for fetching the records through API call, the function looks like below,
onClick(rollNo){
axios({
url: '/api/getStudentDetail/'+rollNo,
method: 'get',
headers: {
'Content-type': 'text/csv'
}
}).then(function (successData) {
console.log(successData.data);
}.bind(this)).catch(function (errorData) {
console.log(errorData.data);
}.bind(this));
}
I am trying to mock this axios call using axios mock adapter as below,
it('should test StudentContainer ', function (done) {
const wrapper = shallow(<StudentContainer />);
const button= wrapper.find('button').at(0);
var rollNo = 'A016SS1245';
button.simulate('click', [rollNo]);
mock.reset();
mock.onGet('/api/getStudentDetail/').reply(200, {
firstName: 'John',
lastName: 'smith'
});
axios.get('/api/getStudentDetail/')
.then(function(response) {
console.log(response);
});
done();
});
While running this testcase, it every time execute the catch block, rather than then block. Can anyone help me on how to mock this axios call using axios mock adapter.
Hi, this might be a bit of an edge case but it did drive me crazy for a couple of hours today until I realised what was going on. Basically, there is an inconsistency in how the axios library and axios-mock-adapter behave when axios is set up with a baseUrl
that contains a trailing slash.
I've set up a little test to showcase the issue:
var axios = require('axios');
var expect = require('chai').expect;
var createServer = require('http').createServer;
var MockAdapter = require('../src');
describe('trailing slash in axios baseUrl issue (requires Node)', function() {
var instance;
var mock;
var httpServer;
var serverUrl;
before('set up Node server', function() {
return new Promise(function(resolve, reject) {
httpServer = createServer(function(req, resp) {
if (req.url === '/error') {
resp.statusCode = 500;
resp.end();
} else {
resp.statusCode = 200;
// Reply with path minus leading /
resp.end(req.url.slice(1), 'utf8');
}
})
.listen(0, '127.0.0.1', function() {
serverUrl = 'http://127.0.0.1:' + httpServer.address().port;
resolve();
})
.on('error', reject);
});
});
beforeEach(function() {
instance = axios.create({ baseURL: serverUrl + '/' }); // baseUrl has a trailing slash
mock = new MockAdapter(instance);
});
it('axios should handle trailing slash in baseUrl', function() { // passes
mock.onAny().passThrough();
return Promise.all([
instance.get('/foo')
.then(function(response) {
expect(response.status).to.equal(200);
expect(response.data).to.equal('foo');
}),
instance.get('foo')
.then(function(response) {
expect(response.status).to.equal(200);
expect(response.data).to.equal('foo');
})
]);
});
it('mock adapter should handle trailing slash in baseUrl', function() { // both fail: 404
mock.onGet('/foo').reply(200, 'bar');
return Promise.all([
instance.get('/foo')
.then(function(response) {
expect(response.status).to.equal(200);
expect(response.data).to.equal('bar');
}),
instance.get('foo')
.then(function(response) {
expect(response.status).to.equal(200);
expect(response.data).to.equal('bar');
})
]);
});
});
I'll open a PR with a fix, as I think it's important that we should mimic axios behaviour seamlessly.
It would be raaaad if I could do something like this:
mock.onPost(`/tests`).reply((data) => {
return doSomething(data.data)
.then((intermediate) => doSomethingElse(intermediate))
.then((final) => final ? [200, final] : [404, {}])
.catch((err) => [500, err]);
});
instead, it looks like the .reply handler expects an immediate reply, instead of a deferred.
when i send a post request which be passed to network,the data in body lost. And it is normal after i close mock.
ver: 1.9.0, os: macOS, browser: Chrome 59.0.3071.104
I would be nice to have the ability to turn mocking on
during development. The library currently has the method reset
, which removes the handlers, and restore
which removes mocking from axios. However, there is currently no possiblity to stop mocking, remember the added handlers and start mocking again. Think the opposite of restore
, but on an already initialized adapter.
Or it's already possible and I can't figure out why.
Hi Team,
I have a click function for fetching the records through API call, the function looks like below,
onClick(rollNo){
axios({
url: '/api/getStudentDetail/'+rollNo,
method: 'get',
headers: {
'Content-type': 'text/csv'
}
}).then(function (successData) {
console.log(successData.data);
}.bind(this)).catch(function (errorData) {
console.log(errorData.data);
}.bind(this));
}
I am trying to mock this axios call using axios mock adapter as below,
it('should test StudentContainer ', function (done) {
const wrapper = shallow(<StudentContainer />);
const button= wrapper.find('button').at(0);
var rollNo = 'A016SS1245';
mock.reset();
mock.onGet('/api/getStudentDetail/' + rollNo).reply(200, {
firstName: 'John',
lastName: 'smith'
});
button.simulate('click', [rollNo]);
axios.get('/api/getStudentDetail/')
.then(function(response) {
console.log(response);
});
done();
});
While running this testcase, it every time execute the catch block, rather than then block. Can anyone help me on how to mock this axios call using axios mock adapter.
@ctimmerm, also i tried as you said in previous post its not working, and this is the respone i get when i run the test script,
Error: the object {
"config": {
"adapter": [Function]
"data": [undefined]
"headers": {
"Accept": "application/json, text/plain, /"
}
"maxContentLength": -1
"method": "get"
"timeout": 0
"transformRequest": {
"0": [Function]
}
"transformResponse": {
"0": [Function]
}
"url": '/api/getStudentDetail/'
"validateStatus": [Function]
"withCredentials": [undefined]
"xsrfCookieName": "XSRF-TOKEN"
"xsrfHeaderName": "X-XSRF-TOKEN"
}
"status": 404
was thrown, throw an Error :)
Could you please help me in resolving this issue.
Doing this request
return axios({
method: method,
url: uri,
headers: {
'PRIVATE-TOKEN': GITLAB_TOKEN
},
data: body || {},
params: query || {}
})
.then(response => {
if (response.status === 429) {
throw new Error('gitlab rate limit reached')
}
console.log(response)
})
.catch(err => {
console.log(err)
})
with
const axios = require('axios')
const MockAdapter = require('axios-mock-adapter')
const mock = new MockAdapter(axios)
require('./blog')(mock)
mock.onAny().passThrough()
blog.js looks like this
module.exports = function (mock) {
mock.onGet(/^\/api\/blog/).reply(200, [
{
Title: 'Item 1',
Content: 'Much content here'
},
{
Title: 'Item 2',
Content: 'Much much content here'
}
])
}
The blog
mock is unrelated to the above axios request. No other mocking is done, its very basic right now.
This results in page being unresponsive, until it runs out of memory.
Mock should do deep clone and return new response every time it is invoked. Example if we set below mock
mock.onGet('/users').reply(200, {
someProp: [
{
id: 1,
nextLevel: {
nestedProp: "Hi this value will be shared with all the response generated by this mock"
}
}
]
})
and if we test below in actual function
var someState = ...
var someFunc = function() {
axios.get('/users')
.then(function(response) {
// some modification in someState based on response.data.someProp[0].nextLevel.nestedProp
// also some change in nestedProp
});
}
if we test above function multiple times change in nestedProp
will be carried forward to other test cases
Hi @ctimmerm,
it seems, that 1.8.0 broke the behaviour of onGet
.
Before all GET requests matching my URL defined in onGet
landed the reply callback function.
Now I have to explicitly define EVERY SINGLE parameter, to have that match.
Example:
GET /users?q=Adam
mock.onGet('/users').reply(conf => {
// not reached!!
});
mock.onGet('/users', { params: { q: 'Adam' }}).reply(conf => {
// reached
});
When using a regex expression, requests don't get caught by the adapter in some cases
This works :
const axios = axios.create({
baseURL: 'https://apiurl.com'
})
axios.get('/foo/123').then(function (data) {
console.log(data)
})
mock.onGet(/\/foo\/\d+/).reply(function(config) {
return [200, {}];
})
This doesn't :
const axios = axios.create({
baseURL: 'https://apiurl.com/'
})
axios.get('/foo/123').then(function (data) {
console.log(data)
})
mock.onGet(/\/foo\/\d+/).reply(function(config) {
return [200, {}];
})
It is due to the trailing slash in the baseURL.
Is there a way to fix that (in handleRequest function for example) or at least change the documentation ?
// error code
import Axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
const mock = new MockAdapter(Axios);
// start mock
mock.onAny().passThrough();
// end mock
Axios.get('/host/path')
// correct code
import Axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
const mock = new MockAdapter(Axios);
// start mock
mock.onAny().passThrough();
// end mock
const axiosIns = Axios.create();
axiosIns.get('/host/path')
Hello!
I started to use this library since I switched my work from Angular to React and axios for http-requests. Thank you for this package, that was really a missing feature.
Now I have a lack of matching body for requests with payload. I'd like to do something like this:
mock.onPost('/api/users', {name: 'new user', email: '[email protected]'}).reply(200);
Then I can to test not only that request was actually called, but also that it has proper body. That feature was built-in in Angular's mock library, so it would be nice to have it there as well.
Hi.
Is there a way to mock multiple get requests originally managed by the all() method?
I saw the last section of the doc ("Composing from multiple sources with Promises:") but I'm not sure this is what I need and if so how to deal with it.
Any suggestions?
Thanks.
Testing some re-authentication logic that retries a request after refreshing. Snippet should be fairly explanatory:
context('when auth token has expired', () => {
const code = 'auth_token_expired';
const refresh = { refresh_token: 'refresh', user: {} };
const user = { name: 'bob' };
const success = { results: [], totalCount: 0 };
context('when refresh succeeds', () => {
beforeEach(() => {
spyOn(session, 'refreshToken').andReturn('refresh');
mockAdapter.onGet(endpoint).replyOnce(401, { code })
.onGet(endpoint).replyOnce(200, success)
.onPost('/sessions/refresh').reply(200, refresh);
});
it('retries the original request', (done) => {
adapter.get(endpoint).then((resp) => {
expect(response).toEqual(success);
}).catch(e => {
debugger
});
});
The first call to endpoint
gives me a 401, but the second one gives me a 404. I suspect it's due to the way I'm executing the second call:
adapter.interceptors.response.use(undefined, (error) => {
if (error.response.status === 401) {
if (error.response.data.code === 'auth_token_expired') {
const refresh = session.refreshToken();
if (refresh) {
return adapter.post('/sessions/refresh', { refresh_token: refresh }).then((resp) => {
session.login(resp.data);
return adapter(error.config);
}).catch((e) => {
When I call adapter(error.config)
, the effect is that the endpoint is called again, but I don't think axios-mock-adapter
recognizes it as being the same call. Is this a bug, or expected? Is there a way I can work around it?
Can Not Mocking a request with a specific request body/data by POST
like this:
mock.onPost('/product', { id: 4, name: 'foo' }).reply(204);
mock.onGet('/users').reply(200, [{
"name": "jd"
}]);
Dosen't work when it's an array.
I'm guessing it expects the response to only be an object
I'm making the following request:
axios.get('/api', { params: { name: 'Bob' }})
...
And I'm trying to mock it like so:
mock.onGet('/api', { params: { name: 'Bob' } }).reply(200, 'Hello')
But it keeps returning a 404. I also tried the following to no avail:
mock.onGet('/api', { name: 'Bob' }).reply(200, 'Hello')
mock.onGet('/api?name=Bob').reply(200, 'Hello')
The only thing that matches it is:
mock.onGet('/api').reply(200, 'Hello')
How can I match against and mock get
requests with specific query params?
In Angular testing for a service that implements $http
, we're using to doing this:
$httpBackend.flush();
What this does is it takes any outstanding requests and processes them so that you can then begin the assertion process. See its docs for more.
Anyway, I'm bringing this up as an example because it would be really nice to be able to have this for the axios mocker. Instead of this flush() method or something similar, we're forced to create a timeout with a zero millisecond duration and then nest all of our expectations within that timeout. For an example of this, see here:
import { expect } from 'chai';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { fetchPost } from './lib'
describe('Lib', () => {
it('Should return data from response', (done) => {
let mockAdapter = new MockAdapter(axios);
mockAdapter.onGet('http://awesome.com/posts').reply(200, {
data: {
posts: ['Intro to git']
}
});
let response = fetchPost();
setTimeout(() => {
expect(response.posts[0]).to.be.equal('Intro to git');
done();
}, 0)
});
});
I've confirmed in my own local code that without the timeout, you indeed cannot expect response.posts[0]
to be resolved, but you can inside the timeout. I don't like this syntax though because it forces all of the code to be nested another level, it's not as linear, and it assumes some things about how your axios promiser is implemented (e.g. it breaks on an otherwise perfectly functioning custom wrapper that I wrote for fun).
Would it be possible to have some sort of $httpBackend.flush();
equivalent for this axios mocker?
Thanks!
Such as the method 'networkError', 'timeout' , there is no
Hi guys
given below:
import axios from 'axios'; import mockAdaptor from 'axios-mock-adapter'; let mock = new mockAdaptor(axios, {delayResponse: 2000});
Is it possible to conditionally hit mocked/real endpoint if the route matches a certain condition? for example
if i hit http://localhost/login then i want to hit real endpoint, while http://localhost/register should hit be intercepted by mock adaptor and give the mocked response.
After axios update i sadly can't use passThrough anymore - browser is freezing. After switching axios back to 0.15.2 it is working again.
Hi @ctimmerm,
I'm having an "axios.create() is not a function error" when i try to use axios-mock-adapter. Here's the implementation.
`
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
let mock = new MockAdapter(axios);
mock.onGet('https://myapi.org/v1/', { params: { param1: 'holiday', sortBy:'top' } }).reply(200, {
data: [{
author: "Vivian Michaels",
}]
});
axios.get('https://myapi.org/v1/', { params: { param1: 'holiday', sortBy:'top' } })
.then(function(response) {
console.log(response.data);
});`
I'm doing exactly as the documentation says but then i get the error: TypeError: axios.create is not a function. Any help is appreciated.
I have tried
import {MockAdapter} from 'axios-mock-adapter';
but MockAdapter is undefined
@mzabriskie already addressed some of those Breaking Changes in #12, but there is also the change that rejected responses should now reject with an error object with the response attached as error.response and not only with the response. See https://github.com/mzabriskie/axios/blob/master/UPGRADE_GUIDE.md#error-handling.
This makes my test fail when updating my code to work with the new axios version.
I have my mocks set up like to:
mock
.onGet('/foo').reply(200)
.onAny().reply(500);
However, when I make a request to /bar
, a 404
code is returned instead of my specified 500
. Changing this to .onAny('/bar')
or .onAny(/.*/)
works as expected.
I am using axios v0.14.0 and axios-mock-adapter v1.6.1.
I am looking for a way to verify that the JSON in my request is structured properly for the API on the server. (I don't want to match routes or methods against certain request parameters.) Is the only way to inspect the request data via the config.data
property in the .reply()
method?
For example, I'm doing something like this now:
mock.onPost().reply( ({data}) => {
expect(data.items.length).not.toBe(0);
expect(data.title).toBe("my test title");
// etc...
done();
});
but using .reply()
for this seems somewhat counterintuitive and I'm wondering if I'm missing something.
Anyway to reply with the exact data that were posted?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.