Wednesday, February 26, 2014

Testing window.scroll with QUnit/Jasmine

So you have to write set of tests for your code. Lets say it modifies evilGlobal variable when window is scrolled past certain point, e.g.:

var evilGlobal=false;

$(window).on("scroll.singleJob", function(e) {
if (window.scrollY > 100) 
{
evilGlobal = true;
 }
});

Say you using either QUnit or Jasmine (I will provide examples for both) to write your tests and so you got yourself nice fixture setup:

<div style="padding-top: 0px;height: 20000px;">
        Very tall content
</div>

HTML seems straightforward so you put your test together in no time. Using QUnit it might look something like:

test("sets evil to true", function() {

window.scroll(0, 1000);
ok(evilGlobal, "test 1 was great success!!!");

});

Jasmine version:

it("sets evil to true", function() {

window.scroll(0, 1000);
expect(evilGlobal).toBeTruthy();

});

You run the test and it fails miserably. You called window.scroll(0,1000) but the callback will not be executed immediately. It will be put in tasks queue that every browser maintains (I wrote a post on tasks queues a while ago). As Javascript is single threaded the callback will have to wait till current thread is finished. So as our thread continues, the ok assertion that follows will be executed before the callback will have a chance to modify our evil variable. The interesting part is that the browser will however change the window.scrollY position and so if you call window.scrollY you will get 1000. 

Knowing that, the solution is simple. Simply trigger the handler manually and as we already using jQuery, trigger method will do the trick. QUnit code:

test("sets evil to true", function() {

window.scroll(0, 1000);
 $(window).trigger("scroll");
ok(evilGlobal, "test 1 was great success!!!");

});

Jasmine version:

it("sets evil to true", function() {

window.scroll(0, 1000);
 $(window).trigger("scroll");
expect(evilGlobal).toBeTruthy();

});

Why does it work? As the scrollY of the window is already updated all we need is to execute our callback. Trigger function of jQuery is called synchronously setting our variable to true so its ready for our assertion.

No comments:

Post a Comment