Automated Testing with Watir and RSpec, Part 1

Sometimes it can be hard to get started with open source automated testing. The documentation is usually on the bad side of horrible. Further, many of the tools were written by developers with a development focus in mind, which is different from those tools developed by testers. Even when you do find technical people that are able to describe how to use something well, the context for using the tool may not be what you are looking for. I certainly found this when I started out wanting to use Watir, WebDriver, and RSpec. You can spend a lot of time looking through various Wiki pages or blog posts to figure out the bits of information you need to eventually have a fully working solution.

And that can be really annoying. And yet here I am apparently offering yet another blog post covering the stuff. What I’m doing here is presenting the information I wish I had when I started out. I provide a little historical detail, a lot of implementation detail, and some reference information behind the implementation.

In order to get started with all of this, you do need Ruby installed as well as some gems. I’ve heard horror stories about people trying this but I’ve never found this to be terribly difficult. If you follow my instructions in Open Source Automation Setup you should be off to a good start.

Watir (pronounced “water”) stands for Web Application Testing In Ruby. Watir started out life as an automation tool for the Internet Explorer browser only. Specifically, Watir was a Ruby library that wrapped the COM interface to Internet Explorer. As it matured, the development of Watir branched into a group of related tools for different browsers. There was FireWatir (for Firefox), SafariWatir, and OperaWatir. All of these tools of what you might call the “Watir family” use a common API for accessing page elements within a browser window. All of the scripting is done using the Ruby language. The concepts behind Watir eventually were ported to a .NET-specific implementation called WatiN (“what in”) and a Java-based implementation called Watij (“wattage”). This is all very similar to how unit-based testing tools were ported to various languages, thus giving us RUnit, JUnit, and NUnit.

In many ways Watir started life very much like the popular tool Selenium. However, Selenium took a very different approach from Watir. The original Selenium was written in JavaScript and executed its scripts in the context of the browser, as a so-called “browser bot.” Selenium also promoted a sort of “vendorscript” known as Selenese although you could write tests in other languages, including Ruby. While Watir had a bit more functionality than Selenium, it gained that functionality by tying itself to a platform and a browser: Internet Explorer running on Windows. While Selenium had some clunky aspects, it was at least cross-browser.

Then along came WebDriver. WebDriver, unlike Watir and Selenium, is more of a framework than a library. The goal of the framework is to allow for the automated testing of web sites and web applications. Like Selenium, WebDriver is cross-browser. Like Watir, WebDriver allows certain aspects of its implementation to be tied to specific browsers to provide focused functionality. WebDriver’s approach is that of supporting the most suitable control to automate each browser but doing so from one common interface. Here the control refers to the browser itself. Put another way, WebDriver works by changing the mechanism used to control the browser. In situations where using the browser to control automation does not quite work, WebDriver will utilize control points that are offered by the operating system itself. As an example, this means behind the scenes the framework will use “native OS events”, which comes in really handy when you have to deal with some aspects of JavaScript.

All of this explains how we ultimately got Watir-WebDriver. Watir-WebDriver is basically a nice Watir implementation on WebDriver. By using WebDriver, Watir can support any browser that WebDriver does. The same applies to Selenium, which is why we have Selenium-WebDriver. So basically Watir-WebDriver provides the Watir API for accessing page elements as an interface to WebDriver. This means there is now one common Watir tool for all WebDriver supported browsers: Internet Explorer, Firefox, Chrome and the headless HtmlUnit browser.

With that introduction out of the way, I’m going to present a development spike (that you can follow along with on your own system) to do the following:

  1. Create a Ruby script that uses watir-webdriver.
  2. Make sure the script can run on Firefox, Internet Explorer, and Chrome.
  3. Run a headless version of the script.
  4. Wrap the watir-webdriver logic in a BDD framework.
  5. Make sure I get useful output for test results.

So first I’ll create a file called testSpike_01.rb. If you read my post Spiking With Open Source Testing Tools, you know I tend to perform little spikes to assure myself I understand what I’m doing. Following on from what I learned in that post, here was my next iteration:

Here I did a little more than the bare minimum to prove things could work for me. I broke out the test into a class that has to be instantiated. I created two methods in the class: one to run the test (search_test) and another to verify the results of running the test (search_test_verify). I also made the script such that a command line argument (indicating what browser to run on) must be passed in. You’ll probably note that I didn’t include any error handling for situations where a browser name is not passed in. So if you want to run this script and have it work, make sure to call it with the name of a browser, like this:

$ testSpike_01.rb firefox

What that ends up doing is having the statement in the initialize method execute as if it were written like this:

That’s a statement you’re probably going to see in blogs or other material about how to use Watir-WebDriver. Assuming all goes were, here are the results you get:

$ testSpike_01.rb firefox
Result: Showing 1 - 12 of 35,732 Results
PASS: Results Count verified.
Result: Title was Amazon.com: star wars: Books
PASS: Title was reflective of content.

Granted, your results count may differ but you should see something like the above.

Since I’m using a site not under my control for this example, it’s very possible Amazon may change things around in terms of their controls or the identifiers on those controls. If the above script were not to work, such changes on Amazon’s part would be the most likely culprit.

Once I had that script running, I made sure I could run the test in other browsers by executing these commands:

$ testSpike_01.rb ie
$ testSpike_01.rb chrome

The output from each browser execution should be the same.

Using Internet Explorer In terms of Internet Explorer, if you’re like everyone else who tries this you’ll probably get a message telling you that “Protected mode must be set to the same value (enabled or disabled) for all zones.” There’s really no way around this. Choose the settings you want in your Internet Explorer browser settings. If you are concerned about this, read up on Understanding and Working in Protected Mode Internet Explorer. I’ve personally found it easier to just turn on protected mode for all zones but do whatever works for you.

Using Chrome If running on Chrome and you see an error about “Unable to find the chromedriver executable” — well, just follow the instructions it gives you. (I also mention this on Open Source Automation Setup.)

Okay, so that all works. Now you’ll probably be hearing all this interesting stuff about “running headless.” What this basically means is running your test with a headless browser. And what that means is running your test with a browser that does not have a graphical user interface. Essentially these headless versions are programmatic simulations of an actual browser. In order to do this, you’ll need a headless browser automation library. One such is known as HtmlUnit, which is an automation library for Java. HtmlUnit is designed to model web interactions in terms of the documents and interface elements which the user interacts with.

Celerity, anyone? There’s a lot of material out there about this and many Ruby-focused users will hear about Celerity, which is essentially a Ruby wrapper around HtmlUnit. (Actually, it’s a JRuby wrapper.) The goal of Celerity was to wrap HtmlUnit in a Watir-like API. Celerity itself was eventually wrapped by the similar sounding Culerity. The goal of that tool is to integrate Celerity and Cucumber. Never let it be said we don’t have lots of choices, I guess.

This can be a little confusing. The selenium-webdriver gem (which watir-webdriver is built on) does not support HtmlUnit directly. However, the gem does support the remote WebDriver protocol. What that means is that you can use HtmlUnit by launching the Java WebDriver server and then pointing watir-webdriver at it. So to get my above test script to run with HtmlUnit, I found that the best option was to launch a Selenium Standalone server from within my script. This, of course, implies I have the Selenium Standalone server available to me. (Again, I mention this on Open Source Automation Setup.) So I created a testSpike_02.rb file based on my testSpike_01.rb file. Here’s that script with the major differences highlighted:

Since this a headless browser you can see I dropped the idea of passing in the browser name. This meant my initialize method no longer took an argument and the call to instantiate a Watir browser was quite a bit different. You can see that I create a server instance for Selenium, referencing the jar. In the above example, I just put the jar in the same directory as the script for ease of demonstration. Running this test should give you the same output as the previous test script but, since this is a headless execution, you will see no browser open up as part of the test execution.

And this brings up a real good place to perhaps take a break but also segue into what I want to discuss next, which is that output. If you’ve built automated test frameworks before or at least worked with commercial tools, one glaringly obvious problem with what I’ve done so far is that you have to look at a console window for printed output indicating whether or not a test passed. Clearly one approach would just be to print nothing if everything succeeded and save output for error situations. Then if you got no output at the console you could just assume everything worked well.

Yeah, I know. That approach is fraught with peril.

Another approach would be to make my framework do nifty things like give the output in a nicer format. As long as I’m going to do that, I might want to just check if some other framework exists that already does that for me.

As it turns out, RSpec can work quite well in this regard. RSpec is one of the numerous test frameworks written in Ruby. In this context, I’m going to use RSpec with Watir but I want to note that RSpec and Watir have no necessary connection. The goal of RSpec is to provide a domain-specific language for describing the expected behavior of an application. RSpec provides methods that allow you to specify the behavior you expect. You can then fill in those methods with logic that serve as executable examples.

I’ll do all that as part of the next post on this topic. In the meantime, I urge you to explore the script created here. Study up on Watir-WebDriver and its API. As you try various aspects of the API, make sure your script can continue to run in different browsers. If you are new to Ruby, you’ll want to continue your education in that regard as you play with Watir constructs. For example, did you know that the @browser in all my examples is an instance variable? If not, read up on those. Was it clear to you that “(/Showing .* of .* Results/)” in my examples was the use of a regular expression? If not, you might want to check out those. There’s a lot to learn as you embark upon open source testing but I’ve found one of the better approaches is to simply jump right in, once someone has given you some context for doing so.

Happy learning!

About Jeff Nyman

Anything I put here is an approximation of the truth. You're getting a particular view of myself ... and it's the view I'm choosing to present to you. If you've never met me before in person, please realize I'm not the same in person as I am in writing. That's because I can only put part of myself down into words. If you have met me before in person then I'd ask you to consider that the view you've formed that way and the view you come to by reading what I say here may, in fact, both be true. I'd advise that you not automatically discard either viewpoint when they conflict or accept either as truth when they agree.
This entry was posted in RSpec, Watir. Bookmark the permalink.

4 Responses to Automated Testing with Watir and RSpec, Part 1

  1. Brandon says:

    This is the best article I’ve read online in a long time. Thank you for a clear and well-formed tutorial.

  2. Priyanka says:

    Hi,

    Thanks for this awesome tutorial.I tried running script testSpike_01.rb with FF and Chrome , it works as expected.But why doesn’t it works with safari?

    • Jeff Nyman says:

      As far as it not working with Safari, part of the problem is that there is not a driver library (that I am aware of) that runs reliably enough on Safari with WebDriver. Chrome, for example, uses the ChromeDriver and Internet Explorer uses the IEServer. Firefox support tends to be built in. I’m not aware of too much support for Safari. (In the world of Watir there was a SafariWatir driver, but I think that was before Watir-WebDriver.)

  3. Jaime Lyn says:

    Hey, there. Just wanted to let you know that your blog is still helping aspiring coders in the future. Thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">