CoffeeScript’s for loops don’t work on strings (despite appearances to the contrary)

I’ve been playing around with CoffeeScript, and found myself needing to loop over the characters (and indexes) in a string. So I tried a simple CoffeeScript for loop:

for char, index in line
    # ...

I ran it, and it worked, even in IE, so I assumed that CoffeeScript was doing whatever magical syntax was required to make it work everywhere.

Later I found out I was wrong. CoffeeScript was generating the syntax that works with arrays — list[index] — and that syntax only happens to sometimes work with strings. It works consistently in Chrome, and FireFox, and Opera. It even works in IE… but only if you have an HTML5 doctype.

<!DOCTYPE html>
<script>
document.write('abc'[1]);
</script>

The above HTML page works fine in IE9, outputting b as expected. But if you remove the <!DOCTYPE html> line, IE outputs undefined instead. That’s right, it loads a completely different version of JavaScript depending on what version of HTML you’re using! And if you load the above page into a WPF Frame, even the doctype won’t save you — it always outputs undefined.

When I went back and looked through the CoffeeScript documentation, sure enough, nowhere do they actually say that for loops can be used to iterate through the characters in a string. The fact that it ever works is apparently an accident, so don’t rely on it.

If you need to loop over the characters in a string, the right thing is to loop over the indexes and use charAt: See update below

for index in [0...line.length]
    char = line.charAt index
    # ...

Edit: Here’s a better way, suggested by the kind CoffeeScript folks:

for char, index in str.split ''

.NET and CoffeeScript: comparing Jurassic, Jint, and IronJS

Recently I went looking for ways to write a .NET desktop app that could compile CoffeeScript to JavaScript. There are already several NuGet packages for exactly this, but most of them look like they’re tightly bound to ASP.NET. So I struck out on my own, following the general steps in “CoffeeDemo – A Simple Demo of IronJS, using CoffeeScript”. The main CoffeeScript compiler is written in CoffeeScript, but they also provide one written in JavaScript, so my basic outline was:

  1. Instantiate a JavaScript engine.
  2. Tell the JavaScript engine to run coffee-script.js. This creates the CoffeeScript object and its compile method.
  3. Tell the JavaScript engine to call CoffeeScript.compile, and pass a string containing the CoffeeScript code to compile.

But my first attempt ran slower than I’d hoped for. (Well, coffee-script.js is 163 KB, and that’s the minified version! So I guess it does have a lot to do.)

I decided to find out whether I could do better: I tried several different JavaScript-in-.NET implementations, to see which one would perform the best. I tested Jurassic, Jint, and IronJS. My results are below, along with the C# code in case anyone is interested in seeing the minor differences between the APIs.

In all three cases, the coffeeCompiler parameter contains the 1.1.2 version of coffee-script.js, as downloaded from GitHub; and the input parameter contains a one-line CoffeeScript script:

alert "Hello world!"

Jurassic

Jurassic dynamically compiles JavaScript to CLR code at runtime, so you take a performance hit the first time you run some JS, but it should be pretty fast after that. Jurassic is available via NuGet.

private void CompileCoffeeScriptUsingJurassic(
    string coffeeCompiler, string input)
{
    Console.WriteLine("Jurassic");
    var stopwatch = Stopwatch.StartNew();
    Console.WriteLine(stopwatch.Elapsed + ": Creating engine");
    var engine = new ScriptEngine();
    Console.WriteLine(stopwatch.Elapsed + ": Parsing coffee-script.js");
    engine.Execute(coffeeCompiler);
    Console.WriteLine(stopwatch.Elapsed + ": Adding compile wrapper");
    engine.Execute("var compile = function (src) " +
        "{ return CoffeeScript.compile(src, { bare: true }); };");
    Console.WriteLine(stopwatch.Elapsed + ": Compiling CoffeeScript input");
    var output = engine.CallGlobalFunction("compile", input);
    Console.WriteLine(stopwatch.Elapsed + ": Done");
    Console.WriteLine("Output:");
    Console.WriteLine(output);
    Console.WriteLine();
}

Jint

Jint is a JavaScript interpreter. It’s not available through NuGet yet, but it’s a single DLL.

private void CompileCoffeeScriptUsingJint(
    string coffeeCompiler, string input)
{
    Console.WriteLine("Jint");
    var stopwatch = Stopwatch.StartNew();
    Console.WriteLine(stopwatch.Elapsed + ": Creating engine");
    var engine = new JintEngine();
    Console.WriteLine(stopwatch.Elapsed + ": Parsing coffee-script.js");
    engine.Run(coffeeCompiler);
    Console.WriteLine(stopwatch.Elapsed + ": Adding compile wrapper");
    engine.Run("var compile = function (src) " +
        "{ return CoffeeScript.compile(src, { bare: true }); };");
    Console.WriteLine(stopwatch.Elapsed + ": Compiling CoffeeScript input");
    object output = null;
    try
    {
        output = engine.CallFunction("compile", input);
    }
    catch (JsException ex)
    {
        Console.WriteLine("ERROR: " + ex.Value);
    }
    Console.WriteLine(stopwatch.Elapsed + ": Done");
    Console.WriteLine("Output:");
    Console.WriteLine(output);
    Console.WriteLine();
}

IronJS

IronJS is based on the DLR, so it seemed like it might strike a great balance between upfront compile time and runtime — after all, that’s what the DLR is all about.

IronJS is available through NuGet — there’s both an IronJS.Core (standalone) and an IronJS (depends on IronJS.Core), with nothing to explain the difference between the two; but at least for this code, you only need IronJS.Core.

private void CompileCoffeeScriptUsingIronJs(
    string coffeeCompiler, string input)
{
    Console.WriteLine("IronJS");
    var stopwatch = Stopwatch.StartNew();
    Console.WriteLine(stopwatch.Elapsed + ": Creating engine");
    var engine = new CSharp.Context();
    Console.WriteLine(stopwatch.Elapsed + ": Parsing coffee-script.js");
    engine.Execute(coffeeCompiler);
    Console.WriteLine(stopwatch.Elapsed + ": Adding compile wrapper");
    engine.Execute("var compile = function (src) " +
        "{ return CoffeeScript.compile(src, { bare: true }); };");
    Console.WriteLine(stopwatch.Elapsed + ": Fetching compile wrapper");
    var compile = engine.GetGlobalAs<FunctionObject>("compile");
    Console.WriteLine(stopwatch.Elapsed + ": Compiling CoffeeScript input");
    var result = compile.Call(engine.Globals, input);
    var output = IronJS.TypeConverter.ToString(result);
    Console.WriteLine(stopwatch.Elapsed + ": Done");
    Console.WriteLine("Output:");
    Console.WriteLine(output);
    Console.WriteLine();
}

The results

Jurassic
00:00:00.0000063: Creating engine
00:00:00.1540545: Parsing coffee-script.js
00:00:03.4346969: Adding compile wrapper
00:00:03.4408860: Compiling CoffeeScript input
00:00:05.3466983: Done
Output:
alert("Hello world!");

Jint
00:00:00.0000019: Creating engine
00:00:00.2617049: Parsing coffee-script.js
00:00:02.5270733: Adding compile wrapper
00:00:02.5295317: Compiling CoffeeScript input
ERROR: Parse error on line 2: Unexpected 'STRING'
00:00:02.5832895: Done
Output:


IronJS
00:00:00.0000019: Creating engine
00:00:00.2282421: Parsing coffee-script.js
00:00:55.5590620: Adding compile wrapper
00:00:55.5629230: Fetching compile wrapper
00:00:55.5642908: Compiling CoffeeScript input
00:01:17.8580574: Done
Output:
alert("Hello world!");

Jint wasn’t up to the task — it got a weird error when trying to call CoffeeScript.compile. I played with this a bit, and found that it would work if I passed an empty string, but give errors with non-blank CoffeeScript to compile; sometimes a string error like above, sometimes a weird error about multiline comments. It’s too bad, because Jint shows a lot of promise, speed-wise. I don’t know what the problem is; the error didn’t give me much to go on, and I’m not terribly motivated to pursue the problem when the other libraries work. (I did write this up in their bugtracker, though — it’s issue #6928.)

I was surprised that IronJS was so much slower than the others — about 20x slower than Jint at running coffee-script.js, and about 10x slower than Jurassic. This is especially puzzling since the article I based my code on mentions a “compilation lag”. To me, 55 seconds is hardly “lag”!

The winner here (and coincidentally the first one I tried) is Jurassic — so the performance that disappointed me is also the best I’m likely to get. On my laptop, you take about a 3.5-second penalty to compile coffee-script.js, and then another two seconds to run CoffeeScript.compile on a one-line script.

I did find that subsequent calls to CoffeeScript.compile were nearly instantaneous with all three libraries. So Jurassic’s 2 seconds is probably due to the JIT compiler running for the first time on that runtime-generated code. Not sure what to make of the 20 seconds for IronJS; is the DLR just that big?

Continuing the browser-testing journey: more automation and Vista thumbnails

I’ve been continuing my quest to easily run my unit tests in multiple browsers. Obviously, anything that takes more than 30 seconds is worth burning a couple of weeks trying to automate.

I originally thought I could do what I wanted with a Ruby script, using Watir (for IE), FireWatir (for FireFox), and ChromeWatir (for Google Chrome). I planned to run the script on demand, e.g. from my editor’s Tools menu, to (a) launch the browsers if they weren’t already running, (b) find an existing tab that was already open to the tests, or open a new tab if needed, and (c) (re)load the test page.

Worked great — for IE. (I posted sample code last time.) But FireWatir wasn’t able to re-use existing windows/tabs. And ChromeWatir is very pre-alpha and didn’t have anywhere near the feature set I needed.

Strike the *Watirs as a solution.

So let’s step back. What steps do I really want to automate?

  1. For each browser (Chrome, FireFox, and IE):
  2. If the browser is already running, Alt+Tab to it. Otherwise, launch it.
  3. If the tests are already open, Ctrl+Tab to the correct tab. If not, Ctrl+T to open a new tab, type in the URL, and hit Enter.
  4. Press Ctrl+R (or Ctrl+Shift+R in FireFox).
  5. Watch the screen while the tests run, to see whether they all pass.

Step 2 is automatable, and so is step 4. The others pose a bit more of a problem.

Then I stumbled across a solution for step 3. All three browsers, of course, support Ctrl+Tab and Ctrl+Shift+Tab to move between open tabs. It turns out they also all support Ctrl+<tab number> to jump to a tab by position. For example, Ctrl+1 to move to the first tab. Hey, I’m running these tests in a controlled environment — I can just say that I’ll keep the tests open in the first tab in each browser!

Okay, so that takes care of 3(a), of switching to the right existing tab. What about 3(b), opening a new tab? Ah, but why should I even need to do that? When I launch the browser, I can just pass the URL on the command line. Presto — my tests open in the first tab. As long as I’m smart enough not to close that tab, I’m set.

This is looking better and better. But there’s still that pesky matter of waiting for the tests to run in each browser, before I move on to the next one.

Or is there?

See, Windows Vista has this feature where, when you hover the mouse over a taskbar button, it shows a little thumbnail of the window. And that thumbnail is live — as long as the window isn’t minimized, the thumbnail stays updated in real-time as the window repaints, even if the window is fully covered by another maximized window. And this feature has an API.

If you have a window handle, you can put a live thumbnail of that window anywhere in your application, and any size you like. You don’t even have to write timer code to keep it updated — it just happens. It’s maaaagic.

I wound up going one step better than window handles and FindWindow: I wrote code that takes the fully-qualified path to the browser EXE, and automatically finds the main window for the running process. That way, I can have one thumbnail for the 32-bit IE, and another for the 64-bit IE, even though they both use the same window class. It’s pretty slick.

I wrapped it all up into a WinForms control called WindowThumbnail. Here’s a screenshot of my app with four thumbnails: Google Chrome, FireFox, 32-bit IE, and 64-bit IE:

WindowThumbnails action shot

The code isn’t polished enough to release yet, but if you drop me a note in the contact form I can e-mail you the rough code as it stands.

I was trying to enhance this app to be able to send the Ctrl+R keystrokes to the apps — ideally without focusing the other windows — but haven’t had much luck yet (turns out some apps don’t expect to get keystrokes when they’re not the foreground window). But I’ve realized that really, I can simplify that some more. There are tools that can launch apps, change focus, send keys; I don’t need to write C# code for that. I’ve heard good things about AutoHotkey, and it looks insanely scriptable, as well as making it trivial to bind the script to a shortcut key on the keyboard.

I might well be able to get this to the point where I press one key, and my computer automatically launches the browsers, Alt+Tabs through them, sends the tab-switch and refresh keystrokes, then switches to my dashboard app where I can watch the tests scroll by on all the browser windows at once.

Man, this is what being a geek is all about.

Watir: opening/reopening specific page in IE

I’m trying to use Watir to load a page in all three browsers (Chrome, FireFox, and IE). In my case, the page runs my JavaScript automated tests. My first step is to get this working with IE. IE runs the slowest, so it’s most in need of automation.

When I try the simple thing, I get some behavior that I wouldn’t expect. (For the record, I’m running IE7 on 64-bit Vista, with Watir 1.6.2.)

If I do the simple thing:

require 'watir'
ie = Watir::IE.new
ie.goto 'quest/stupid/specs/lib.html'

then IE opens two windows. Let us call them “the useless empty window” and “the real window”. The useless empty window opens first; its address bar says “about:blank”. Then the real window opens, pointing to the URL I actually told it to load.

If I run the code again, I get a second useless empty window, and then the URL loads in a new tab in the existing real window.

What’s more, if I manually click the address bar in one of the useless empty windows, and type a URL — say, www.google.com — IE pops up its “Internet Explorer needs to open a new window to display this webpage” warning. When I OK that, it opens Google in a new tab in the real window. So when I say “useless empty window”, I mean it — it’s useless, it’s empty, and it’s damn well gonna stay that way.

Okay, so the simple code needs some refinement. I don’t want useless empty windows piling up. I also don’t want tabs piling up in the real window. If there’s already a tab open to the URL I want, I want to reuse that existing tab (but still make it reload, since the point is to make sure I’ve run the latest and greatest version of my JavaScript unit tests).

Watir supports finding existing tabs through the Watir::IE.attach and Watir::IE.find methods; attach throws an exception if the page isn’t already open, while find just returns nil. Since I don’t know whether the page is already open, I want find. And if it succeeds, no useless empty window.

If IE isn’t even running yet, then there’s nothing for it: I have to open a useless empty window, and use that to open the real window. Fortunately, Watir has a close method, so I can close the useless empty window as soon as I have the real window open.

There’s another case, where IE is already running but there’s no tab that has my page open. I don’t want to stomp on an existing tab (unless it’s one that’s already pointing to my test page — in that case, I don’t mind assuming that it’s safe to refresh). In the “IE running but page not open” case, I currently just do the same thing as when IE wasn’t running: I open a useless empty window, use that to open a new tab in the real window, and then close the useless empty window so it doesn’t clutter up my life. There might be a nicer way to deal with this, but my code’s simpler when I only have to deal with two cases instead of three.

Here’s the code I settled on for opening a page in IE, or reloading it if it’s already open:

require 'watir'

def open_or_reopen_in_ie(url, url_regex)
  ie = Watir::IE.find(:url, url_regex)
  if ie
    ie.goto url
  else
    starter = Watir::IE.new
    starter.goto url
    starter.close
    ie = Watir::IE.find(:url, url_regex)
  end
  ie
end

open_or_reopen_in_ie('quest/stupid/specs/lib.html',
  /\bquest\/stupid\/specs\/lib\.html\b/)

open_or_reopen_in_ie needs two parameters: the URL to open, and a regex (or string, but regex lets you match just part of the URL and, for example, ignore the querystring). The regex is used to find an existing tab (or to find the tab we just opened in the real window).

So far, this has worked without a hitch. If the page I want isn’t already open, then I get an extra window for a few seconds, but it goes away automatically. If the page is already open, it reloads in its pristine state (no querystring), which is exactly what I want.

Unfortunately, Watir’s browser libraries aren’t all identical, so I’ll have to figure this out all over again for FireFox and Chrome. Stay tuned and I’ll relay the details.

Rant: IE and local JavaScript

So I’m writing a JavaScript-heavy application and testing it on my local machine. No problem, I think: just save the .html file on my disk and open it in a browser. Nothing could be simpler… if you’re using FireFox or Chrome.

IE, on the other hand, throws a hissy fit. “Danger!” it screams. “There’s a file on your local hard drive with JavaScript in it! Cower! Panic! The end is near!”

Okay, I took a bit of poetic license. What it actually says is, “To help protect your security, Internet Explorer has restricted this webpage from running scripts or ActiveX controls that could access your computer. Click here for options…”

Same thing.

It’s so bad that, if I type a path to a local file into the address bar, IE won’t even open it in the same window. It has to open a new window. Opening a local file involves opening IE, typing the path, clicking OK to its “sky is falling” dialog, letting it open its new window, Alt+Tabbing back to the original window, and closing it. All to open a file that’s under my complete control, completely trusted, doesn’t even require a network access.

Oookay. I guess I get it: IE is a claustrophobe. It panics when it feels the four walls of the local hard drive closing in on it. The remedy, obviously, is to let it out, and make it feel like it’s actually accessing the network. So I installed IIS, set up a virtual directory, and browsed to the web server on my local machine.

FireFox works fine. Chrome works fine. IE runs screaming in horror. “Oh noes!” it cries. “You’re trying to access an intranet! Oh, will nobody save me from the unspeakable dangers lurking on the private, firewalled network?”

Yeah, yeah, poetic license again, but honestly, that boy could use some Prozac*. Or heavy drugs. Or group hugs.

* Actually, anti-depression meds aren’t a good fit for the symptoms. Anti-anxiety might be better. Or possibly a good anti-psychotic.

At least it does run JavaScript now. And you can tell it to shut up about the many perils of the Intranet zone. (For that matter, yes, I could configure it to allow JavaScript for local files. But that doesn’t answer the question of why it’s got ridiculous settings to begin with.)

I just don’t get it. When IE runs across JavaScript on the big bad Internet, it trusts it unquestioningly. Sure, there are zone settings; it won’t let it do anything dangerous. But how is that less worthy of abject terror than something on my own hard drive? If I opened an EXE from my hard drive, Windows would quite happily let it install all the spyware it wants. But heaven forbid I open a Web page with some JavaScript animation. That might be bad.

Can’t we treat a Web page like a Web page and just open the damn thing? Is that too much to ask?

(Apparently not, because everybody but IE can do it just fine…)

Fumbling toward automation: running JavaScript tests with Watir

A group at work is doing some web-app development, and they’re using a tool called WatiN for end-to-end tests. I’m aware of that but didn’t think much of it.

Last night I went to Brian Marick‘s talk at the odynug meeting, and in passing, he mentioned Watir, which it turns out is infinitely cooler than WatiN, because Watir (a) came first, (b) is in Ruby, and (c) can automate IE, FireFox, and (via a separate library) Chrome.

I’m working on a JavaScript-based video-game development kit, and I spend a lot of time Alt+Tabbing to a browser, Ctrl+Tabbing to the tab with the automated test runner, refreshing the page, waiting (especially in IE) for the tests to finish, and (in Chrome) deciding whether the failures are actual test failures or just Chrome failures. Then it’s Alt+Tab to the next browser in the round-robin to try it again.

It shouldn’t be this hard to run all the tests. And with Watir, it looks like it won’t be. I think I’ll be able to write a Ruby script that

  • finds the Chrome tab that’s already open to the test URL (or opens a new tab);
  • reloads the Screw.Unit test page;
  • waits for the tests to complete;
  • scrapes the HTML to decide whether the tests passed or failed; and
  • repeats with FireFox and then with IE.

It won’t be trivial, because the Watir documentation really has nothing to say about finding stuff in the DOM. They’re heavily oriented toward clicking links and filling in forms, so if you want to manipulate a button or a hyperlink or a text field, they’ve got you covered. A myriad of examples, cheat sheets, and FAQs will get you on your way using methods like text_field and button. But if you want to find an <h3> with a particular CSS class, I wish you a lot of luck. The documentation does not go there. You need a lot of Google searches, a lot of luck, and a lot of lucky guessing.

I did scrape together something useful, and I’m noting it here. My tests currently report their results in an <h3>, which happens to be the only h3 on the page. This snippet of Ruby code will display the contents of that h3 (assuming the variable ie already refers to a Watir::IE instance):

ie.document.getElementsByTagName("h3")["0"].innerHTML

Huh. I get it that getElementsByTagName would return an array, so I would understand — and expect — having to do [0] on it. But [0] gives me an error: “TypeError: can’t convert Fixnum into String”. ["0"] works fine, though. I do not understand why, but as long as it works, I’ll accept that for now.

That’s just a start, though, because that snippet only works for classic Watir (for IE). FireWatir (the FireFox version, which is part of the same install but apparently not a compatible Ruby API) fails with “NoMethodError: undefined method `getElementsByTagName'”, and ChromeWatir (separate install) fails with “NoMethodError: undefined method `document'”.

Ah well. I came up with the above snippet by stealing shamelessly from the code for Watir’s show_spans method. Maybe I can do the same for the FireWatir and ChromeWatir versions of show_spans (if they have it). We shall see.

jQuery lesson learned: Close your tags

I’ve been playing around with JavaScript, so of course I’ve been looking for a JavaScript unit-testing framework — or better yet, a BDD framework, since they tend to make the assertions much more readable. I found Screw.Unit, and fell in love with it for its nested describes, which definitely merit their own blog post.

But I kept using JSSpec for a while, because Screw.Unit is still pretty buggy. JSSpec isn’t a resounding win by any means; its assertion syntax is merely okay, and it leaves you stuck with the traditional test-suite mentality. But it’s got a fantastic test-runner GUI that scales well as you add lots of tests.

Well, this weekend, after writing tests for one of my classes in both JSSpec and Screw.Unit, I finally decided the nested describes were so worth it. So I checked the Screw.Unit distro into my svn repository and started making the Screw.Unit runner better. I made it so you can tell when the tests are done, and whether any failed. I made it automatically scroll to the first failure on the page. I converted all my tests over to Screw.Unit. And I checked it all into my repository.

Then I tried running it in IE. Whoops. Blank page with nothing but some Roman numerals. Guess I should’ve done some cross-browser checking a little sooner…

I did some digging and some troubleshooting, and found that this jQuery syntax:

$('#myDiv').append($('<h2>'));

doesn’t work in IE. Dynamically-created nodes (the $('<h2>')) weren’t being added to the page — the append was doing nothing.

So I posted a question yesterday night on the jQuery list (“append() not working on dynamically-created nodes in IE”), and by this morning, I already had an answer: close the tag.

$('#myDiv').append($('<h2></h2>'));

Explains why some of my own code that created images was working in IE — I was using XHTML <img/> syntax, so my tags were closed.

I tried closing all the tags Screw.Unit was dynamically creating, and it worked like a champ. So there’s my jQuery lesson learned for today: always close your tags. If you don’t, things May Not Just Work.