Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

return handler in reply(...) mocks in order to allow removing handler and monitoring calls #159

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,3 @@ language: node_js
node_js:
- "10"
- "8"
- "6"
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ var mock = new MockAdapter(axios);

// Mock any GET request to /users
// arguments for reply are (status, data, headers)
mock.onGet('/users').reply(200, {
var handler = mock.onGet('/users').reply(200, {
users: [
{ id: 1, name: 'John Smith' }
]
Expand All @@ -41,6 +41,9 @@ axios.get('/users')
.then(function(response) {
console.log(response.data);
});

// Assert mock was called
expect(handler.called).to.equal(1);
```

Mocking a `GET` request with specific parameters
Expand Down
1 change: 1 addition & 0 deletions mocha.opts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--file setupTests.js
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"name": "axios-mock-adapter",
"version": "1.16.0",
"engines" : { "node" : ">=8" },
"description": "Axios adapter that allows to easily mock requests",
"main": "src/index.js",
"scripts": {
Expand Down Expand Up @@ -43,6 +44,7 @@
"axios": "^0.18.0",
"chai": "^4.1.0",
"eslint": "^5.2.0",
"formdata-node": "^1.5.2",
"istanbul": "^0.4.5",
"mocha": "^5.2.0",
"rimraf": "^2.6.1",
Expand Down
1 change: 1 addition & 0 deletions src/handle_request.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ function handleRequest(mockAdapter, resolve, reject, config) {
);

if (handler) {
handler.called++;
if (handler.length === 7) {
utils.purgeIfReplyOnce(mockAdapter, handler);
}
Expand Down
13 changes: 10 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

var deepEqual = require('deep-equal');

var utils = require('./utils');
var handleRequest = require('./handle_request');

var VERBS = ['get', 'post', 'head', 'delete', 'patch', 'put', 'options', 'list'];
Expand Down Expand Up @@ -54,6 +55,10 @@ function MockAdapter(axiosInstance, options) {

MockAdapter.prototype.adapter = adapter;

MockAdapter.prototype.removeHandler = function removeHanlder(handler) {
utils.purgeIfReplyOnce(this, handler);
};

MockAdapter.prototype.restore = function restore() {
if (this.axiosInstance) {
this.axiosInstance.defaults.adapter = this.originalAdapter;
Expand All @@ -73,13 +78,13 @@ VERBS.concat('any').forEach(function(method) {
function reply(code, response, headers) {
var handler = [matcher, body, requestHeaders, code, response, headers];
addHandler(method, _this.handlers, handler);
return _this;
return handler;
}

function replyOnce(code, response, headers) {
var handler = [matcher, body, requestHeaders, code, response, headers, true];
addHandler(method, _this.handlers, handler);
return _this;
return handler;
}

return {
Expand All @@ -90,7 +95,7 @@ VERBS.concat('any').forEach(function(method) {
passThrough: function passThrough() {
var handler = [matcher, body];
addHandler(method, _this.handlers, handler);
return _this;
return handler;
},

networkError: function() {
Expand Down Expand Up @@ -151,6 +156,8 @@ function findInHandlers(method, handlers, handler) {
}

function addHandler(method, handlers, handler) {
handler.called = 0;
// const handler = originalHandler
if (method === 'any') {
VERBS.forEach(function(verb) {
handlers[verb].push(handler);
Expand Down
20 changes: 20 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,26 @@ function isParametersMatching(parameters, required) {
}

function isBodyMatching(body, requiredBody) {
if (typeof FormData !=='undefined' && requiredBody instanceof FormData) {
if (!(body instanceof FormData)) {
return false;
}
var requiredBodyFormData = {};
// eslint-disable-next-line
for (var pair of requiredBody.entries()) {
requiredBodyFormData[pair[0]] = pair[1];
}
var bodyFormData = {};
for (pair of body.entries()) {
bodyFormData[pair[0]] = pair[1];
}
for(var key in requiredBodyFormData) {
if(!(key in bodyFormData) || requiredBodyFormData[key]!==bodyFormData[key]) {
return false;
}
}
return true;
}
if (requiredBody === undefined) {
return true;
}
Expand Down
99 changes: 76 additions & 23 deletions test/basics.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
var axios = require('axios');
var expect = require('chai').expect;

var FormData = require('formdata-node').default;
var MockAdapter = require('../src');

describe('MockAdapter basics', function() {
Expand Down Expand Up @@ -101,8 +101,8 @@ describe('MockAdapter basics', function() {
it('accepts a callback that returns an axios request', function() {
mock
.onGet('/bar')
.reply(200, { foo: 'bar' })
.onGet('/foo')
.reply(200, { foo: 'bar' });
mock.onGet('/foo')
.reply(function() {
return instance.get('/bar');
});
Expand Down Expand Up @@ -216,6 +216,18 @@ describe('MockAdapter basics', function() {
});
});

it('allow removing mock handler', function() {
const handler = mock.onGet('/').reply(200);
return instance.get('/').then(function(response) {
expect(response.status).to.equal(200);
mock.removeHandler(handler);
return instance.get('/');
}).catch(function(error) {
expect(error.response.status).to.equal(404);
expect(handler.called).to.equal(1);
});
});

it('matches when parameters were not expected', function() {
mock.onGet('/withParams').reply(200);
return instance
Expand Down Expand Up @@ -311,6 +323,50 @@ describe('MockAdapter basics', function() {
});
});

describe('with FormData', function() {
it('works when multipart FormData body matches', function() {
var body = new FormData();
body.append('key', 'value');
var matchBody = new FormData;
matchBody.append('key', 'value');
mock.onPost('/formDataMatch', body).replyOnce(200);

return instance
.post('/formDataMatch', matchBody)
.then(function(response) {
expect(response.status).to.equal(200);
});
});

it('does not reply on FormData keys mismatch', function() {
var body = new FormData();
body.append('key', 'value');
var matchBody = new FormData;
matchBody.append('some-other-key', 'value');
mock.onPost('/formDataMatch', body).replyOnce(200);

return instance
.post('/formDataNoMatch', matchBody)
.catch(function(error) {
expect(error.response.status).to.equal(404);
});
});

it('does not reply on FormData data mismatch', function() {
var body = new FormData();
body.append('key', 'value');
var matchBody = new FormData;
matchBody.append('key', 'another value');
mock.onPost('/formDataMatch', body).replyOnce(200);

return instance
.post('/formDataNoMatch', matchBody)
.catch(function(error) {
expect(error.response.status).to.equal(404);
});
});
});

it('works when using baseURL', function() {
instance.defaults.baseURL = 'http://www.example.org';

Expand Down Expand Up @@ -466,10 +522,10 @@ describe('MockAdapter basics', function() {
it('can chain calls to add mock handlers', function() {
mock
.onGet('/foo')
.reply(200)
.onAny('/bar')
.reply(404)
.onPost('/baz')
.reply(200);
mock.onAny('/bar')
.reply(404);
mock.onPost('/baz')
.reply(500);

expect(mock.handlers['get'].length).to.equal(2);
Expand Down Expand Up @@ -510,10 +566,9 @@ describe('MockAdapter basics', function() {
});

it('maps empty GET path to any path', function() {
mock
.onGet('/foo')
.reply(200, 'foo')
.onGet()
mock.onGet('/foo')
.reply(200, 'foo');
mock.onGet()
.reply(200, 'bar');

return Promise.all([
Expand Down Expand Up @@ -636,14 +691,13 @@ describe('MockAdapter basics', function() {
});

it('supports chaining on same path with different params', function() {
mock
.onGet('/users', { params: { searchText: 'John' } })
.reply(200, { id: 1 })
.onGet('/users', { params: { searchText: 'James' } })
.reply(200, { id: 2 })
.onGet('/users', { params: { searchText: 'Jake' } })
.reply(200, { id: 3 })
.onGet('/users', { params: { searchText: 'Jackie' } })
mock.onGet('/users', { params: { searchText: 'John' } })
.reply(200, { id: 1 });
mock.onGet('/users', { params: { searchText: 'James' } })
.reply(200, { id: 2 });
mock.onGet('/users', { params: { searchText: 'Jake' } })
.reply(200, { id: 3 });
mock.onGet('/users', { params: { searchText: 'Jackie' } })
.reply(200, { id: 4 });

return instance
Expand Down Expand Up @@ -739,10 +793,9 @@ describe('MockAdapter basics', function() {
});

it('allows overwriting mocks with parameters', function() {
mock
.onGet('/users', { params: { searchText: 'John' } })
.reply(500)
.onGet('/users', { params: { searchText: 'John' } })
mock.onGet('/users', { params: { searchText: 'John' } })
.reply(500);
mock.onGet('/users', { params: { searchText: 'John' } })
.reply(200, { id: 1 });

return instance
Expand Down
5 changes: 2 additions & 3 deletions test/pass_through.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,8 @@ describe('passThrough tests (requires Node)', function() {
});

it('allows setting default passThrough handler', function() {
mock
.onGet('/foo').reply(200, 'bar')
.onAny().passThrough();
mock.onGet('/foo').reply(200, 'bar');
mock.onAny().passThrough();

var randomPath = 'xyz' + Math.round(10000 * Math.random());

Expand Down
17 changes: 2 additions & 15 deletions test/reply_once.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,6 @@ describe('MockAdapter replyOnce', function() {
mock = new MockAdapter(instance);
});

it('supports chaining', function() {
mock
.onGet('/foo')
.replyOnce(200)
.onAny('/foo')
.replyOnce(500)
.onPost('/foo')
.replyOnce(201);

expect(mock.handlers['get'].length).to.equal(2);
expect(mock.handlers['post'].length).to.equal(2);
});

it('replies as normally on the first call', function() {
mock.onGet('/foo').replyOnce(200, {
foo: 'bar'
Expand Down Expand Up @@ -90,8 +77,8 @@ describe('MockAdapter replyOnce', function() {
.onGet('/foo')
.replyOnce(function() {
return [200];
})
.onGet('/foo')
});
mock.onGet('/foo')
.replyOnce(function() {
return [202];
});
Expand Down
9 changes: 9 additions & 0 deletions test/setupTests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
var FormData = require('formdata-node').default;

beforeEach(function() {
global.FormData = FormData;
});

afterEach(function() {
delete global.FormData;
});
Loading