I've had no problems sorting out mocking the success condition, but cannot seem to fathom how to mock the failure/timeout conditions when using Sinon and Qunit to test and ajax function:
My set up is this:
$(document).ready( function() {
module( "myTests", {
setup: function() {
xhr = sinon.sandbox.useFakeXMLHttpRequest();
xhr.requests = [];
xhr.onCreate = function (request) {
xhr.requests.push(request);
};
myObj = new MyObj("#elemSelector");
},
teardown: function() {
myObj.destroy();
xhr.restore();
}
});
});
and my success case test, running happily and receiving/passing through the received data to the success method is this:
test("The data fetch method reacts correctly to receiving data",
function () {
sinon.spy(MyObject.prototype, "ajaxSuccess");
MyObject.prototype.fetchData();
//check a call got heard
equal(1, xhr.requests.length);
//return a success method for that obj
xhr.requests[0].respond(200, {
"Content-Type": "application/json"
},
'[{ "responseData": "some test data" }]'
);
//check the correct success method was called
ok(MyObj.prototype.ajaxSuccess.calledOnce);
MyObj.prototype.ajaxSuccess.restore();
}
);
However, I cannot work out what I should be putting instead of this:
xhr.requests[0].respond(200, { "Content-Type": "application/json" },
'[{ "responseData": "some test data" }]');
to make my ajax call handler hear
a failure or timeout method? The only thing I could think to try was this:
xhr.requests[0].respond(408);
But it doesn't work.
What am I doing wrong or what have I misunderstood? All help much appreciated :)
I've had no problems sorting out mocking the success condition, but cannot seem to fathom how to mock the failure/timeout conditions when using Sinon and Qunit to test and ajax function:
My set up is this:
$(document).ready( function() {
module( "myTests", {
setup: function() {
xhr = sinon.sandbox.useFakeXMLHttpRequest();
xhr.requests = [];
xhr.onCreate = function (request) {
xhr.requests.push(request);
};
myObj = new MyObj("#elemSelector");
},
teardown: function() {
myObj.destroy();
xhr.restore();
}
});
});
and my success case test, running happily and receiving/passing through the received data to the success method is this:
test("The data fetch method reacts correctly to receiving data",
function () {
sinon.spy(MyObject.prototype, "ajaxSuccess");
MyObject.prototype.fetchData();
//check a call got heard
equal(1, xhr.requests.length);
//return a success method for that obj
xhr.requests[0].respond(200, {
"Content-Type": "application/json"
},
'[{ "responseData": "some test data" }]'
);
//check the correct success method was called
ok(MyObj.prototype.ajaxSuccess.calledOnce);
MyObj.prototype.ajaxSuccess.restore();
}
);
However, I cannot work out what I should be putting instead of this:
xhr.requests[0].respond(200, { "Content-Type": "application/json" },
'[{ "responseData": "some test data" }]');
to make my ajax call handler hear
a failure or timeout method? The only thing I could think to try was this:
xhr.requests[0].respond(408);
But it doesn't work.
What am I doing wrong or what have I misunderstood? All help much appreciated :)
Share Improve this question edited Sep 15, 2020 at 9:31 Alex 1,5801 gold badge15 silver badges27 bronze badges asked May 15, 2013 at 8:41 CarolineCaroline 1,6123 gold badges18 silver badges30 bronze badges 4- Timeout is a lack of response in given time, so you can't return a timeout – Cjxcz Odjcayrwl Commented May 15, 2013 at 8:44
- 1 I was hoping sinon might overcome that and give a standardised interface for all types of response. If I cannot 'return' a timeout using sinon - then how do I fake one? – Caroline Commented May 15, 2013 at 8:53
- I don't know sinon so maybe there's something specific, but normally you set the timeout to say 1ms, and use wait on server or mock-server side. – Cjxcz Odjcayrwl Commented May 15, 2013 at 8:54
- Good idea - I'll try that for the timeout method, but how about the failure method, what would the standard sinon way be of doing that? – Caroline Commented May 15, 2013 at 13:31
4 Answers
Reset to default 1For the timeout, sinon’s fake timers could help. Using them you wouldn’t need to set the timeout to 1ms. As for the failures, your approach looks correct to me. Can you give us more code, especially the failure handler?
Doing something like this
requests[0].respond(
404,
{
'Content-Type': 'text/plain',
'Content-Length': 14
},
'File not found'
);
works to trigger the 'error' callback in jQuery AJAX requests.
As for the timouts, you can use sinons fake clock like this:
test('timeout-test', function() {
var clock = sinon.useFakeTimers();
var errorCallback = sinon.spy();
jQuery.ajax({
url: '/foobar.php',
data: 'some data',
error: errorCallback,
timeout: 20000 // 20 seconds
});
// Advance 19 seconds in time
clock.tick(19000);
strictEqual(errorCallback.callCount, 0, 'error callback was not called before timeout');
// Advance another 2 seconds in time
clock.tick(2000);
strictEqual(errorCallback.callCount, 1, 'error callback was called once after timeout');
});
The main idea that I would use is to wrap everything related to the request inside "another function" that returns a promise.
Then in the test, when I mock the "another function" I just return a Promise.reject({}).
If some endpoint is going to give me a timeout, that is equivalent to a failed promise.
Set a timeout on your $.ajax() call and use Sinon fake timers to move the clock ahead before responding.