4

I'm trying to test some jQuery ajax code using QUnit and Mockjax and have it return different JSON for different tests, like this:

$(document).ready(function() {

function functionToTest() {
    return $.getJSON('/echo/json/', {
        json: JSON.stringify({
            "won't": "run"
        })
    });
}

module("first");

test("first test", function() {

    stop();

    $.mockjax({
        url: '/echo/json/',
        responseText: JSON.stringify({
            hello: 'HEYO!'
        })
    });

    functionToTest().done(function(json) {
        ok(true, json.hello);
        start();
    });               
});


 test("second test", function() {

    stop();

    $.mockjax({
        url: '/echo/json/',
        responseText: JSON.stringify({
            hello: 'HELL NO!'
        })
    });


    functionToTest().done(function(json) {
        ok(true, json.hello);
        start();
    });


});

});

Unfortunately it returns the same response for each call, and order can't be guaranteed, so was wondering how I could set it up so that it was coupled to the actual request and came up with this:

$.mockjax({
    url: '/echo/json/',
    response: function(settings) {

        if (JSON.parse(settings.data.json).order === 1) {
            this.responseText = JSON.stringify({
                hello: 'HEYO!'
            });
        } else {
            this.responseText = JSON.stringify({
                hello: 'HELL NO!'
            });
        }
    }
});

This relies on parameters being sent to the server, but what about requests without parameters, where I still need to test different responses? Is there a way to use QUnit's setup/teardown to do this?

Simon Gibbs
  • 4,737
  • 6
  • 50
  • 80
NickL
  • 1,870
  • 2
  • 15
  • 35

1 Answers1

3

It looks like you need to call $.mockjaxClear(); before you create another mock handler.

Mockjax works by changing the $.ajax method.

At the bottom of its source code we can see that the $.mockjax method you are using, which is one of its exposed methods, just appends more handlers to the mockHandlers array.

    $.mockjax = function(settings) {
        var i = mockHandlers.length;
        mockHandlers[i] = settings;
        return i;
    };

In the source code for the $.ajax replacement, we can see:

    // Iterate over our mock handlers (in registration order) until we find
    // one that is willing to intercept the request
    for(var k = 0; k < mockHandlers.length; k++) {

Your problem is due to the $.ajax method being satisfied with the first handler (therefore not the latest) mock handler in the array for the /echo/json/ url.

Here is my fork of your fiddle, just adding a $.mockjaxClear() line.


Edit:

A more flexible solution:

  • Outside any test function, decare a variable which will have the ID of the request handler for later changes.
  • Before a module where you need to override a certain handler, declare a variable (no need for initial value) for holding a backup of the handler you want to modify.
  • Then in the module setup function use $.extend to copy the settings from $.mockjax.handler(<your handlerID variable>) to this backup. In the module's teardown, use $.mockjaxClear(<your handlerID variable>) to delete the module, and then set <your handlerID variable> to something else.
  • Now you can override your handlers in the module setup and in the individual test functions.

But don't take my word for it. Check out the fiddle.

It's a lot more flexible like this. You can change that one handler and leave all the other handlers you might have intact.

It does seem to be potentially error-prone, so I would advise to be careful.

Fábio Santos
  • 3,899
  • 1
  • 26
  • 31
  • The unit tests don't lie! I could have sworn I tried mockjaxClear previously...I'll have to start taking my medication again :P – NickL Oct 23 '12 at 16:14
  • I had it in the module tear down, and in fact even clearing individual items by ID seems to fail for me. Clear all in the test body is less flexible, but works. – Simon Gibbs Oct 23 '12 at 21:45
  • Would rather award the bounty to something with the flexibility to declare a set of defaults for the module, unless I am persuaded that my need is a bad code smell. – Simon Gibbs Oct 24 '12 at 08:33
  • @SimonGibbs I guess a good approach would be to declare the mock settings object as a variable, and change it in module setup and teardown. – Fábio Santos Oct 24 '12 at 15:15