UNPKG

hanbi

Version:

A small javascript library for stubbing and spying on methods/functions.

177 lines (176 loc) 4.45 kB
/** * Represents a single stubbed function */ export class Stub { /** * Whether or not this stub has been called */ get called() { return this._calls.size > 0; } /** * List of all calls this stub has received */ get calls() { return this._calls; } /** * Retrieves an individual call * @param index Index of the call to retrieve * @return Call at the specified index */ getCall(index) { return [...this._calls][index]; } /** * Retrieves the first call * @return Call object */ get firstCall() { return this.getCall(0); } /** * Retrieves the last call * @return Call object */ get lastCall() { return this.getCall(this.callCount - 1); } /** * Number of times this stub has been called */ get callCount() { return this._calls.size; } /** * Constructor * @param fn Function being stubbed */ constructor(fn) { this._calls = new Set(); this.original = fn; // eslint-disable-next-line @typescript-eslint/no-this-alias const self = this; this.handler = function handler(...args) { // eslint-disable-next-line no-invalid-this return self._handleCall.call(self, this, args); }; } /** * Processes an individual call to this stub * @param thisValue Context of the call (`this`) * @param args Arguments passed when being called * @return Return value of this call */ _handleCall(thisValue, args) { const returnValue = this._returnFunction ? this._returnFunction.apply(thisValue, args) : this._returnValue; this._calls.add({ args: args, thisValue, returnValue }); return returnValue; } /** * Specifies the value this stub should return * @param val Value to return */ returns(val) { this._returnFunction = undefined; this._returnValue = val; } /** * Specifies a function to call to retrieve the return value of this * stub * @param fn Function to call */ callsFake(fn) { this._returnValue = undefined; this._returnFunction = fn; } /** * Enables pass-through, in that the original function is called when * this stub is called. */ passThrough() { this.callsFake(this.original); } /** * Resets call state (e.g. call count, calls, etc.) */ reset() { this._calls.clear(); } /** * Restores this stub. * This behaviour differs depending on what created the stub. */ restore() { if (this.restoreCallback) { this.restoreCallback(); } } /** * Asserts that the stub was called with a set of arguments * @param args Arguments to assert for * @return Whether they were passed or not */ calledWith(...args) { return [...this.calls].some((call) => call.args.length === args.length && call.args.every((arg, idx) => args[idx] === arg)); } /** * Asserts that the stub returned a given value * @param val Value to check for * @return Whether the value was ever returned or not */ returned(val) { return [...this.calls].some((call) => call.returnValue === val); } } const stubbedMethods = new Set(); /** * Stubs a method of a given object. * @param obj Object the method belongs to * @param method Method name to stub * @return Stubbed method */ export function stubMethod(obj, method) { const instance = new Stub(obj[method]); obj[method] = instance.handler; instance.restoreCallback = () => { obj[method] = instance.original; stubbedMethods.delete(instance); }; stubbedMethods.add(instance); return instance; } /** * Stubs a given function. * @param fn Function to stub * @return Stubbed function */ export function stub(fn) { const result = new Stub(fn); return result; } /** * Creates an anonymous spy. * @return Anonymous stub */ export function spy() { return new Stub((() => { return; })); } /** * Restores all tracked stubs at once. */ export function restore() { for (const stub of stubbedMethods) { stub.restore(); } stubbedMethods.clear(); }