diff --git a/README.md b/README.md index 58f7e36..0e30493 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ Mock a low level network error // Returns a failed promise with Error('Network Error'); mock.onGet('/users').networkError(); -// networkErrorOnce can be used to mock a network error only once +// networkErrorOnce can be used to mock a network error only once mock.onGet('/users').networkErrorOnce(); ``` @@ -110,7 +110,7 @@ Mock a network timeout // 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 +// timeoutOnce can be used to mock a timeout only once mock.onGet('/users').timeoutOnce(); ``` @@ -245,6 +245,17 @@ mock Note that `passThrough` requests are not subject to delaying by `delayResponse`. +If you set `passThroughByDefault` option 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 +var mock = new MockAdapter(axiosInstance, { passThroughByDefault: true }); + +mock + .onAny('/foo').reply(200); +``` + As of 1.7.0, `reply` function may return a Promise: ```js diff --git a/src/handle_request.js b/src/handle_request.js index 7ad2bb0..d343773 100644 --- a/src/handle_request.js +++ b/src/handle_request.js @@ -76,15 +76,19 @@ function handleRequest(mockAdapter, resolve, reject, config) { } } else { // handler not found - utils.settle( - resolve, - reject, - { - status: 404, - config: config - }, - mockAdapter.delayResponse - ); + if (mockAdapter.passThroughByDefault) { + mockAdapter.originalAdapter(config).then(resolve, reject); + } else { + utils.settle( + resolve, + reject, + { + status: 404, + config: config + }, + mockAdapter.delayResponse + ); + } } } diff --git a/src/index.js b/src/index.js index 5c91363..9c76c07 100644 --- a/src/index.js +++ b/src/index.js @@ -49,6 +49,7 @@ function MockAdapter(axiosInstance, options) { this.axiosInstance = axiosInstance; this.originalAdapter = axiosInstance.defaults.adapter; this.delayResponse = options && options.delayResponse > 0 ? options.delayResponse : null; + this.passThroughByDefault = !!(options && options.passThroughByDefault); axiosInstance.defaults.adapter = this.adapter.call(this); } } diff --git a/test/pass_through_by_default.spec.js b/test/pass_through_by_default.spec.js new file mode 100644 index 0000000..85b71a9 --- /dev/null +++ b/test/pass_through_by_default.spec.js @@ -0,0 +1,161 @@ +var axios = require('axios'); +var expect = require('chai').expect; +var createServer = require('http').createServer; + +var MockAdapter = require('../src'); + +describe('passThroughByDefault option tests (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 + resp.end(req.url, 'utf8'); + } + }) + .listen(0, '127.0.0.1', function() { + serverUrl = 'http://127.0.0.1:' + httpServer.address().port; + resolve(); + }) + .on('error', reject); + }); + }); + + after(function() { + httpServer.close(); + }); + + beforeEach(function() { + instance = axios.create({ baseURL: serverUrl }); + mock = new MockAdapter(instance, { passThroughByDefault: true }); + }); + + it('works correctly if set no handlers', function() { + var randomPath = 'xyz' + Math.round(10000 * Math.random()); + + return Promise.all([ + instance.get('/' + randomPath).then(function(response) { + expect(response.status).to.equal(200); + expect(response.data).to.equal('/' + randomPath); + }) + ]); + }); + + it('allows selective mocking', function() { + mock.onGet('/foo').reply(200, 'bar'); + mock.onGet('/error').reply(200, 'success'); + mock.onGet('/bar').passThrough(); + + var randomPath = 'xyz' + Math.round(10000 * Math.random()); + + return Promise.all([ + instance.get('/foo').then(function(response) { + expect(response.status).to.equal(200); + expect(response.data).to.equal('bar'); + }), + instance.get('/error').then(function(response) { + expect(response.status).to.equal(200); + expect(response.data).to.equal('success'); + }), + instance.get('/bar').then(function(response) { + expect(response.status).to.equal(200); + expect(response.data).to.equal('/bar'); + }), + instance.get('/' + randomPath).then(function(response) { + expect(response.status).to.equal(200); + expect(response.data).to.equal('/' + randomPath); + }) + ]); + }); + + it('handles errors correctly', function() { + return instance + .get('/error') + .then(function() { + // The server should've returned an error + expect(false).to.be.true; + }) + .catch(function(error) { + expect(error).to.have.nested.property('response.status', 500); + }); + }); + + it('setting passThrough handler don\'t break anything', function() { + mock + .onGet('/foo') + .reply(200, 'bar') + .onAny() + .passThrough(); + + var randomPath = 'xyz' + Math.round(10000 * Math.random()); + + return Promise.all([ + instance.get('/foo').then(function(response) { + expect(response.status).to.equal(200); + expect(response.data).to.equal('bar'); + }), + instance.get('/' + randomPath).then(function(response) { + expect(response.status).to.equal(200); + expect(response.data).to.equal('/' + randomPath); + }), + instance.post('/post').then(function(response) { + expect(response.status).to.equal(200); + expect(response.data).to.equal('/post'); + }) + ]); + }); + + it('handles baseURL correctly', function() { + instance = axios.create({ + baseURL: '/test', + proxy: { + host: '127.0.0.1', + port: httpServer.address().port + } + }); + mock = new MockAdapter(instance, { passThroughByDefault: true }); + + return instance.get('/foo').then(function(response) { + expect(response.status).to.equal(200); + expect(response.data).to.equal('http://null/test/foo'); + }); + }); + + it('handles request transformations properly', function() { + return instance + .get('/foo', { + data: 'foo', + transformRequest: [ + function(data) { + return data + 'foo'; + } + ] + }) + .then(function(response) { + expect(response.config.data).to.equal('foofoo'); + }); + }); + + it('handles response transformations properly', function() { + return instance + .get('/foo', { + transformResponse: [ + function(data) { + return data + 'foo'; + } + ] + }) + .then(function(response) { + expect(response.data).to.equal('/foofoo'); + }); + }); +}); diff --git a/types/index.d.ts b/types/index.d.ts index c070869..3b598b5 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -22,6 +22,7 @@ interface RequestHandler { interface MockAdapterOptions { delayResponse?: number; + passThroughByDefault?: boolean; } interface RequestDataMatcher { diff --git a/types/test.ts b/types/test.ts index 60998ef..bd348d9 100644 --- a/types/test.ts +++ b/types/test.ts @@ -10,7 +10,8 @@ namespace AllowsConstructing { namespace AllowsConstructingWithOptions { new MockAdapter(instance, { - delayResponse: 2000 + delayResponse: 2000, + passThroughByDefault: true }); }