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.

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.