appsignal

# Automated screenshots using Capybara and Selenium

Last week's AppSignal update included an updated interface design for every screen. This meant we had to update all screenshots on our homepage, to make sure they reflect the current state of the app. To reduce the vast amount of manual labor this takes, we decided to automate the process.

Luckily, we soon remembered that Selenium is capable of taking screenshots. We already use Selenium quite heavily through Capybara for our feature tests, so we set out to investigate if this could be a way to automate the task without introducing new moving parts. After some tinkering, we learned that our plan was feasible.

The API for taking a screenshot is straight-forward. Just set the browser window to the desired size, visit a page and take a screenshot:

require 'capybara'

Capybara.default_driver = :selenium
page.driver.browser.manage.window.resize_to(1600, 1200)
visit 'https://appsignal.com'
page.save_screenshot(file)

This creates a png file in the specified location. There's a caveat if you want to take Retina screenshots though: the Chrome driver creates Retina screenshots, but only shoots the visible area. The Firefox driver on the other hand does shoot the entire page, but not in Retina resolution. And because not everyone on our team uses a Retina screen, they wouldn't be able to update the screenshots anyway.

After some searching, we found a solution to the problem in this Gist by chrism. Using this nifty hack we let Firefox blow up the page to double the normal size, right before taking a screenshot:

page.driver.execute_script('
body = document.getElementsByTagName("body")[0];
body.style["transform-origin"] = "top left";
body.style["transform"] = "scale(2)";
')

With the Retina screenshot of the entire page done, the next step is to crop it to the desired dimension using the convert CLI tool that's included with ImageMagick:

convert #{file} -crop #{1600 * 2}x#{ 800 * 2}+0+0  #{to_file}

We have to double the dimensions, because ImageMagick does not know it's a Retina image. It just considers it to be 3200px by 1600px. The to_file directly points to the file in our assets folder.

Finally, we use pngquant to optimize the file. Our typical screenshots range from 220kB to 250kB, which means we should definitely minimize their sizes:

pngquant --force --output #{to_file} #{to_file}

That's all there's to it. We wrote a Rakefile based on these commands that we can run again whenever we make design changes. You can find a Gist with the complete code right here.

Automating this process has already paid off, and will keep us sane in the future too. For now, enjoy the resulting images in all their Retina glory in the Tour and elsewhere!