Last active
June 10, 2018 12:52
-
-
Save mhluska/86f302d2fc1b4356db814aa9408aedba to your computer and use it in GitHub Desktop.
Quick and dirty visual regression testing with Rails + Capybara + Selenium
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# spec/rails_helper.rb | |
if ENV['SAVE_SCREENSHOTS'] | |
module CapybaraElementExtensions | |
INTERACTION_METHODS = %i[set select_option unselect_option click | |
right_click double_click send_keys hover trigger drag_to execute_script | |
evaluate_script evaluate_async_script] | |
INTERACTION_METHODS.each do |method| | |
define_method method do |*args, &block| | |
result = super(*args, &block) | |
sleep 1 | |
save_screenshot_with_description_filename | |
result | |
end | |
end | |
private | |
def screenshots_type | |
ENV['SAVE_SCREENSHOTS'] == 'baseline' ? 'baseline' : 'after' | |
end | |
def feature_name | |
RSpec.current_example.example_group.description.parameterize.underscore | |
end | |
def test_name | |
RSpec.current_example.description.parameterize.underscore | |
end | |
def save_screenshot_with_description_filename | |
self.class.interaction_counters[test_name] ||= 0 | |
filename = self.class.interaction_counters[test_name].to_s + '.png' | |
path = Rails.root.join('spec', 'screenshots', screenshots_type, feature_name, test_name, filename) | |
Capybara.save_screenshot(path) | |
self.class.interaction_counters[test_name] += 1 | |
end | |
end | |
module Capybara | |
module Node | |
class Element | |
class << self | |
attr_accessor :interaction_counters | |
end | |
@interaction_counters = {} | |
prepend CapybaraElementExtensions | |
end | |
end | |
end | |
end | |
# lib/visual_regression.rb | |
class VisualRegression | |
def self.write_html(image_paths) | |
images_html = image_paths.map { |path| "<div style='margin-bottom: 2em;'><a href=\"file://#{path}\" target=\"_blank\">#{path}</a></div><img src=\"#{path}\" style='max-width: 100%; margin-bottom: 4em; border-bottom: 1px solid #ddd; padding-bottom: 4em;' />" }.join("\n") | |
html = "<!DOCTYPE html><html><head><title></title></head><body style='font-family: sans-serif;'>#{images_html}</body></html>" | |
path = Rails.root.join('spec', 'screenshots', 'index.html') | |
File.write(path, html) | |
puts "Wrote #{path}" | |
end | |
def self.run | |
root_path = Rails.root.join('spec', 'screenshots', 'baseline') | |
image_paths = [] | |
Find.find(root_path) do |path| | |
if File.basename(path)[0] == '.' | |
Find.prune | |
next | |
end | |
next if FileTest.directory?(path) | |
baseline = Magick::ImageList.new(path) | |
after_path = path.gsub('/baseline/', '/after/') | |
after = begin | |
Magick::ImageList.new(after_path) | |
rescue Magick::ImageMagickError | |
puts "Not found, skipping #{after_path}" | |
next | |
end | |
diff, mean_error = baseline.compare_channel(after, Magick::MeanAbsoluteErrorMetric) | |
diff_path = path.gsub('/baseline/', '/diff/') | |
if mean_error > 0.01 | |
puts "Error #{(mean_error * 100).round(2)}\% found for #{diff_path}" | |
FileUtils.mkdir_p(File.dirname(diff_path)) | |
(after + baseline + [diff]).append(false).write(diff_path) | |
image_paths << diff_path | |
end | |
end | |
write_html(image_paths) unless image_paths.empty? | |
end | |
end | |
# lib/tasks/spec.rake | |
namespace :spec do | |
desc 'Run visial regression comparisons' | |
task :run_visual_regression => :environment do | |
VisualRegression.run | |
end | |
end | |
# .gitignore | |
/spec/screenshots/after | |
/spec/screenshots/diff | |
/spec/screenshots/index.html | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Easily adds visual regression testing to your existing selenium test suite. It works by monkey-patching Capybara to take screenshots whenever any
NODE_METHODS
are run. Now just run your tests before and after any front end changes and compare the resulting screenshots with a rake task.SAVE_SCREENSHOTS=baseline bundle exec rspec
Then take after screenshots using:
SAVE_SCREENSHOTS=after bundle exec rspec
Then run the diff task:
This will generate diff screenshots with baseline and complain if any have a difference beyond a threshold. Inspect screenshots: