28

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 :)

Alex
  • 1,457
  • 1
  • 13
  • 26
Caroline
  • 1,582
  • 3
  • 16
  • 30
  • Timeout is a lack of response in given time, so you can't return a timeout – Danubian Sailor May 15 '13 at 08: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 May 15 '13 at 08: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. – Danubian Sailor May 15 '13 at 08: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 May 15 '13 at 13:31

4 Answers4

1

For 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?

Adrian Heine
  • 4,051
  • 2
  • 30
  • 43
0

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');
});
Jost
  • 5,948
  • 8
  • 42
  • 72
  • 1
    Perhaps the way to go for jQuery's Ajax, but CJ was asking about sinon's fake XHR; neither of these approaches work for sinon. – Yuri Gadow Feb 28 '17 at 18:35
0

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.

Samuel Urias
  • 92
  • 1
  • 3
-1

Set a timeout on your $.ajax() call and use Sinon fake timers to move the clock ahead before responding.

Mukul M.
  • 540
  • 1
  • 5
  • 15
  • CJ isn't making a $.ajax() call, but a sinon fake XHR call and sinon doesn't support the .timeout property. – Yuri Gadow Feb 28 '17 at 18:36