views:

58

answers:

2

Hi, i'm having a javascript function using jquery:

my.namespace.loadSomeStuff = function() {

    $.get('/Services/loadStuff', function(c){
        $("#stuffDiv").html(c);
    });
};

and am trying to write unit tests for this.

now, since this function is not really returning anything and loading some stuff asynchronous using jquery's 'get' i'm having a hard time testing this.

essentially what i would like to do is call this function, wait until it returns something and then access the loaded elements to verify... something like:

my.namespace.loadSomeStuff(function(){
    alert('boo');
    assertSame('Login', $("#stuffDiv").find(......);
});

now, i created a in the template that calls the unit test, and it will load and display correctly, but the alert or the assert are never executed.

is there a way i can do this without adding a ton of extra code to every single function i have?

thanks t

+1  A: 

You can use the global AJAX events for this, for example:

$(document).ajaxSuccess(fuction() {
  assertSame('Login', $("#stuffDiv").find(......));
});

ajaxSuccess would happen after each AJAX request, if you wanted an event that ran after all simultaneous requests finished, then ajaxStop is what you're after. Both of these handlers don't have to be attached to your AJAX methods directly, they can be done in the unit tests.

These are normal events (full list here), so you can .bind()/.unbind() as needed, for example when the unit test above is done:

$(document).ajaxSuccess(fuction() {
  assertSame('Login', $("#stuffDiv").find(......));
  $(this).unbind('ajaxSuccess'); //cleanup
});
Nick Craver
+1  A: 

You'd have to add an argument to the loadSomeStuff method to receive the callback function you called in your example code, and then deliberately call it:

my.namespace.loadSomeStuff= function(callback) {
    $.get('/Services/loadStuff', function(c){
        $("#stuffDiv").html(c);
        if (callback!==undefined)
            callback();
    });
};

I'm not sure it's worth making your code more complicated merely to support unit tests, though you could argue that adding callbacks to async functions is of general-purpose usefulness.

An alternative would be making the test use a crude timeout.

You could use ajaxSuccess as mentioned by Nick (maybe combined with a timeout, and/or also catching ajaxError?). But it strikes me this might be adding a bit too much implementation knowledge for a unit test. What if loadSomeStuff is changed in future to work without an XMLHttpRequest, or maybe only use it sometimes, when it's not cached? Then the unit test will break. Sure, you can update the test to match the implementation, but then that's not really a useful unit test, is it?

bobince
this though tells me that "callback is not a function"is there any other way i have to invoke this function now?
thorsten codeho
Ah, yeah, you'd need a check that a `callback` actually had been passed, otherwise code that didn't supply a callback would now fail! Added in code sample above.
bobince