I am trying to test a very simple jQuery plugin which simply calls $.ajax method and put its content into a element. For testing I am using JsTestDriver and Sinon for mocking.
Plugin file looks:
(function($) {
$.fn.transfer = function() {
$.ajax({
url : 'friends',
type : 'GET',
contentType : 'application/json',
dataType : 'json',
success : function(html) {
console.log("-"+html+"-");
console.log($(this));
$(this).html(html);
console.log("+"+$(this).html()+"+")
}
});
};
})(jQuery);
In theory very simple plugin.
And then I have written a unit test mocking success function:
TestCase("Ajax ", {
'test response' : function () {
/*:DOC divElement = <div id="container" style="height: 100px;"></div>*/
sinon.stub(jQuery, "ajax").yieldsTo(
"success", 'alex');
$(this.divElement).transfer();
console.log("*"+$(this.divElement).text()+"*");
}
});
it seems correct too. Then if you execute this test, next lines are printed through console:
[LOG] -alex-
[LOG] [object Object]
[LOG] +null+
[LOG] **
So success function receives correctly "alex" string. Then $(this) reference is printed, message is set with html() function and when I log previous set value, a null is returned. And last log message is in test file, where as you can see ajax text is not set.
Does anybody know what I am doing wrong? Because I am sure I am missing something that now I cannot see.
Use Synchronous AJAX
JS Test driver and most testing frameworks I know of have a bit of a problem handling asynchronous javascript, basically the disjointed nature of asynchronous calls screws up the order of test execution (think: test 2 starts executing before test 1 is finished). For this reason try using synchornous ajax calls for the duration of your tests by setting the global async property with jQuery.ajaxSetup().
// Use synchronous AJAX
jQuery.ajaxSetup({async: false});
TestCase("Ajax ", {
'test1' : function () {
// etc...
}
});
// Revert to default
jQuery.ajaxSetup({async: true});
I recommend you use the AsyncTestCase that is provided by js-test-driver. It handles asynchronous processes well.
Add your mocked server method to the callbacks in the queue so the test waits until the "server" has been called. Something like this:
var AjaxTest = AsyncTestCase('AjaxTest');
AjaxTest.prototype.testResponse = function(queue) {
/*:DOC divElement = <div id="container" style="height: 100px;"></div>*/
queue.call('Set up mocked server', function(callbacks) {
var serverStub = sinon.stub(jQuery, "ajax").yieldsTo("success", 'alex');
callbacks.add(serverStub);
$(this.divElement).transfer();
});
queue.call('Make assertions here', function() {
console.log("*"+$(this.divElement).text()+"*");
});
};
Note: I haven't tried the code. Hope there are no typos. ;)