Created
June 20, 2019 18:18
-
-
Save philippefutureboy/40559cc632613f6c5f12de48b6551662 to your computer and use it in GitHub Desktop.
MockAxios with call operator support
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const defaultResponse = { data: {} }; | |
class ExtensibleFunction extends Function { | |
constructor(f) { | |
return Object.setPrototypeOf(f, new.target.prototype); | |
} | |
} | |
export class MockAxios extends ExtensibleFunction { | |
static instances = new WeakMap(); | |
static defaultInstance; | |
static resetAll(clear = true) { | |
if (clear) { | |
// Getting the defaultInstance to be able to set it in the new WeakMap | |
const defaultInstancePrivateMembers = MockAxios.instances.get( | |
MockAxios.defaultInstance | |
); | |
MockAxios.instances = new WeakMap(); | |
MockAxios.instances.set( | |
MockAxios.defaultInstance, | |
defaultInstancePrivateMembers | |
); | |
MockAxios.reset(MockAxios.defaultInstance); | |
} else { | |
MockAxios.instances.entries().forEach((instance) => { | |
MockAxios.reset(instance); | |
}); | |
} | |
} | |
static reset(instance) { | |
instance.get = jest.fn(() => Promise.resolve(defaultResponse)); | |
instance.put = jest.fn(() => Promise.resolve(defaultResponse)); | |
instance.post = jest.fn(() => Promise.resolve(defaultResponse)); | |
instance.delete = jest.fn(() => Promise.resolve(defaultResponse)); | |
const privateMembers = MockAxios.instances.get(instance); | |
privateMembers.__callee = jest.fn(() => Promise.resolve(defaultResponse)); | |
MockAxios.addMockingFeatures(privateMembers.__callee, instance); | |
} | |
static addMockingFeatures(source, target) { | |
// Adding mocking properties to the axios function | |
Object.entries(source).forEach(([k, v]) => { | |
if (typeof v === 'function') { | |
target[k] = v.bind(source); | |
} else { | |
target[k] = v; | |
} | |
}); | |
} | |
constructor(defaults = { headers: { common: {} } }) { | |
// privateMembers: All the stuff that has to be hidden because it is not normally on axios. | |
// __callee: the mock function that will be called when one does `axios(...args)` | |
const privateMembers = { | |
__callee: null, | |
}; | |
// This closure allows the __callee member of privateMembers to be | |
// modified dynamically, thus ensuring the ability to reset the instance | |
super(function(...args) { | |
return privateMembers.__callee(...args); | |
}); | |
// We set it in a WeakMap to be able to set/reset __callee later on | |
// By not setting __callee to a function, we avoid having the 'this' current object from being | |
// set in the scope of the function, which would prevent the WeakMap from releasing it | |
MockAxios.instances.set(this, privateMembers); | |
const self = this; | |
this.defaults = defaults; | |
MockAxios.reset(self); | |
} | |
create(options) { | |
return new MockAxios(options); | |
} | |
} | |
// //////////////////////////////////////////////// | |
const defaultInstance = new MockAxios(); | |
MockAxios.defaultInstance = defaultInstance; | |
export default defaultInstance; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment