Skip to content

Instantly share code, notes, and snippets.

@philippefutureboy
Created June 20, 2019 18:18
Show Gist options
  • Save philippefutureboy/40559cc632613f6c5f12de48b6551662 to your computer and use it in GitHub Desktop.
Save philippefutureboy/40559cc632613f6c5f12de48b6551662 to your computer and use it in GitHub Desktop.
MockAxios with call operator support
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