Can't get chai.spy.on to work - javascript

Please don't suggest to use Sinon. I want to get chai-spies specifically chai.spy.on working with your help. Basically, I have this spec. Inside my initialize method in PatientController, I call this.initializePatientEvents();
beforeEach(function() {
this.patientController = new PatientController({model: new Backbone.Model(PatientModel)});
});
it('executes this.initializePatientEvents', function () {
let spy = chai.spy.on(this.patientController, 'initializePatientEvents');
expect(spy).to.have.been.called();
});
However, the test is failing with this error
AssertionError: expected { Spy } to have been called
at Context.<anonymous>
I spent almost 3 hours now with no luck! :(

Moving my comment above to a response here:
Looking at your code, I'm just not sure what the this reference refers to. And based on your error message, it seems like its related to something about the context. Therefore, I'd try something like this:
var patientController;
beforeEach(function() {
patientController = new PatientController({model: new Backbone.Model(PatientModel)});
});
it('executes this.initializePatientEvents', function () {
let spy = chai.spy.on(patientController, 'initializePatientEvents');
expect(spy).to.have.been.called();
});
If this doesn't work, then its more specific to your implementation of patientController and the initializePatientEvents method, and not something related to chai.spy.
EDIT:
Here's something I set up locally and I was able to get a passing test. The main difference is that instead of using Backbone, I just created my own constructor function.
"use strict";
var chai = require("chai");
var sinon = require("sinon");
var sinonChai = require("sinon-chai");
chai.use(sinonChai);
var expect = chai.expect;
var should = chai.should();
describe("PatientController Test", function() {
var PatientController;
var initializePatientEventsSpy;
var patient;
beforeEach(function() {
PatientController = function(name, age) {
this.name = name;
this.age = age;
this.initializePatientEvents();
};
PatientController.prototype.initializePatientEvents = function() {
console.log("Do some initialization stuff here");
};
initializePatientEventsSpy = sinon.spy(PatientController.prototype, "initializePatientEvents");
});
it("should test initializePatientEvents was called", function() {
patient = new PatientController("Willson", 30);
initializePatientEventsSpy.should.have.been.called;
});
});

If the PatientController constructor is what calls initializePatientEvents, then the timing of your spy creation is a bit off. Currently, the order of your spy-function relationship is:
Call function
Spy on function
Expect spied on function to have ben called
Because the function is not being spied on when it is called, the spy misses the call entirely. What the order should be is:
Spy on function
Call function
Expect spied on function to have ben called
However, you are in the sticky situation where the object you are spying on doesn't exist until after the constructor is called. One workaround would be to assert that the effects of the initializePatientEvents have taken place instead of asserting that the function was called.

Related

Jasmine - how to spyOn instance methods

I have a function
var data = {};
var myFunc = function() {
data.stuff = new ClassName().doA().doB().doC();
};
I'd like to test that doA, doB, and doC were all called.
I tried spying on the instance methods like this
beforeEach(function() {
spyOn(ClassName, 'doA');
};
it('should call doA', function() {
myFunc();
expect(ClassName.doA).toHaveBeenCalled();
});
but that just gives me a "doA() method does not exist" error.
Any ideas?
Where you went wrong was your understanding of how to refer to methods in JavaScript in a static context. What your code is actually doing is spying on ClassName.doA (that is, the function attached to the ClassName constructor as the property doA, which is not what you want).
If you want to detect when that method gets called on any instance of ClassName anywhere, you need to spy on the prototype.
beforeEach(function() {
spyOn(ClassName.prototype, 'doA');
});
it('should call doA', function() {
myFunc();
expect(ClassName.prototype.doA).toHaveBeenCalled();
});
Of course, this is assuming that doA lives in the prototype chain. If it's an own-property, then there is no technique that you can use without being able to refer to the anonymous object in myFunc. If you had access to the ClassName instance inside myFunc, that would be ideal, since you could just spyOn that object directly.
P.S. You should really put "Jasmine" in the title.
Let’s do some code refactoring as we want implement constructor injection pattern as James Shore mentions that:
Dependency injection means giving an object its own instance variables. Really. That’s it.
var data = {};
var stuff = new ClassName()
var myFunc = function(stuff) { // move step of creation new object outside
data.stuff = stuff.doA().doB().doC();
};
And time for some tests
function ClassName() {
}
var data = {};
var stuff = new ClassName()
var myFunc = function(stuff) {
data.stuff = stuff.doA().doB().doC();
};
describe('stub for ClassName implementation', function() {
var stubStuff = {
doA: function() {
return stubStuff
},
doB: function() {
return stubStuff
},
doC: function() {
return stubStuff
}
}
beforeEach(function() {
spyOn(stubStuff, 'doA').and.callThrough();
});
it('calls "doA" on "myFunc" exection', function() {
myFunc(stubStuff);
expect(stubStuff.doA).toHaveBeenCalled();
});
});
<link href="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine.css" rel="stylesheet" />
<script src="//safjanowski.github.io/jasmine-jsfiddle-pack/pack/jasmine-2.0.3-concated.js"></script>

Using JavaScript and sinon How do you spy on methods called in the constructor?

I really need help with the following code - This is not pasted from my program its off the top of my head but I think it clearly demonstrates the problem (and I believe it to be fully accurate). When I request the value of "spy.called" it ignores the call made in the constructor function. How do I code this so that the call inside the constructor is registered by the spy?
OR if not possible what approach should I take? Example code greatly appreciated - Many thanks - Been banging my head all day with this!
function MyClass() {
var self = this;
this.myFunc = function() {
console.log("hi");
}
function init() {
self.myFunc();
}
init();
}
var spy = sinon.spy(new MyClass(), "myFunc");
console.log(spy.called); // true if the spy was called at least once
// ABOVE OUTPUTS FALSE - IT FAILS TO REGISTER THE CALL IN THE CONSTRUCTOR!
spy.myFunc();
console.log(spy.called);
// ABOVE OUTPUTS TRUE AS EXPECTED
The problem here is that when the method myFunc is called the spy doesn't exist yet. Your code is equivalent to :
var c = new MyClass()
var spy = sinon.spy(c, "myFunc");
Clearly the spy is not in place when the constructor is called.
To solve this problem you can move the method myFunc in the prototype of the MyClass object and then spy the methods in the prototype.
For example:
function MyClass() {
this.init();
}
MyClass.prototype.myFunc = function() {
console.log("hi");
}
MyClass.prototype.init = function() {
this.myFunc();
}
var myFuncSpy = sinon.spy(MyClass.prototype, "myFunc");
var initSpy = sinon.spy(MyClass.prototype, "init");
var c = new MyClass();
console.log(myFuncSpy.called); // TRUE
console.log(initSpy.called); // TRUE
JSFIDDLE: http://jsfiddle.net/och191so/1/
Open the console to see the result.
I think you should redesign your class a bit. You can either accept myFunc in constructor argument (only if it makes sense from point of usage) or you can set it on MyClass' prototype:
function MyClass() {
function init() {
this.myFunc();
}
init();
}
MyClass.prototype.myFunc = function() {
console.log("hi");
}
var spy = sinon.spy(MyClass.prototype, "myFunc");
new MyClass();
console.log(spy.called);

Creating test objects in Sinon.js

I'm trying to test code using Sinon.js, but I'm unfamiliar with out it's supposed to behave.
I expect that I can create a 'fake' object, wrap it with sinon and pass it to whatever I'm testing, and have it do its thing. However, it seems like every time I try to wrap a sinon object, the function is not there:
var event_api = {
startTime: function() {
return '123';
}
}
var stub = sinon.stub(event_api);
console.log(stub.startTime()) // returns undefined
var mock = sinon.mock(event_api);
console.log(mock.startTime()) // returns undefined
What am I missing?
It depends on what are you trying to do:
If you don't have any expectations on the call then you should use a stub, for example startTime() only has to return a value.
var event_api = {
startTime: sinon.stub().returns('123')
}
console.log(event_api.startTime());
But if what you want is to set some assertions for the call, then you should use a mock.
var event_api = {
startTime: function() {
return '123';
}
}
//code to test
function getStartTime(e) {
return e.startTime();
}
var mock = sinon.mock(event_api);
mock.expects("startTime").once();
getStartTime(event_api);
mock.verify();
Hope this helps.
The function is indeed there, but it's void of any functionality, since it has been stubbed.
If you want to log the function itself in the console, you have to execute:
console.log(stub.startTime) //logs the function itself
instead of:
console.log(stub.startTime()) //logs the result of the function, which is undefined
However, as said, all the methods of a stub object have been "emptied" of their functionality. If you want to make a method of a stubbed object return a value, you can do the following:
var stub = sinon.stub(event_api);
stub.startTime.returns(123);
console.log(stub.startTime) //log the function
console.log(stub.startTime()) //log the result of function, that is now 123

Jasmine - Spying on a method call within a constructor

I want to test whether the following method is called with in my Javascript object constructor. From what I have seen in the Jasmine documentation, I can spy on a constructor method and I can spy on methods after an object has been instantiated, but I can't seem to be able to spy on a method before the object is constructed.
The object:
Klass = function() {
this.called_method();
};
Klass.prototype.called_method = function() {
//method to be called in the constructor.
}
I want to do something like this in the spec:
it('should spy on a method call within the constructor', function() {
spyOn(window, 'Klass');
var obj = new Klass();
expect(window.Klass.called_method).toHaveBeenCalled();
});
Spy directly on the prototype method:
describe("The Klass constructor", function() {
it("should call its prototype's called_method", function() {
spyOn(Klass.prototype, 'called_method'); //.andCallThrough();
var k = new Klass();
expect(Klass.prototype.called_method).toHaveBeenCalled();
});
});
Broadly, I agree with Dave Newton's answer above. However, there are some edge-cases to this approach that you should consider.
Take a variation to Dave's solution, with another test-case:
// production code
var Klass = function() {
this.call_count = 0;
this.called_method();
};
Klass.prototype.called_method = function() {
++this.call_count;
};
// test code
describe("The Klass constructor", function() {
it("should call its prototype's called_method", function() {
spyOn(Klass.prototype, 'called_method');
var k = new Klass();
expect(k.called_method).toHaveBeenCalled();
});
it('some other test', function() {
var k = new Klass();
expect(k.call_count).toEqual(1);
});
});
The second test will fail because the spy setup in the first test persists across the test boundaries into the second method; called_method doesn't increment call_count, so this.call_count does not equal 1. It's also possible to come up with scenarios with false positives - tests that pass, that shouldn't.
On top of this, because the spy remains, the more Klass instances that are created, the bigger the memory heap the spy will consume, because the spy will record each call to called_method. This probably isn't a problem in most circumstances, but you should be aware of it, just in case.
A simple solution to this problem would be to make sure that the spy is removed after it has been used. It can look a bit ugly, but something like this works:
// test code
describe("The Klass constructor", function() {
it("should call its prototype's called_method", function() {
var spy = jasmine.createSpy('called_method');
var method = Klass.prototype.called_method;
Klass.prototype.called_method = spy;
var k = new Klass();
expect(spy).toHaveBeenCalled();
Klass.prototype.called_method = method;
});
[NOTE - a little opinion to finish] A better solution would be to change the way you write production code to make the code easier to test. As a rule, spying on prototypes is probably a code-smell to be avoided. Instead of instantiating dependencies in the constructor, inject them. Instead of doing initialization in the constructor, defer to an appropriate init method.

Am I using Javascript call-backs appropriately (object-oriented style)?

I have the following code example to use an object that receives the action from the callback. Doesn't seem like this is a good design pattern. Or is it?
When setTimeOut() fires on the function after 1 second, it uses the objInstance global variable (DOM scope) to access the ClassExample object instance. Can someone recommend a better way to utilize callbacks within an object oriented design?
The whole idea is so I can use the callback to update data within my object instance (increment a variable for example).
function ClassExample{
this.initiate = function() {
setTimeOut(objInstance.afterTimeOut,1000); //using the objects global handle
}
this.afterTimeOut = function() {
alert("Received!");
}
}
var objInstance = new ClassExample(); //instance
objInstance.initiate();
No, you're not. You'll want to do this:
this.initiate = function() {
setTimeOut(objInstance.afterTimeOut,1000); //using the objects global handle
}
Now, if "afterTimeout" needs the proper object context, you could do this:
this.initiate = function() {
var instance = this;
setTimeout(function() { instance.afterTimeOut(); }, 1000);
}
OK well you changed the question considerably with that little edit :-) If I were you, I'd just do this (like my original second example):
this.initiate = function() {
var instance = this;
setTimeout(function() { instance.afterTimeOut(); }, 1000);
}
Then you don't need any ugly global variables around at all.
edit — Stackoverflow user #Christoph comments that this isn't particularly pretty. One thing that might help would be to use a "bind" facility, as provided by newer browsers natively (as a method on the Function prototype) or by some libraries (Prototype or Functional for example). What "bind" lets you do is create a little wrapper function like I've got above:
this.initiate = function() {
setTimeout(this.afterTimeOut.bind(this), 1000);
}
That call to "bind" returns a function that is effectively the same sort of thing as the little wrapper I coded explicitly in the example.
function ClassExample{
this.afterTimeOut = function() {
alert("Received!");
}; // Don't forget these
setTimeOut(afterTimeOut, 1000); // Don't use () if you're passing the function as an argument
}
var objInstance = new ClassExample(); //instance
That way you don't need the initiate() method.
If you really want the initiate() method, I'd do it like this:
function ClassExample{
var self = this;
self.afterTimeOut = function() {
alert("Received!");
};
self.initiate = function() {
setTimeOut(self.afterTimeOut, 1000);
};
}
var objInstance = new ClassExample(); //instance
objInstance.initiate();
This is how I'd do it to allow timer reuse and minimize the number of closures:
function Timer(timeout, callback) {
this.timeout = timeout;
this.callback = callback;
}
Timer.prototype.run = function(thisArg /*, args... */) {
var argArray = Array.prototype.slice.call(arguments, 1);
var timer = this;
setTimeout(function() {
timer.callback.apply(thisArg, argArray);
}, timer.timeout);
};
var timer = new Timer(1000, alert);
timer.run(null, 'timer fired!');
And just for fun, a golfed version which is functionally equivalent, but replaces the object with a closure:
function delay(func, timeout) {
return function() {
var self = this, args = arguments;
setTimeout(function() { func.apply(self, args); }, timeout);
};
}
delay(alert, 1000).call(null, 'timer fired!');
You are right it is not the optimal way of doing what you are aiming for. however i have to wonder why you need to break the callstack as part of the initiation, it seems very academic.
apart from that if i had to do that, i'd probably use a closure like so:
function ClassExample{
this.initiate = function() {
setTimeOut((function(self) { return function() { self.afterTimeout();}})(this),1000); //using the objects global handle
}
this.afterTimeOut = function() {
alert("Received!");
}
}
var objInstance = new ClassExample(); //instance
objInstance.initiate()
this.initiate = function() {
var instance = this;
setTimeOut(function() {
instance.afterTimeOut();
}, 1000);
};
By saving this to a local variable, you can avoid using the global handle at all. Also this prevent the afterTimeout() from losing it's this.
Building on Znarkus answer...
I really don't know in which environment his code is running but for me the first approach just do not works. I got: 'ReferenceError: afterTimeOut is not defined'...
The second one, nevertheless, is really cool... I just changed setTimeOut for setTimeout (using lowercase 'o') and included parenthesis after the class name definition turning the first line of code into 'function ClassExample(){'; solved my problem.
My snippet of example code:
Oop with private behaviour, intern callback calling and etc.
function MyTry (name){
// keep this object pointer... that's the trick!
var self = this;
// create private variable
var d = new Date()toJSON().slice(0, 10);
// create a private function
function getName(){return name}
// create public access method
self.hello = function(){alert('Hello '+getName()+'!\nToday is: '+d)}
// note instance method hello passed as a callback function!
self.initiate = function(){setTimeout(self.hello, 3000)}
}

Categories