R

E

A

C

T

O

xamples 

epeat

ode

pproach

ptimize

est

Make a Spy

The Question

 Sample Output

 

(keep in mind that not all functions take two arguments!)

function adder(n1, n2) { return n1 + n2; }

var adderSpy = spyOn( adder );

adderSpy.getCallCount(); // 0

adderSpy(2, 4); // returns 6
adderSpy.getCallCount(); // 1

adderSpy(3, 5); // returns 8
adderSpy.getCallCount(); // 2
adderSpy.wasCalledWith(2); // true
adderSpy.wasCalledWith(0); // false
adderSpy.returned(6); // true
adderSpy.returned(9); // false

1. Create the SpyOn function 

var spyOn = function(func) {

    // keep track of function call count, start at 0
    var callCount = 0; 
    // array to store call results   
    var resVals = [];
    // array to store call call arguments
    var calVals = [];

    //function to be returned
    var spy = function () {

    /** code will go here **/

    };

    //create required methods on spy
    spy.getCallCount = function() {
        return callCount;
    };
    spy.wasCalledWith = function (val) { 
        // search through resVals array for val
    };
    spy.returned = function (val) { 
        // search through calVals array for val 
    };

    return spy;
}

2. Figure out how to access function arguments


// Remember that function arguments are an array-like objects? 
// How can we turn the function arguments object into an actual array? Array.prototype.object.slice.call(arguments)


//Now we can use the resulting array to call .apply() on our function

var spy = function() {
    var args = [].slice.call(arguments);
    var retVal = func.apply(func, args);

    /* More code will go here */

};

3. Save the returned and called values in the proper arrays and increment call count

var spyOn = function (func) {
  var callCount = 0,
      callVals  = [],
      retVals   = [];
  var spy = function () {
    var args = [].slice.call(arguments);
    var retVal = func.apply(func, args);

    //store result of applying function
    retVals.push(retVal);

    // add arguments array values to called values array
    callVals = callVals.concat(args);

    //increment function call count by 1
    callCount++;

    //return the result of the function call
    return retVal;

  };

  spy.getCallCount;
  spy.wasCalledWith;
  spy.returned;

  return spy;
};

4. Implement the  'wasCalledWith' and 'returned' methods

// the 'indexOf' method of an Array returns '-1' if a value is not found
// we can use this to return a boolean value for the two search methods

 spy.getCallCount = function () { 
    return callCount; 
 };

 spy.wasCalledWith = function (val) { 
    return (callVals.indexOf(val) > -1); 
 };

 spy.returned = function (val) { 
    return (retVals.indexOf(val) > -1); 
 };

 return spy;

Final Solution

var spyOn = function (func) {

  var callCount = 0,
      callVals  = [],
      retVals   = [];

  var spy = function () {
    var args = [].slice.call(arguments);
    var retVal = func.apply(func, args);
    retVals.push(retVal);
    callVals = callVals.concat(args);
    callCount++;
    return retVal;
  };

  spy.getCallCount = function () { 
    return callCount; 
  };

 spy.wasCalledWith = function (val) { 
    return (callVals.indexOf(val) > -1); 
 };

 spy.returned = function (val) { 
    return (retVals.indexOf(val) > -1); 
 };

  return spy;
};

Reacto: Spy

By kabibster

Reacto: Spy

  • 1,503