Watir reports with screenshots using RSpec and Win32::Screenshot

Posted by aslak.hellesoy

At one of the projects in BEKK we’re using Watir extensively to verify that the web application is working as expected. We’re using RSpec to drive Watir.

Every now and then the Watir specs fail (either on a developer machine or on the Continuous Integration machine). For each failure we want to know what HTML the browser had, and what the browser looked like at the time of failure. Knowing this makes the process of hunting down the cause much easier, because it gives us more context information.

Watir comes with built-in support for screenshots via Watir::ScreenCapture, but it is a really nasty hack so we didn’t want to use that. We also wanted a nice-looking HTML report for all the specs, with a screenshot of the browser (and a link to the HTML) for each of the failing specs.

About the same time as I released Win32::Screenshot, Luke Redpath contributed a much improved HTML report for RSpec. (The RSpec website has some more examples of passing and failing specs).

Getting screenshots into the RSpec HTML reports is quite easy. First, in the spec’s teardown we have to take a screenshot and store it in a file with a unique name. (I’ve simplified the code a little here to illustrate the technique – the full code is available in RSpec’s svn). Let’s start with the spec:


context "Google's search page" do
  setup do
    @browser.goto('http://www.google.com')
  end

  specify "should find rspec's home page when I search for rspec" do
    @browser.text_field(:name, "q").set("rspec")
    @browser.button(:name, "btnG").click
    @browser.contains_text("rspec.rubyforge.org").should_not_be nil # should_contain_text is RSpec sugar
  end

  specify "should find rspec's home page when I search for 'better than fudge' (will probably fail)" do
    @browser.text_field(:name, "q").set("better than fudge")
    @browser.button(:name, "btnG").click
    @browser.contains_text("rspec.rubyforge.org").should_not_be nil
  end

  specify "should not find Ali G when I search for respec" do
    @browser.text_field(:name, "q").set("respec")
    @browser.button(:name, "btnG").click
    @browser.contains_text("Ali G").should_be nil
  end

  teardown do
    # Take the screenshot 
    width, height, bmp = Win32::Screenshot.foreground
    img = Magick::Image.from_blob(bmp)[0]
    # dir and spec number are defined outside
    img_path = "#{dir}/#{spec_number}.png" 
    img.write(img_path)

    # Get the HTML from Watir and save it too
    File.open("#{dir}/#{spec_number}.html", "w") {|io| io.write(browser.html)}
  end
end

RSpec will output a HTML report when you run it with —format html, but it doesn’t link to images or the HTML source. We have to write a little extension to RSpec’s default HTML formatter:


class WebTestHtmlFormatter < Spec::Runner::Formatter::HtmlFormatter
  def extra_failure_content
    @output.puts "
" @output.puts "" end end

Finally we have to tell RSpec (which is driving Watir via our specs) to use our WebTestHtmlFormatter when it runs the specs:


spec --require web_test_html_formatter.rb --format WebTestHtmlFormatter

The astute reader might have noticed that in the clickable screenshot above I have a Safari window and not an Internet Explorer one. The fact is, you can use this very same technique on a Mac, using Dave Hoover’s SafariWatir. The only difference is that you’ll use OS X’ built-in screencapture command to take the screenshots.

If you want to try this out, install the latest RSpec (0.7.4 or later). Then check out RSpec with subversion and peek inside vendor/web_spec. (The path within the repository may change soon).