16

How To Take A Screenshot On Failure

The Problem

With browser tests it can often be challenging to track down the issue that triggered a failure.

A Solution

A simple way to gain insight into your test failures is by capturing screenshots at the moment of failure. This is not only a quick and easy thing to add ot your tests. It's also a cornerstone of good automated testing practice.

Let's dig in with an example.

An Example

Let's start by including our requisite libraries (selenium-webdriver to drive the browser and rspec/expectations for our assertions) and wire up setup and teardown methods.

# filename: screenshot.rb

require 'selenium-webdriver'
require 'rspec/expectations'
include RSpec::Matchers

def setup
  @driver = Selenium::WebDriver.for :firefox
end

def teardown
  @driver.quit
end

Next we'll want to create a run method that will tie our test actions together with setup and teardown.

In it we'll not only want to use setup and teardown but we'll also want to wrap our test actions (e.g., the yield command) so we can rescue failed assertions. That way, when a failure occurs, we can specify some commands to capture additional information.

In this case, let's output the test failure message and leverage Selenium's screenshotting capability.

def run
  setup
  begin
    yield
  rescue RSpec::Expectations::ExpectationNotMetError => error
    puts error.message
    @driver.save_screenshot "./#{Time.now.strftime("failshot__%d_%m_%Y__%H_%M_%S")}.png"
  end
  teardown
end

.save_screenshot accepts a filename as a string (e.g., 'failshot.png'). When this command executes it will save an image file to your local system in the current working directory.

Note the use of Time.now.strftime in the screenshot filename. This is using a timestamp (down to the second). This will provide a (reasonably) unique file name and has the added benefit of listing the files in the order taken.

Now let's wire up our test.

run do
  @driver.get 'http://the-internet.herokuapp.com'
  expect(@driver.find_element(css: 'h1').text).to eql 'Welcome to the Internet!'
end

Expected Behavior

If we save this file and run it (ruby screenshot.rb from the command-line) here is what you would see:

  • Load the homepage of the-internet
  • Check the text of the page header
  • Output a failure message in the terminal
  • Capture a timestamped screenshot in the current working directory

Outro

For more info on strftime (a.k.a. String Formatted Time) go here.

But if you want truly unique filenames, then you should use a unique ID in the filename instead of a timestamp (e.g., something like uuid). This will prevent screenshots from getting overwritten when you have two (or more) tests taking screenshots at the same time.

Happy Testing!

Found this helpful?

Submit your e-mail in the form below to recieve tips like this!

One email every Tuesday. No Spam. Ever. Unsubscribe anytime.


Back to the archives