I am new to javascript testing. I am using jasmine and need to test if correct arguments have been passed to a method.
This is my method:
function myView(){
if($('.view').is('.list')){
myWindow('list');
}else{
myWindow('random');
}
$('.view').toggleClass('my-list');
}
function myWindow(list) {
var url = /test.json;
$.post(url, {"list": list});
}
Here are my tests:
describe('#myView', function() {
beforeEach(function() {
fixture.load('myview.html');
});
it('sets window to list', function(){
expect(window.myWindow).toHaveBeenCalledWith('list');
});
});
I get the following error.
Error: Expected a spy, but got Function.
If i add this line before the expect(which seems wrong because I am specifying the correct param which should be identified by test)
spyOn(window, myWindow('list'));
I get the following error:
undefined() method does not exist
Can someone show my a good way to write the above tests?
spyOn
's second parameter is the name of the property you need to spy on. When you call spyOn(window, myWindow('list'));
, your second parameter is the return value of myWindow('list')
which is undefined
=> throws error: undefined() method does not exist
In your code, simply doing this should work:
describe('#myView', function() {
beforeEach(function() {
fixture.load('myview.html');
});
it('sets window to list', function(){
spyOn(window, "myWindow");//spy the function
myView();//call your method that in turn should call your spy
expect(window.myWindow).toHaveBeenCalledWith('list');//verify
});
});
In software unit testing, there are concepts called stub and mock objects. These are dependencies of the method under test. spyOn
is to create your fake objects to test your methods.
You're accessing the global window
object directly, that's really a problem in unit testing. Although Javascript is a dynamically typed language, we're still able to mock your window
object (this is not possible with some statically-typed languages like c#). But to create a good unit-testable code, I recommend you should redesign your code to inject it from outside.
function myView(awindow){ //any dependency should be injected, this is an example to inject it via parameter
if($('.view').is('.list')){
awindow.myWindow('list');
}else{
awindow.myWindow('random');
}
$('.view').toggleClass('my-list');
}
Try this:
describe('#myView', function() {
beforeEach(function() {
fixture.load('myview.html');
});
it('sets window to list', function(){
var spy = {myWindow:function(list){}};
spyOn(spy, "myWindow"); //create a spy
myView(spy); //call your method that in turn should call your spy
expect(spy.myWindow).toHaveBeenCalledWith('list'); //verify
});
});
One more thing, jQuery code like this is not quite a good candidate for unit testing as it involves DOM manipulation in your code. If you have time, you should take a look at angularjs framework that separates your View (DOM) from your model (logic), uses dependency injection to make your code testable.