Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Wrapped gist up in an application

  • Loading branch information...
commit f8ad4d3178dd07238b1136b41e8aee49c5d63065 0 parents
Ben Griffiths authored
7 .gitignore
... ... @@ -0,0 +1,7 @@
  1 +*.gem
  2 +.rvmrc
  3 +*.tar.gz
  4 +rdoc
  5 +Gemfile.lock
  6 +html
  7 +pkg
2  Gemfile
... ... @@ -0,0 +1,2 @@
  1 +source :rubygems
  2 +gemspec
22 Rakefile
... ... @@ -0,0 +1,22 @@
  1 +require 'rubygems'
  2 +require 'rubygems/package_task'
  3 +require 'rdoc/task'
  4 +
  5 +RDoc::Task.new do |rd|
  6 + rd.main = "README.rdoc"
  7 + rd.rdoc_files.include("README.rdoc","lib/**/*.rb","bin/**/*")
  8 + rd.title = 'Your application title'
  9 +end
  10 +
  11 +spec = eval(File.read('web_regression.gemspec'))
  12 +
  13 +Gem::PackageTask.new(spec) do |pkg|
  14 +end
  15 +
  16 +require 'rake/testtask'
  17 +Rake::TestTask.new do |t|
  18 + t.libs << "test"
  19 + t.test_files = FileList['test/**/*_test.rb']
  20 +end
  21 +
  22 +task :default => :test
14 bin/web-regression
... ... @@ -0,0 +1,14 @@
  1 +#!/usr/bin/env ruby
  2 +
  3 +unless File.respond_to? :realpath
  4 + class File #:nodoc:
  5 + def self.realpath path
  6 + return realpath(File.readlink(path)) if symlink?(path)
  7 + path
  8 + end
  9 + end
  10 +end
  11 +$: << File.expand_path(File.dirname(File.realpath(__FILE__)) + '/../lib')
  12 +require 'web_regression'
  13 +
  14 +WebRegression::Cli.execute($PROGRAM_NAME,ARGV)
8 lib/web_regression.rb
... ... @@ -0,0 +1,8 @@
  1 +module WebRegression
  2 +end
  3 +
  4 +require 'web_regression/version'
  5 +require 'web_regression/application'
  6 +require 'web_regression/cli'
  7 +require 'web_regression/comparator'
  8 +
13 lib/web_regression/application.rb
... ... @@ -0,0 +1,13 @@
  1 +require 'uri'
  2 +
  3 +class WebRegression::Application
  4 + def initialize(options)
  5 + @options = options
  6 + end
  7 +
  8 + def start
  9 + reference_file = @options.reference_file
  10 + uri = URI(@options.url)
  11 + return WebRegression::Comparator.new(reference_file,"#{uri.scheme}://#{uri.host}:#{uri.port}",uri.path,@options).compare
  12 + end
  13 +end
59 lib/web_regression/cli.rb
... ... @@ -0,0 +1,59 @@
  1 +require 'optparse'
  2 +require 'ostruct'
  3 +
  4 +module WebRegression
  5 + class Cli
  6 + def self.parse_options(program,args)
  7 + options = OpenStruct.new
  8 + options.fastfail = false
  9 + options.nodiff = false
  10 + options.opendiff = false
  11 + options.reference_file = "/tmp/reference.png"
  12 +
  13 + opts = OptionParser.new do |opts|
  14 + executable = File.basename(program)
  15 + opts.banner = "Usage: #{executable} [options] URL"
  16 + opts.separator ""
  17 +
  18 + opts.on_tail("-h", "--help", "Show this message") do
  19 + puts opts
  20 + exit
  21 + end
  22 +
  23 + opts.on("-r","--reference_png PNG_FILE","Png file to compare against") do |f|
  24 + options.reference_file = f
  25 + end
  26 +
  27 + opts.on("-f", "--fastfail","Fail as soon as a difference detected. Implies -n") do
  28 + options.fastfail = true
  29 + end
  30 +
  31 + opts.on("-n", "--nodiff","Don't create a diff png") do
  32 + options.nodiff = true
  33 + end
  34 +
  35 + opts.on("-o", "--opendiff","Open the diff file") do
  36 + options.opendiff = true
  37 + end
  38 +
  39 + opts.on_tail("--version", "Show version") do
  40 + puts WebRegression::VERSION
  41 + exit
  42 + end
  43 + end
  44 + opts.parse!(args)
  45 + if ARGV.length != 1
  46 + puts opts
  47 + exit
  48 + end
  49 + options.url = ARGV[0]
  50 + options
  51 + end
  52 +
  53 + def self.execute(program,args)
  54 + options = parse_options(program,args)
  55 + app = WebRegression::Application.new(options)
  56 + exit app.start
  57 + end
  58 + end
  59 +end
88 lib/web_regression/comparator.rb
... ... @@ -0,0 +1,88 @@
  1 +require 'capybara'
  2 +require 'capybara/dsl'
  3 +require 'capybara/poltergeist'
  4 +require 'chunky_png'
  5 +require 'tempfile'
  6 +
  7 +Capybara.run_server = false
  8 +Capybara.default_driver = :poltergeist
  9 +Capybara.javascript_driver = :poltergeist
  10 +
  11 +class WebRegression::Comparator < Struct.new(:reference_file,:host,:path,:options)
  12 + include Capybara::DSL
  13 +
  14 + SUCCESS, FAILURE = 0,1
  15 +
  16 + def take_screenshot(name)
  17 + Capybara.app_host = self.host
  18 + visit(self.path);
  19 + page.driver.render(name,:full => true)
  20 + end
  21 +
  22 + def ensure_reference_image
  23 + unless File.exists?(self.reference_file)
  24 + $stderr.puts "Creating a reference screenshot at #{self.reference_file}"
  25 + take_screenshot(self.reference_file)
  26 + end
  27 + end
  28 +
  29 + def screenshot
  30 + @screenshot ||= begin
  31 + image_name = '/tmp/ss.png'
  32 + take_screenshot(image_name)
  33 + image_name
  34 + end
  35 + end
  36 +
  37 + def checksum_match?(file1, file2)
  38 + ref_md5 = `md5 #{file1}`
  39 + new_md5 = `md5 #{file2}`
  40 + ref_md5 == new_md5
  41 + end
  42 +
  43 + def reference_image
  44 + @reference_image ||= ChunkyPNG::Image.from_file(self.reference_file)
  45 + end
  46 +
  47 + def new_image
  48 + @new_image ||= ChunkyPNG::Image.from_file(screenshot)
  49 + end
  50 +
  51 + def highlight_diffs(new_image,diff)
  52 + x, y = diff.map{ |xy| xy[0] }, diff.map{ |xy| xy[1] }
  53 +
  54 + new_image.rect(x.min, y.min, x.max, y.max, ChunkyPNG::Color.rgb(255,0,0))
  55 + diff_path = '/tmp/diff.png'
  56 + new_image.save(diff_path)
  57 +
  58 + if options.opendiff
  59 + `open #{diff_path}`
  60 + end
  61 + end
  62 +
  63 + def compare
  64 + ensure_reference_image
  65 +
  66 + return SUCCESS if checksum_match?(self.reference_file,screenshot)
  67 +
  68 + diff = []
  69 +
  70 + reference_image.height.times do |y|
  71 + reference_image.row(y).each_with_index do |pixel, x|
  72 + unless pixel == new_image[x,y]
  73 + return FAILURE if options.fastfail
  74 + diff << [x,y]
  75 + end
  76 + end
  77 + end
  78 +
  79 + return SUCCESS if diff.length == 0
  80 +
  81 + unless options.nodiff
  82 + highlight_diffs(new_image,diff)
  83 + end
  84 +
  85 + return FAILURE
  86 + end
  87 +
  88 +end
3  lib/web_regression/version.rb
... ... @@ -0,0 +1,3 @@
  1 +module WebRegression
  2 + VERSION = '0.9'
  3 +end
14 test/null_test.rb
... ... @@ -0,0 +1,14 @@
  1 +require 'test/unit'
  2 +
  3 +class NullTest < Test::Unit::TestCase
  4 +
  5 + def setup
  6 + end
  7 +
  8 + def teardown
  9 + end
  10 +
  11 + def test_the_truth
  12 + assert true
  13 + end
  14 +end
23 web_regression.gemspec
... ... @@ -0,0 +1,23 @@
  1 +require File.join([File.dirname(__FILE__),'lib','web_regression','version.rb'])
  2 +spec = Gem::Specification.new do |s|
  3 + s.name = 'web_regression'
  4 + s.version = WebRegression::VERSION
  5 + s.author = 'Ben Griffiths'
  6 + s.email = 'bengriffiths@gmail.com'
  7 + s.homepage = 'http://techbelly.com'
  8 + s.platform = Gem::Platform::RUBY
  9 + s.summary = 'Simple guard-friendly utility for diffing web screenshots to make css refactoring easier'
  10 + s.files = %w(
  11 +bin/web-regression
  12 + )
  13 + s.require_paths << 'lib'
  14 + s.has_rdoc = false
  15 + s.bindir = 'bin'
  16 + s.executables << 'web-regression'
  17 +
  18 + s.add_dependency('chunky_png')
  19 + s.add_dependency('poltergeist')
  20 +
  21 + s.add_development_dependency('rake')
  22 + s.add_development_dependency('rdoc')
  23 +end

0 comments on commit f8ad4d3

Please sign in to comment.
Something went wrong with that request. Please try again.