diff --git a/README.md b/README.md index fe83cdce..d4081e94 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,9 @@ Returns the options for the last matched call to fetch Set some global config options, which include * `sendAsJson` [default `true`] - by default fetchMock will convert objects to JSON before sending. This is overrideable fro each call but for some scenarios e.g. when dealing with a lot of array buffers, it can be useful to default to `false` +##### `setImplementations(opts)` +When using non global fetch (e.g. a ponyfill) or an alternative Promise implementation, this will configure fetch-mock to use your chosen implementations. `opts` is an object with one or more of the following properties: `Headers`,`Request`,`Response`,`Promise`. Note that `setImplementations(require('fetch-ponyfill'))` will configure fetch-mock to use all of fetch-ponyfill's classes. + ## Troubleshooting and alternative installation ### `fetch` is assigned to a local variable, not a global diff --git a/src/client.js b/src/client.js index fc495b4a..0a7a8f02 100644 --- a/src/client.js +++ b/src/client.js @@ -4,12 +4,14 @@ const FetchMock = require('./fetch-mock'); const statusTextMap = require('./status-text'); const theGlobal = typeof window !== 'undefined' ? window : self; -FetchMock.setGlobals({ - global: theGlobal, +FetchMock.global = theGlobal; +FetchMock.statusTextMap = statusTextMap; + +FetchMock.setImplementations({ + Promise: Promise, Request: theGlobal.Request, Response: theGlobal.Response, - Headers: theGlobal.Headers, - statusTextMap: statusTextMap + Headers: theGlobal.Headers }); module.exports = new FetchMock() \ No newline at end of file diff --git a/src/fetch-mock.js b/src/fetch-mock.js index b2ced28f..4bc6468a 100644 --- a/src/fetch-mock.js +++ b/src/fetch-mock.js @@ -80,7 +80,7 @@ FetchMock.prototype.spy = function () { } FetchMock.prototype.fetchMock = function (url, opts) { - const Promise = this.Promise || FetchMock.global.Promise; + const Promise = this.Promise || FetchMock.Promise; let response = this.router(url, opts); if (!response) { @@ -130,7 +130,7 @@ FetchMock.prototype.addRoute = function (route) { FetchMock.prototype.mockResponse = function (url, responseConfig, fetchOpts) { - const Promise = this.Promise || FetchMock.global.Promise; + const Promise = this.Promise || FetchMock.Promise; // It seems odd to call this in here even though it's already called within fetchMock // It's to handle the fact that because we want to support making it very easy to add a @@ -269,8 +269,11 @@ FetchMock.prototype.configure = function (opts) { Object.assign(FetchMock.config, opts); } -FetchMock.setGlobals = function (globals) { - Object.assign(FetchMock, globals) +FetchMock.setImplementations = FetchMock.prototype.setImplementations = function (implementations) { + FetchMock.Headers = implementations.Headers || FetchMock.Headers; + FetchMock.Request = implementations.Request || FetchMock.Request; + FetchMock.Response = implementations.Response || FetchMock.Response; + FetchMock.Promise = implementations.Promise || FetchMock.Promise; } FetchMock.prototype.sandbox = function (Promise) { @@ -295,7 +298,9 @@ FetchMock.prototype.sandbox = function (Promise) { functionInstance.bindMethods(); boundMock = functionInstance.fetchMock; functionInstance.isSandbox = true; - functionInstance.Promise = Promise; + if (Promise) { + functionInstance.Promise = Promise; + } return functionInstance; }; diff --git a/src/server.js b/src/server.js index 89c03eb8..0f79d479 100644 --- a/src/server.js +++ b/src/server.js @@ -7,13 +7,15 @@ const stream = require('stream'); const FetchMock = require('./fetch-mock'); const http = require('http'); -FetchMock.setGlobals({ - global: global, +FetchMock.global = global; +FetchMock.statusTextMap = http.STATUS_CODES; +FetchMock.stream = stream; + +FetchMock.setImplementations({ + Promise: Promise, Request: Request, Response: Response, - Headers: Headers, - stream: stream, - statusTextMap: http.STATUS_CODES + Headers: Headers }); module.exports = new FetchMock() \ No newline at end of file diff --git a/test/spec.js b/test/spec.js index 6ab8db94..d870ac87 100644 --- a/test/spec.js +++ b/test/spec.js @@ -1073,6 +1073,61 @@ module.exports = (fetchMock, theGlobal, Request, Response) => { } fetchMock.restore(); }); + + describe('fetch utility class implementations', () => { + const FetchMock = require('../src/fetch-mock'); + ['Headers', 'Request', 'Response'] + .forEach(className => { + it(`should use configured ${className}`, () => { + const original = FetchMock[className]; + sinon.spy(FetchMock, className); + const spy = FetchMock[className]; + let callCount = 0; + const custom = function () { + callCount++; + return spy.apply(this, arguments) + }; + custom.prototype = original.prototype; + const confObject = {}; + confObject[className] = custom + fetchMock.setImplementations(confObject); + expect(FetchMock[className]).to.equal(custom); + + fetchMock.mock('http://test.url.com/', { + status: 200, + headers: { + id: 1 + } + }); + return Promise.all([ + fetch('http://test.url.com/'), + fetch(new FetchMock.Request('http://test.url.com/')) + ]) + .then(() => { + expect(callCount).to.equal(spy.args.length); + confObject[className] = original; + fetchMock.restore(); + fetchMock.setImplementations(confObject); + }) + }) + + }) + }); + + it('can be configured to use alternate Promise implementations', () => { + fetchMock.setImplementations({ + Promise: BluebirdPromise + }); + fetchMock + .mock('http://example.com', 200) + const fetchCall = fetch('http://example.com'); + expect(fetchCall).to.be.instanceof(BluebirdPromise); + return fetchCall.then(() => { + fetchMock.restore(); + fetchMock.setImplementations({Promise}); + }) + + }); }) describe('sandbox', () => {