Skip to content

Commit

Permalink
Investigating new handlers structure (#115)
Browse files Browse the repository at this point in the history
* purge will only happen if array.length === 7

* merged test from overwrite-existing-mocks

* removed replyOnceHandlers

* added functionality to overwrite exisitng mocks that use .reply

* updated test to verify new code

* code cleanup

* resolved conflict

* fixed linting issues

* now checking matcher, body, and headers for deep equality

* added test for overwriting with params and headers

* Updated path check as we need to stringify the RegExp

* added test to check that regex overwrite properly

* removed deepEqual on scalar values

* added strict to avoid type coercion

* updated header test
  • Loading branch information
davidlewallen authored and ctimmerm committed Feb 15, 2018
1 parent fdfd66c commit 84e343e
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 19 deletions.
8 changes: 4 additions & 4 deletions src/handle_request.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,14 @@ function handleRequest(mockAdapter, resolve, reject, config) {
);

if (handler) {
utils.purgeIfReplyOnce(mockAdapter, handler);

if (handler.length === 2) {
// passThrough handler
if (handler.length === 2) { // passThrough handler
// tell axios to use the original adapter instead of our mock, fixes #35
config.adapter = mockAdapter.originalAdapter;
mockAdapter.axiosInstance.request(config).then(resolve, reject);
} else if (!(handler[3] instanceof Function)) {
if (handler.length === 7) {
utils.purgeIfReplyOnce(mockAdapter, handler);
}
utils.settle(
resolve,
reject,
Expand Down
33 changes: 29 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use strict';

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

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

var VERBS = ['get', 'post', 'head', 'delete', 'patch', 'put', 'options'];
Expand All @@ -24,7 +26,6 @@ function reset() {
accumulator[verb] = [];
return accumulator;
}, {});
this.replyOnceHandlers = [];
}

function MockAdapter(axiosInstance, options) {
Expand Down Expand Up @@ -64,9 +65,8 @@ VERBS.concat('any').forEach(function(method) {
reply: reply,

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

Expand Down Expand Up @@ -96,13 +96,38 @@ VERBS.concat('any').forEach(function(method) {
};
});

function findInHandlers(method, handlers, handler) {
var index = -1;
for (var i = 0; i < handlers[method].length; i += 1) {
var item = handlers[method][i];
var isReplyOnce = item.length === 7;
var comparePaths = item[0] instanceof RegExp && handler[0] instanceof RegExp
? String(item[0]) === String(handler[0])
: item[0] === handler[0];
var isSame = (
comparePaths &&
deepEqual(item[1], handler[1], { strict: true }) &&
deepEqual(item[2], handler[2], { strict: true })
);
if (isSame && !isReplyOnce) {
index = i;
}
}
return index;
}

function addHandler(method, handlers, handler) {
if (method === 'any') {
VERBS.forEach(function(verb) {
handlers[verb].push(handler);
});
} else {
handlers[method].push(handler);
var indexOfExistingHandler = findInHandlers(method, handlers, handler);
if (indexOfExistingHandler > -1 && handler.length < 7) {
handlers[method].splice(indexOfExistingHandler, 1, handler);
} else {
handlers[method].push(handler);
}
}
}

Expand Down
17 changes: 6 additions & 11 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,12 @@ function isBodyMatching(body, requiredBody) {
}

function purgeIfReplyOnce(mock, handler) {
var index = mock.replyOnceHandlers.indexOf(handler);
if (index > -1) {
mock.replyOnceHandlers.splice(index, 1);

Object.keys(mock.handlers).forEach(function(key) {
index = mock.handlers[key].indexOf(handler);
if (index > -1) {
mock.handlers[key].splice(index, 1);
}
});
}
Object.keys(mock.handlers).forEach(function(key) {
var index = mock.handlers[key].indexOf(handler);
if (index > -1) {
mock.handlers[key].splice(index, 1);
}
});
}

function settle(resolve, reject, response, delay) {
Expand Down
139 changes: 139 additions & 0 deletions test/basics.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -532,4 +532,143 @@ describe('MockAdapter basics', function() {
expect(data[0].bar).to.equal(123);
});
});

it('should overwrite existing mock', function() {
mock.onGet('/').reply(500);
mock.onGet('/').reply(200);

return instance
.get('/')
.then(function(response) {
expect(response.status).to.equal(200);
});
});

it('should not add duplicate handlers', function() {
mock.onGet('/').replyOnce(312);
mock.onGet('/').reply(200);
mock.onGet('/1').reply(200);
mock.onGet('/2').reply(200);
mock.onGet('/3').replyOnce(300);
mock.onGet('/3').reply(200);
mock.onGet('/4').reply(200);

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

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' } }).reply(200, { id: 4 });

return instance.get('/users', { params: { searchText: 'John' } })
.then(function(response) {
expect(response.data.id).to.equal(1);
return instance.get('/users', { params: { searchText: 'James' } });
})
.then(function(response) {
expect(response.data.id).to.equal(2);
return instance.get('/users', { params: { searchText: 'Jake' } });
})
.then(function(response) {
expect(response.data.id).to.equal(3);
return instance.get('/users', { params: { searchText: 'Jackie' } });
})
.then(function(response) {
expect(response.data.id).to.equal(4);
});
});

it('should overwrite replys', function() {
mock.onGet('/').reply(500);
mock.onGet('/').reply(200);
mock.onGet('/').reply(401);

return instance.get('/')
.catch(function(error) {
expect(mock.handlers['get'].length).to.equal(1);
expect(error.response.status).to.equal(401);
});
});

it('should overwrite replys using RegEx', function() {
mock.onGet(/foo\/bar/).reply(500);
mock.onGet(/foo\/bar/).reply(200);
mock.onGet(/foo\/baz\/.+/).reply(200);

return instance.get('/foo/bar')
.then(function(response) {
expect(mock.handlers['get'].length).to.equal(2);
expect(response.status).to.equal(200);
return instance.get('/foo/baz/56');
})
.then(function(response) {
expect(response.status).to.equal(200);
});
});

it('should allow overwriting only on reply if replyOnce was used first', function() {
var counter = 0;
mock.onGet('/').replyOnce(500);
mock.onGet('/').reply(200);
mock.onGet('/').reply(401);

return instance.get('/')
.catch(function(error) {
expect(error.response.status).to.equal(500);
counter += 1;
return instance.get('/');
})
.catch(function(error) {
expect(error.response.status).to.equal(401);
counter += 1;
})
.then(function() {
expect(counter).to.equal(2);
});
});

it('should not allow overwriting only on reply if replyOnce wasn\'t used first', function() {
var counter = 0;
mock.onGet('/').reply(200);
mock.onGet('/').reply(401);
mock.onGet('/').replyOnce(500);
mock.onGet('/').reply(500);

return instance.get('/')
.catch(function(error) {
expect(error.response.status).to.equal(500);
counter += 1;
return instance.get('/');
})
.catch(function(error) {
expect(error.response.status).to.equal(500);
counter += 1;
})
.then(function() {
expect(counter).to.equal(2);
});
});
it('allows overwriting mocks with parameters', function() {
mock
.onGet('/users', { params: { searchText: 'John' } })
.reply(500)
.onGet('/users', { params: { searchText: 'John' } })
.reply(200, { id: 1 });

return instance.get('/users', { params: { searchText: 'John' } })
.then(function(response) {
expect(response.status).to.equal(200);
});
});

it.only('allows overwriting mocks with headers', function() {
mock.onGet('/', {}, { 'Accept-Charset': 'utf-8' }).reply(500);
mock.onGet('/', {}, { 'Accept-Charset': 'utf-8' }).reply(200);

expect(mock.handlers['get'].length).to.equal(1);
expect(mock.handlers['get'][0][3]).to.equal(200);
});
});

0 comments on commit 84e343e

Please # to comment.