About
What is JQuery Spy?
Jquery spy is a plugin to extend jquery, qunit and sinon.js providing developers a concise, elegant way to write / describe tests for test driven development (tdd)
Why do we need JQuery Spy?
The most important reason is to be able to test ajax in a ledgible way.
Secondly, to encourage testing by making it easier for every tom dick and harry javascript developer.
As a Developer, I want to test
As a Developer, I want to test the following in an easy to remember syntax:
- Test the $.ajax method was called
- Test ajax request url
- Test ajax request type
- Test ajax request dataType
- Test ajax response success method was called within a certain time
- After ajax response, test an element exists
- After ajax response, test an element style
- After ajax response, test an element contents
Without JQuery Spy Example
test( "Test ajax and view", function () {
// Prepare spy tests....
var intMaxAjaxWait = 4,
intExpectCount = 8,
fnTestRequest = function(spyDetails){
ok($.ajax.calledOnce, 'ajax has been called ');
var ajaxParams = spyDetails.args[0];
// Run ajax request tests
equals( ajaxParams.url, "/actions/jsonpproxy/?url=/actions/json.js" , 'ajax url');
equals( ajaxParams.dataType, "jsonp", 'ajax jsonp' );
equals( ajaxParams.type, "GET", 'ajax type' );
},
fnTestResponse = function(spyDetails){
// Collect data from spy and run response tests
ok(spyDetails, 'ajax success method completed under ' + intMaxAjaxWait + ' seconds.');
ok( $('#someSelector').length, 'someSelector exists');
equals( $('#someSelector').html(), 'Some code here...' , 'someSelector html');
equals( $('#someSelector').css('visibility'), 'visible', 'someSelector visibility' );
};
// Use a timer so that we can test if the ajax response returned after a certain time period.
// The alternative, which is cleaner is using a $(body).ajaxOnComplete() but this will only be called if we actually change the Dom
// Using a timer allows flexibility in testing everything
var spyDetails = {returnValue:{status:null}},
intStartTime = new Date().getTime(),
fnTimer = function(){
setTimeout(function(){
var intEndTime = new Date().getTime(),
intDifference = ((intEndTime - intStartTime) / 1000),
isMaxTimeElapsed = intDifference > intMaxAjaxWait;
if(spyDetails.returnValue.status === 200){
fnTestResponse(spyDetails);
start();
}else if(isMaxTimeElapsed){
fnTestResponse(null);
start();
}else{
fnTimer();
}
},100); // Test every 10th of a second
}
expect(intExpectCount);
this.spy($, 'ajax');
stop();
fnTimer();
// Run original ajax method
$.ajax({
url:'/actions/jsonpproxy/?url=/actions/json.js',
dataType:'jsonp',
type:'GET',
cache:'false',
success:function(data){
$('#qunit-fixture').html('<div id="someSelector">Some code here...</div>');
$('#someSelector').css({'visibility':'visible'});
}
});
// Collect data from spy and run request tests
spyDetails = $.ajax.getCall(0);
fnTestRequest(spyDetails);
});
With JQuery Spy Example
test( "Test ajax and view", function () {
// Prepare spy tests....
var spy = $.spy({
ajax:{
url:"/someUrl/",
dataType:'jsonp',
type:'GET',
success:{
views:[{
el:'#someSelector',
css:{'visibility':'visible'},
html:'some code here...'
}]
}
// OR
// success:function(){
// var el = $('#someSelector');
// ok(el.length, '#someSelector exists');
// equals(el.css('visibility'), 'visible',' #someSelector is visible');
// equals(el.html(), 'some code here...',' #someSelector contains html');
// }
//},config:{ intExpectExtra:3 }
}
});
// Run original ajax method
$.ajax({
url:'/actions/jsonpproxy/?url=/actions/json.js',
dataType:'jsonp',
type:'GET',
cache:'false',
success:function(data){
$('#qunit-fixture').html('<div id="someSelector">Some code here...</div>');
$('#someSelector').css({'visibility':'visible'});
}
});
// Collect data from spy and run request tests
// Collect data from spy and run response tests
spy.run();
});