How do I unit test this JavaScript function, including mocking of Ajax call?
jquery, jquery-ui, mocking, qunit, unit-testing
Solution
I have successfully written a QUnit test for the success case and another for the failure case, as you can see from this jsFiddle. I employed Mockjax to fake Ajax responses and simulate success/failure conditions. Notably, I configured Ajax calls to be synchronous, so that I could write synchronous tests, as I had trouble figuring out how to run my tests after asynchronous Ajax callbacks had fired.
I also make use of the Sinon.JS library to fake dependencies and verify that e.g. dialogs are launched correctly.
The working test code is included below, see my question for the function under test (`statusmod.init`). Let me know if there's something you think I've left out.
var dialogSpy = null;
var windowSpy = null;
var id = "srcId";
var binId = "binId";
var url = $.validator.format("/api/binid/?id={0}", id);
var btnId = "#button-status";
module("Open status page", {
setup: function() {
// Allow us to run tests synchronously
$.ajaxSetup({
async: false
});
windowSpy = sinon.spy(window, "open");
dialogSpy = sinon.spy();
sinon.stub($.fn, "dialog", function() {
return {
"dialog": dialogSpy
};
});
statusmod.init(id);
},
teardown: function() {
windowSpy.restore();
$.fn.dialog.restore();
$.mockjaxClear();
// Remove click event handler for each test
$(btnId).unbind();
}
});
test("Successfully open status page", function() {
expect(4);
$.mockjax({
url: url,
contentType: "text/json",
responseText: {
Id: binId
}
});
var spinner = statusmod._spinner;
var spinnerSpy = sinon.spy(spinner, "show");
$(btnId).click();
ok(spinnerSpy.calledOnce, "Spinner shown");
ok(dialogSpy.withArgs("open").calledOnce, "Dialog opened");
ok(dialogSpy.withArgs("close").calledOnce, "Dialog closed");
equal(windowSpy.lastCall.args[0], $.validator.format("http://status/?Page=Status&Id={0}", binId), "Window opened");
});
test("Binary ID not found on server", function() {
expect(3);
$.mockjax({
url: url,
contentType: "text/json",
status: 404
});
$(btnId).click();
ok(dialogSpy.withArgs("open").calledTwice, "Dialogs opened");
ok(dialogSpy.withArgs("close").calledOnce, "Progress dialog closed");
ok(!windowSpy.called, "Window not launched");
});
Problem
As seen in this jsFiddle, I have a function 'init' that configures a button so that when clicked it opens a progress dialog and issues an Ajax call. I want to unit test this JavaScript code (using QUnit), and check the following cases: - Ajax call succeeds - Ajax call fails I need to mock out at least the Ajax call and the call to `window.open`, and other calls I'm sure, depending on unit test implementation. How can I write QUnit unit tests for my code that tests these two scenarios? EDIT: The code that needs to be tested: ``` var statusmod = (function() { var spinner = $("#spinner"); var init = function(id) { var progressDialog = $("#progressdialog-content").dialog({ autoOpen: false, title: "Launching Status Page" }); var errorDialog = $("#errordialog-content").dialog({ autoOpen: false, modal: true, buttons: { "OK": function() { $(this).dialog("close"); } } }); var btn = $("#button-status"); btn.button().click(function() { spinner.show(); progressDialog.dialog("open"); var url = $.validator.format("/api/binid/?id={0}", id); // Call Web service to get binary ID $.ajax({ url: url, dataType: "json" }).done(function(data) { window.open($.validator.format("http://status/?Page=Status&Id={0}", data.Id), target = "_newtab"); }).fail(function(jqXHR, msg, errorThrown) { errorDialog.dialog("open"); }).always(function() { progressDialog.dialog("close"); }); return false; }); }; return { init: init, _spinner: spinner }; }()); ```