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.

Monday, February 10, 2014

Deciphering IE10 popular check syntax

Lovely Microsoft decided to remove support for conditional comments in IE10. So what to do when for whatever reason we need to target this browser and only this browser? There are different ways. One interesting method I would like to discuss is use of self invoking function as:

Function('/*@cc_on return document.documentMode===10@*/')()

In IE10 this will return true and in a code might be used as:

if(Function('/*@cc_on return document.documentMode===10@*/')()) {

$("html").addClass("ie10");
ie10=true;
}

If you are after quick solution its as easy as copy and paste (or try this if(/*@cc_on!@*/false && document.documentMode===10){}). Some might wonder though what exactly this twisted syntax is. Lets try to decipher it step by step. So we trying to understand:

Function('/*@cc_on return document.documentMode===10@*/')()

Right, lots happening here, self invoking function, conditional compilation and what not. Lets start from something easy, consider the code:

var doh=function() {
         alert('DOH!');
}

doh();

This will create a function object and alert DOH! on the screen. Because its a function JS allows us to call it as doh(). Another way of creating function object is via Function constructor as below.

var doh=Function("alert('DOH!')");

doh();

We can still call doh() with no problem. The difference is that this time the body of a function is passed as an argument to Function constructor. 

Keep in mind that there are more differences that you need to be aware when deciding on using constructor syntax. For details I would recommend reading MDN docs for our purposes however all you need to understand is that body of a function can be passed as an argument to a Function constructor.

Easy stuff so far. Now lets make this function self invoking. All we need to do is:

Function("alert('DOH!')")();

We simply instantiating a function object and invoking it right away. When you execute the line it will pop alert on the screen as in previous examples. Very useful construct indeed. Now we might as well replace our alert with /*@cc_on return document.documentMode===10@*/ getting back to our original code:

Function('/*@cc_on return document.documentMode===10@*/')()

Now, what exactly is all this /*@cc.... voodoo you ask? Well, Microsoft folks came up with JScript which is their implementation of JavaScript. JScript also supports something called conditional compilation. You can think of it as sort of conditional comments but for JavaScript (in IE). As per MSDN @cc_on activates conditional compilation within comments in a script so in IE<11:

Function("/*@cc_on alert('DOH!')@*/")()

Will alert DOH!, all other browsers will recognise the function body as a comment only. Now replace alert with our return statement and you got yourself check for IE10 ready to use. 

Furthermore, as I found out skipping cc_on still gives the same results so in my code Function("/*@ alert('DOH!')@*/")() also does the trick. 

I know what you thinking now.. You can check for any IE with this method. From my experiments however, despite of what MSDN documentation is saying I learned that conditional compilation is not supported in IE11. Oh well, I'm sure MS will come up with more conditional improvements soon that will make our lives (not necessarily) easier.

Sunday, February 9, 2014

Sass now even better in Chrome!

So you've tried Sass and you love it. No more CSS-mess for you no more! BUT (isn't there BUT always?) when debugging your code in your favourite Chrome the line numbers in Styles tab do not refer to exact lines in your Sass source file. These refer to generated CSS file that you no longer directly modify. So in dev. tools you still see line number refering to CSS file:



It would be so much easier if tools referred directly to Sass source file as below:


Now (and have been for a while to be honest) it is possible as Chrome allows use of source maps. This basically will map properties from CSS file that browser uses to style elements to source Sass file you directly edit.

To make it happen you need to have late version of Sass installed, at the time of writing this is 3.3.0.rc.2 (whole list of versions can be found here). If you don't have it yet simply run:

gem install sass --version=3.3.0.rc.3

One note.. there is a long list of versions available. As I found out installing anything above version 3.3.0.alpha.201 and running sass with --watch argument does not seem to detect when the file is being updated. --watch argument as you probably know makes Sass to detect when new version of the scss file is saved and recompiles css accordingly. In versions newer then 3.3.0.alpha.201 this doesn't seem to work, at least on my system. That might be fixed by the time you reading this, but I couldn't get it working even with the current latest RC3. If thats the case and you find --watch useful install Sass via gem install sass --version=3.3.0.alpha.201

Now you have Sass installed so go to Chrome dev. tools settings ans tick as below:


And after that you need to tell Chrome where the source file is so it can map CSS properties to it. To do that in Settings-->Workspace "Add folder" and point to the folder where source file is located. Chrome will ask you to confirm that you want to give access to this particular location.


Right, Chrome part is set, all we need to do is run Sass with additional --sourcemap argument e.g.:

sass --sourcemap --watch path_to_scss_file:path_to_css_file

Now you might remember --debuginfo argument used with earlier versions of SASS, this is no more and now --sourcemap does the trick.

And that's pretty much all, hit F5 to refresh the page and enjoy new and improved Styles tab with line numbers referring to Sass file.

Thursday, February 6, 2014

Debugging much?

We all debug. It's easy enough.. hit F12, find a script where breakpoint is needed, set it and wait when JS execution will pause where the breakpoint is set. Wouldn't it be nice though if you could specify directly in the source code when the debugger should pause exactly as the breakpoint does? Well, thank you lucky stars that if you are using Chrome all you need is debugger function. So given code:

// some amazing JS here

debugger; // program will pause here, that's the breakpoint

// even more amazing JS

If dev. tools panel is open this will pause execution at the point where debugger call is. Pretty useful if you ask me.

Wednesday, February 5, 2014

Pure ASCII awesomeness

If you are old enough you might remember how ASCII characters where used to generate images. Non-geeks will say "ehh...I like jpg better", but if you anything like me you will fully appreciate ASCII art awesomeness. I googled this generator, uploaded photo of my lovely daughter and screenshot of result is below. It sure brings back memories of times when 8bit computers ruled.



No more Notepad++! Sublime Text all the way!

You know when a kid gets a new toy and is so excited that wants everyone know how cool the toy is? Well I feel like that kid today as found new tool that some of you might already know about.

Ok, as most of the work I do is JavaScript with usual mixture of HTML and CSS I tend to stick with simple tools. Set of web browsers, Git and text editor. Originally, years back I used Homesite (when it was still owned by Allaire). Then I switched to Notepad++ and been using it till today. Its simple enough, allows easy duplicating lines, folding etc. With a bit of configuration I was able to get it the way I like it. Using plugins you can compare files and it provides most of the basic functionality you would expect from simple text editor. It's far from perfect though and many times got on my nerves and e.g. folding I mentioned gets confused sometimes and N++ got few other glitches.

Every now and then I look up new tools. It's been few years with Notepad++ and thought I should give something new a try. Once my favourite, Homesite officially is dead and buried now. I still cannot believe that even though it wasn't improved since a decade or so Adobe was still charging money for it. Luckily I came across Sublime Text 3. I Downloaded the thing, installed and got totally blown away. All basic editing features that I constantly use are in there. Duplicate line by CTRL+SHIFT+D instead of CTRL+D as in Notepad++. Installing new plugins (they call it packages in ST3) is a breeze and in few minutes I had SASS support, Git and all ready to work. And the best thing is you configure everything by modifying JSON structures in config files. How simple is that??

Long story short Notepad++ compares to Sublime Text 3 like chariot to Merc C63. If you are still one of those unfortunate souls that code with Notepad++, you really should give Sublime Text 3 a try. For me there is no going back, not any time soon anyway. This thing really puts smile on my face and if you haven't already, you can download this gem from http://www.sublimetext.com/3.