Created
May 27, 2016 11:08
-
-
Save Maximilianos/e836ee599e539015c4f2a8a0ea0cdcec to your computer and use it in GitHub Desktop.
Basic Spying and Stubbing for functions in JavaScript
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
import deepEqual from 'deep-equal'; | |
/** | |
* A basic Map implementation whose keys hold a deep equality | |
* relationship but not a referential equality relationship | |
* | |
*/ | |
export default class LooseMap { | |
constructor() { | |
this.__entries__ = []; | |
} | |
set(key, value) { | |
this.__entries__.unshift([key, value]); | |
} | |
get(key) { | |
const entry = this.__entries__.find( | |
entry => deepEqual(entry[0], key) | |
); | |
return entry && entry[1]; | |
} | |
has(key) { | |
return !!~this.__entries__.findIndex( | |
entry => deepEqual(entry[0], key) | |
); | |
} | |
} |
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
/** | |
* Exposes the number of times the | |
* `call` method is called | |
* | |
*/ | |
export class Spy { | |
constructor() { | |
this.call = this.call.bind(this); | |
this.call.called = 0; | |
} | |
call() { | |
this.call.called += 1; | |
} | |
} | |
/** | |
* Replace a function with the `call` method | |
* of an initiallized Spy instance | |
* | |
*/ | |
export default function spy() { | |
return (new Spy()).call; | |
} |
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
import LooseMap from './LooseMap'; | |
import { Spy } from './spy'; | |
/** | |
* Exposes the number of times the `call` method is | |
* called and allows you to specify what the `call` | |
* method returns for a given input | |
* | |
*/ | |
export class Stub extends Spy { | |
constructor() { | |
super(); | |
this.returnValues = new LooseMap(); | |
// set up the default return | |
this.defaultReturn = Symbol('default stub return key'); | |
this.returnValues.set(this.defaultReturn, undefined); | |
// stub.returns(...) should override the default return | |
this.call.returns = this.returns.bind(this, this.defaultReturn); | |
this.call.withArgs = this.withArgs.bind(this); | |
} | |
call(...args) { | |
super.call(); | |
// check if return value is defined for given | |
// args else return the default return | |
const key = this.returnValues.has(args) | |
? args : this.defaultReturn; | |
return this.returnValues.get(key); | |
} | |
returns(inputs, output) { | |
this.returnValues.set(inputs, output); | |
} | |
withArgs(...args) { | |
return { returns: this.returns.bind(this, args) }; | |
} | |
} | |
/** | |
* Replace a function with the `call` method | |
* of an initiallized Stub instance | |
* | |
*/ | |
export default function stub() { | |
return (new Stub()).call; | |
} |
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
import stub from './stub'; | |
// the function we are going to use for our example | |
let foo = () => 'Oh Yeah!!!!'; | |
// Before stubbing the function | |
bin.log(foo()); | |
// We stub the function! | |
foo = stub(); | |
// check that function calls are being recorded | |
bin.log(foo.called); // should be 0 because function hasn't been | |
// called since being made a stub | |
bin.log(foo()); // should return undefined because a stub by itself | |
// does not do anything | |
bin.log(foo.called); // should be 1 because function has been | |
// called once | |
// check that we can set what the stub returns | |
foo.returns('I am a stub'); | |
bin.log(foo()); // should be "I am a stub" | |
bin.log(foo('foo', 'bar')); // should be "I am a stub" | |
// check that we can set what the stub returns | |
// for a given set of inputs | |
foo.withArgs('foo', 'bar').returns('So original'); | |
bin.log(foo('foo', 'bar')); // should be "So original" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This code is available as a bin on webpackbin: http://www.webpackbin.com/E1PxnZWX-