compatriot 0.0.3 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +4 -0
- data/README.md +14 -8
- data/Rakefile +11 -1
- data/compatriot.gemspec +11 -7
- data/examples/compatriot_tests.rb +2 -2
- data/features/list_of_urls.feature +31 -0
- data/features/step_definitions/cli_steps.rb +60 -0
- data/features/support/env.rb +5 -0
- data/lib/compatriot.rb +1 -2
- data/lib/compatriot/image_differ/color_differ.rb +70 -0
- data/lib/compatriot/image_differ/image_differ.rb +41 -0
- data/lib/compatriot/results_presenter.rb +1 -1
- data/lib/compatriot/runner.rb +5 -3
- data/lib/compatriot/version.rb +1 -1
- data/spec/sample_app/{test_app.rb → sample_app.rb} +3 -3
- data/spec/spec_helper.rb +9 -35
- data/spec/unit/browser_spec.rb +4 -0
- data/spec/unit/image_differ/color_differ_spec.rb +39 -0
- data/spec/unit/image_differ/image_differ_spec.rb +67 -0
- data/spec/unit/runner_spec.rb +1 -1
- metadata +178 -48
- data/.rvmrc +0 -47
- data/lib/compatriot/image_differ.rb +0 -100
- data/spec/integration/full_stack_spec.rb +0 -36
- data/spec/unit/image_differ_spec.rb +0 -53
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e100d57f0086c254d7fcd46b1d615dc3ec7570a1
|
4
|
+
data.tar.gz: 3a474ae56359208e474ea4742b3092797e9a13e4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1f712342dfd796f65140fadb0251325d2e44f91d698f3c58859b721b010f3ca9ddd538ff0c8eb8275860b928ddeb2bf046c46c6cca9f6c16cfc63cfce7e91c53
|
7
|
+
data.tar.gz: bed0d7c8323e728fa30cadbb044b9ebe8e92829978da39516f7396fa650c91e4cf2b06a402dd0a20f8d50437cb7702438d65a19d0888bb63822875e1097b18fa
|
data/.gitignore
CHANGED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
compatriot
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.7
|
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
Compatriot
|
2
2
|
==========
|
3
|
+
[![Build Status](https://secure.travis-ci.org/clnclarinet/compatriot.png?branch=master)](http://travis-ci.org/clnclarinet/compatriot)
|
3
4
|
|
4
5
|
**Compat**ibility + **riot**! It's the **friend** that helps with browser compatibility!
|
5
6
|
This Ruby gem makes cross-browser testing less painful.
|
@@ -11,6 +12,7 @@ Don't let your users find the inconsistencies and get to them first.
|
|
11
12
|
What it does now
|
12
13
|
----------------
|
13
14
|
|
15
|
+
* [Documentation on RelishApp](https://www.relishapp.com/clnclarinet/compatriot)
|
14
16
|
* In firefox and chrome, visits a list of paths to a Rack app and takes a screenshot on each page.
|
15
17
|
* Stores the screenshot in `tmp/results/_timestamp_/_browser_/`
|
16
18
|
* Creates `tmp/results/_timestamp_/index.html` that shows thumbnails of each screenshot plus a diff of the two in a table for easy comparison.
|
@@ -19,11 +21,9 @@ What it does now
|
|
19
21
|
What it will do in the future
|
20
22
|
-----------------------------
|
21
23
|
|
22
|
-
* Have documentation
|
24
|
+
* Have more documentation (a start is [on RelishApp](https://www.relishapp.com/clnclarinet/compatriot)!)
|
23
25
|
* Have a screenshot of sample results in the README
|
24
|
-
* Have
|
25
|
-
* Be on travis-ci
|
26
|
-
* Not have a diff that's a different size than the originals
|
26
|
+
* Have more and better tests
|
27
27
|
* Find the largest, darkest contiguous region in the image diff and have a threshold of pass/fail based on that
|
28
28
|
* Perform better on the image processing (by sampling/resizing, using oily_png, etc)
|
29
29
|
* Given a list of URLs/paths to visit, will take a screenshot of each and display which URL it came from in the index
|
@@ -31,6 +31,7 @@ What it will do in the future
|
|
31
31
|
* Automatically compare the screenshots across browsers and flags those that are more than some configurable threshold different
|
32
32
|
* Allow configuration of which browsers to use
|
33
33
|
* Connect to virtual machines so that you don't have to have all the browsers on the machine you're running the tests on
|
34
|
+
* Steal some of VCR's relish rake tasks
|
34
35
|
|
35
36
|
|
36
37
|
How To Use
|
@@ -38,17 +39,19 @@ How To Use
|
|
38
39
|
|
39
40
|
**Requirements**
|
40
41
|
|
41
|
-
* Ruby
|
42
|
+
* Ruby v2.1.7
|
42
43
|
* [Firefox](http://getfirefox.net)
|
43
44
|
* [chromedriver](http://code.google.com/p/selenium/wiki/ChromeDriver)
|
44
45
|
|
46
|
+
There are setup examples in the examples directory and [documentation on RelishApp](https://www.relishapp.com/clnclarinet/compatriot)
|
47
|
+
|
45
48
|
When you run a file similar to the examples it will save results in `_current-directory_/tmp/results/_timestamp_/_browser_`
|
46
49
|
|
47
50
|
|
48
51
|
What to do to run its tests
|
49
52
|
---------------------------
|
50
53
|
|
51
|
-
Using at least ruby 1.
|
54
|
+
Using at least ruby 2.1.7:
|
52
55
|
|
53
56
|
bundle install
|
54
57
|
bundle exec rake test
|
@@ -83,14 +86,17 @@ Many thanks to the wonderful libraries that make this gem possible:
|
|
83
86
|
* [capybara](https://github.com/jnicklas/capybara)
|
84
87
|
* [selenium-webdriver](http://seleniumhq.org/docs/01_introducing_selenium.html#selenium-2-aka-selenium-webdriver)
|
85
88
|
* [chunky_png](https://github.com/wvanbergen/chunky_png) (and especially [this blog post about using chunky_png to create image diffs](http://jeffkreeftmeijer.com/2011/comparing-images-and-creating-image-diffs/?utm_source=rubyweekly&utm_medium=email) by Jeff Kreeftmeijer)
|
89
|
+
* [travis](http://travis-ci.org/) for CI
|
90
|
+
* [relishapp](https://www.relishapp.com/) for documentation
|
91
|
+
* [vcr](https://github.com/myronmarston/vcr) for having such awesome documentation that it inspired me to use Relishapp
|
86
92
|
|
87
93
|
|
88
94
|
Contributors
|
89
95
|
------------
|
90
96
|
* Carol Nichols ([twitter](http://twitter.com/carols10cents), [website](http://carol-nichols.com))
|
91
97
|
* Andrew Cox ([twitter](https://twitter.com/coxandrew), [website](http://andrewcox.org/))
|
92
|
-
* Kurtis Rainbolt-Greene ([twitter](https://twitter.com/krainboltgreene)
|
93
|
-
* Steve Klabnik ([twitter](https://twitter.com/steveklabnik)
|
98
|
+
* Kurtis Rainbolt-Greene ([twitter](https://twitter.com/krainboltgreene), [website](http://kurtisrainboltgreene.name/))
|
99
|
+
* Steve Klabnik ([twitter](https://twitter.com/steveklabnik), [website](http://www.steveklabnik.com/))
|
94
100
|
* You???
|
95
101
|
|
96
102
|
|
data/Rakefile
CHANGED
@@ -13,4 +13,14 @@ end
|
|
13
13
|
desc "Run tests"
|
14
14
|
task :spec do
|
15
15
|
task("test").execute
|
16
|
-
end
|
16
|
+
end
|
17
|
+
|
18
|
+
task :travis do
|
19
|
+
puts "Grabbing chromedriver..."
|
20
|
+
mkdir_p "/tmp/bin"
|
21
|
+
system "cd /tmp/bin && wget http://chromium.googlecode.com/files/chromedriver_linux32_16.0.902.0.zip && unzip chromedriver_linux32_16.0.902.0.zip"
|
22
|
+
|
23
|
+
puts "Starting to run tests..."
|
24
|
+
system("export PATH=/tmp/bin:$PATH && export DISPLAY=:99.0 && bundle exec rake test && bundle exec cucumber features")
|
25
|
+
raise "`rake test` failed!" unless $?.exitstatus == 0
|
26
|
+
end
|
data/compatriot.gemspec
CHANGED
@@ -18,13 +18,17 @@ Gem::Specification.new do |gem|
|
|
18
18
|
gem.name = "compatriot"
|
19
19
|
gem.require_paths = ["lib"]
|
20
20
|
gem.version = Compatriot::VERSION
|
21
|
+
gem.licenses = "MIT"
|
21
22
|
|
22
|
-
|
23
|
-
gem.add_development_dependency '
|
24
|
-
gem.add_development_dependency '
|
25
|
-
gem.add_development_dependency '
|
23
|
+
gem.add_development_dependency 'minitest', '~> 5.8', '>= 5.8.2'
|
24
|
+
gem.add_development_dependency 'sinatra', '~> 1.4', '>= 1.4.6'
|
25
|
+
gem.add_development_dependency 'mocha', '~> 1.1', '>= 1.1.0'
|
26
|
+
gem.add_development_dependency 'cucumber', '~> 2.1', '>= 2.1.0'
|
27
|
+
gem.add_development_dependency 'aruba', '~> 0.10.0'
|
28
|
+
gem.add_development_dependency 'relish', '~> 0.7.1'
|
26
29
|
|
27
|
-
gem.
|
28
|
-
gem.
|
29
|
-
gem.
|
30
|
+
gem.add_runtime_dependency 'capybara', '~> 2.5', '>= 2.5.0'
|
31
|
+
gem.add_runtime_dependency 'selenium-webdriver', '~> 2.48', '>= 2.48.1'
|
32
|
+
gem.add_runtime_dependency 'rake', '~> 10.4', '>= 10.4.2'
|
33
|
+
gem.add_runtime_dependency 'chunky_png', '~> 1.3', '>= 1.3.5'
|
30
34
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
Feature: list_of_urls
|
2
|
+
|
3
|
+
Passing a list of URLs to Compatriot.run will visit each of them in each browser and take a screenshot.
|
4
|
+
|
5
|
+
Scenario: List of URLs
|
6
|
+
Given a Sinatra app named "simple_app.rb" with:
|
7
|
+
"""ruby
|
8
|
+
get '/' do
|
9
|
+
'Hello'
|
10
|
+
end
|
11
|
+
|
12
|
+
get '/goodbye' do
|
13
|
+
'Goodbye'
|
14
|
+
end
|
15
|
+
"""
|
16
|
+
And a file named "compatriot_urls.rb" with:
|
17
|
+
"""ruby
|
18
|
+
$:.unshift(File.expand_path('../../lib', File.dirname(__FILE__)))
|
19
|
+
require 'compatriot'
|
20
|
+
require_relative 'simple_app'
|
21
|
+
Compatriot.app = SimpleApp
|
22
|
+
Compatriot.run(%w[
|
23
|
+
/
|
24
|
+
/goodbye
|
25
|
+
])
|
26
|
+
|
27
|
+
"""
|
28
|
+
And the directory "tmp/results" does not exist
|
29
|
+
When I run `ruby compatriot_urls.rb`
|
30
|
+
Then "tmp/results" should have 1 subdirectory
|
31
|
+
And there should be results for 2 screenshots
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module CompatriotHelpers
|
2
|
+
def create_sinatra_app(file_name, content)
|
3
|
+
app_class = camelize(file_name.gsub(/\.rb$/, ''))
|
4
|
+
beginning_sinatra_app = <<-HERE
|
5
|
+
require 'sinatra/base'
|
6
|
+
require 'rack'
|
7
|
+
require 'yaml'
|
8
|
+
|
9
|
+
class #{app_class} < Sinatra::Base
|
10
|
+
set :root, File.dirname(__FILE__)
|
11
|
+
set :static, true
|
12
|
+
HERE
|
13
|
+
|
14
|
+
ending_sinatra_app = <<-HERE
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
if __FILE__ == $0
|
19
|
+
Rack::Handler::WEBrick.run #{app_class}, :Port => 8070
|
20
|
+
end
|
21
|
+
HERE
|
22
|
+
beginning_sinatra_app + content + ending_sinatra_app
|
23
|
+
end
|
24
|
+
|
25
|
+
def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
|
26
|
+
if first_letter_in_uppercase
|
27
|
+
lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
28
|
+
else
|
29
|
+
lower_case_and_underscored_word.to_s[0].chr.downcase + camelize(lower_case_and_underscored_word)[1..-1]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
World(CompatriotHelpers)
|
34
|
+
|
35
|
+
Given /^a Sinatra app named "([^"]*)" with:$/ do |file_name, content|
|
36
|
+
write_file(file_name, create_sinatra_app(file_name, content))
|
37
|
+
end
|
38
|
+
|
39
|
+
Then /^"([^"]*)" should have (\d+) subdir/ do |directory, subdirectory_count|
|
40
|
+
cd('.') {
|
41
|
+
expect((Dir.entries(directory) - [".", ".."]).size).to eql subdirectory_count.to_i
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
Then /^there should be results for (\d+) screenshots?$/ do |screenshot_count|
|
46
|
+
screenshot_count = screenshot_count.to_i
|
47
|
+
results_tmp_dir = "tmp/results"
|
48
|
+
cd('.') {
|
49
|
+
current_results_dir = (Dir.entries(results_tmp_dir) - [".", ".."]).first
|
50
|
+
current_results_dir = File.join(results_tmp_dir, current_results_dir)
|
51
|
+
|
52
|
+
firefox_dir = File.join(current_results_dir, "firefox")
|
53
|
+
chrome_dir = File.join(current_results_dir, "chrome")
|
54
|
+
diffs_dir = File.join(current_results_dir, "diffs")
|
55
|
+
|
56
|
+
expect(Dir.glob(File.join(firefox_dir, "*.png")).size).to eql 2
|
57
|
+
expect(Dir.glob(File.join(chrome_dir, "*.png")).size).to eql 2
|
58
|
+
expect(Dir.glob(File.join(diffs_dir, "*.png")).size).to eql 2
|
59
|
+
}
|
60
|
+
end
|
data/lib/compatriot.rb
CHANGED
@@ -2,8 +2,7 @@ require "compatriot/version"
|
|
2
2
|
require "compatriot/runner"
|
3
3
|
require "compatriot/browser"
|
4
4
|
require "compatriot/results_presenter"
|
5
|
-
require "compatriot/
|
6
|
-
require "compatriot/image_differ"
|
5
|
+
require "compatriot/image_differ/image_differ"
|
7
6
|
|
8
7
|
module Compatriot
|
9
8
|
class << self
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'chunky_png'
|
2
|
+
include ChunkyPNG::Color
|
3
|
+
|
4
|
+
module Compatriot
|
5
|
+
class ColorDiffer
|
6
|
+
|
7
|
+
def self.diff(filename1, filename2, results_directory)
|
8
|
+
image1 = ChunkyPNG::Image.from_file(filename1)
|
9
|
+
image2 = ChunkyPNG::Image.from_file(filename2)
|
10
|
+
@results_directory = results_directory
|
11
|
+
|
12
|
+
output = ChunkyPNG::Image.new(image1.width, image1.height, WHITE)
|
13
|
+
diff = []
|
14
|
+
|
15
|
+
each_pixel(image1) do |x, y|
|
16
|
+
pixel1 = image1[x,y]
|
17
|
+
pixel2 = image2[x,y]
|
18
|
+
unless pixel1 == pixel2
|
19
|
+
output[x,y], score = color_difference_of_pixels(pixel1, pixel2)
|
20
|
+
diff << score
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
save_diff_image(output, filename1, filename2)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.save_diff_image(output, filename1, filename2)
|
28
|
+
filename = diff_name(filename1, filename2)
|
29
|
+
path = File.join(
|
30
|
+
@results_directory,
|
31
|
+
"diffs",
|
32
|
+
filename
|
33
|
+
)
|
34
|
+
output.save(path)
|
35
|
+
File.join("diffs", filename)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.diff_name(image1, image2)
|
39
|
+
browser1 = File.basename(File.dirname(image1))
|
40
|
+
browser2 = File.basename(File.dirname(image2))
|
41
|
+
|
42
|
+
"color_#{browser1}_vs_#{browser2}_#{File.basename(image1)}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.color_difference_of_pixels(pixel1, pixel2)
|
46
|
+
score = Math.sqrt(
|
47
|
+
(r(pixel2) - r(pixel1)) ** 2 +
|
48
|
+
(g(pixel2) - g(pixel1)) ** 2 +
|
49
|
+
(b(pixel2) - b(pixel1)) ** 2
|
50
|
+
) / Math.sqrt(MAX ** 2 * 3)
|
51
|
+
|
52
|
+
[grayscale(MAX - (score * MAX).round), score]
|
53
|
+
end
|
54
|
+
|
55
|
+
# Not called anywhere
|
56
|
+
def color_difference_total_score
|
57
|
+
pixels_total = image1.width * image1.height
|
58
|
+
pixels_changed = diff.length
|
59
|
+
pixels_changed_percentage = (diff.inject {|sum, value| sum + value} / pixels_total) * 100
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.each_pixel(image)
|
63
|
+
image.width.times do |x|
|
64
|
+
image.height.times do |y|
|
65
|
+
yield(x, y)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative 'color_differ'
|
2
|
+
|
3
|
+
module Compatriot
|
4
|
+
class ImageDiffer
|
5
|
+
|
6
|
+
def initialize(params = {})
|
7
|
+
@paths = params[:paths]
|
8
|
+
@browsers = params[:browsers]
|
9
|
+
@strategy = params[:strategy] || Compatriot::ColorDiffer
|
10
|
+
@results_directory = params[:results_directory]
|
11
|
+
@diffs = {}
|
12
|
+
|
13
|
+
create_diffs_path
|
14
|
+
end
|
15
|
+
|
16
|
+
def diff_for(path)
|
17
|
+
@diffs[path]
|
18
|
+
end
|
19
|
+
|
20
|
+
def compute!
|
21
|
+
@paths.map do |path|
|
22
|
+
images_to_diff = @browsers.map { |b| b.absolute_screenshot_for(path) }
|
23
|
+
@diffs[path] = diff(images_to_diff)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def diff(results)
|
28
|
+
@strategy.diff(results.first, results.last, @results_directory)
|
29
|
+
end
|
30
|
+
|
31
|
+
def diffs_path
|
32
|
+
File.join(@results_directory, "diffs")
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def create_diffs_path
|
38
|
+
FileUtils.mkdir_p(diffs_path)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/compatriot/runner.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
require
|
1
|
+
require 'fileutils'
|
2
|
+
require 'date'
|
2
3
|
|
3
4
|
module Compatriot
|
4
5
|
class Runner
|
@@ -42,7 +43,8 @@ module Compatriot
|
|
42
43
|
@differ = Compatriot::ImageDiffer.new(
|
43
44
|
:paths => @paths,
|
44
45
|
:browsers => @browsers,
|
45
|
-
:strategy =>
|
46
|
+
:strategy => Compatriot::ColorDiffer,
|
47
|
+
:results_directory => @results_directory
|
46
48
|
)
|
47
49
|
@differ.compute!
|
48
50
|
end
|
@@ -60,4 +62,4 @@ module Compatriot
|
|
60
62
|
FileUtils.mkdir_p(@results_directory)
|
61
63
|
end
|
62
64
|
end
|
63
|
-
end
|
65
|
+
end
|
data/lib/compatriot/version.rb
CHANGED
@@ -2,12 +2,12 @@ require 'sinatra/base'
|
|
2
2
|
require 'rack'
|
3
3
|
require 'yaml'
|
4
4
|
|
5
|
-
class
|
5
|
+
class SampleApp < Sinatra::Base
|
6
6
|
set :root, File.dirname(__FILE__)
|
7
7
|
set :static, true
|
8
8
|
|
9
9
|
get '/' do
|
10
|
-
"<h1>Hello world!</h1"
|
10
|
+
"<h1>Hello world!</h1><div><a href='chrome-css-bug'>Try another page</a></div>"
|
11
11
|
end
|
12
12
|
|
13
13
|
get "/chrome-css-bug" do
|
@@ -17,5 +17,5 @@ class TestApp < Sinatra::Base
|
|
17
17
|
end
|
18
18
|
|
19
19
|
if __FILE__ == $0
|
20
|
-
Rack::Handler::WEBrick.run
|
20
|
+
Rack::Handler::WEBrick.run SampleApp, :Port => 8070
|
21
21
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,13 +1,11 @@
|
|
1
1
|
$:.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
|
2
2
|
|
3
|
-
require
|
4
|
-
|
5
|
-
require 'minitest/autorun'
|
6
|
-
require 'mocha'
|
3
|
+
require "minitest/autorun"
|
4
|
+
require "mocha/mini_test"
|
7
5
|
|
8
6
|
require 'compatriot'
|
9
7
|
|
10
|
-
require_relative "sample_app/
|
8
|
+
require_relative "sample_app/sample_app"
|
11
9
|
|
12
10
|
# A custom runner to enable before_suite and after_suite setup/teardown.
|
13
11
|
# http://bfts.rubyforge.org/minitest/index.html
|
@@ -15,37 +13,13 @@ require_relative "sample_app/test_app"
|
|
15
13
|
# before running the suite; it's useful to be able to look at the screenshots
|
16
14
|
# after a test run so we're not deleting them then.
|
17
15
|
|
18
|
-
module
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
def after_suites
|
24
|
-
end
|
25
|
-
|
26
|
-
def _run_suites(suites, type)
|
27
|
-
begin
|
28
|
-
before_suites
|
29
|
-
super(suites, type)
|
30
|
-
ensure
|
31
|
-
after_suites
|
32
|
-
end
|
33
|
-
end
|
16
|
+
module TestRunner
|
17
|
+
def before_setup
|
18
|
+
super
|
19
|
+
FileUtils.remove_dir(File.join("sample_app", "tmp", "results"), true)
|
34
20
|
end
|
35
21
|
end
|
36
22
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
def before_suites
|
41
|
-
super
|
42
|
-
FileUtils.remove_dir(File.join("sample_app", "tmp", "results"), true)
|
43
|
-
end
|
44
|
-
|
45
|
-
def after_suites
|
46
|
-
super
|
47
|
-
end
|
48
|
-
end
|
23
|
+
class Minitest::Spec
|
24
|
+
include TestRunner
|
49
25
|
end
|
50
|
-
|
51
|
-
MiniTest::Unit.runner = MiniTestRemoveScreenshots::Unit.new
|
data/spec/unit/browser_spec.rb
CHANGED
@@ -86,6 +86,8 @@ describe Compatriot::Browser do
|
|
86
86
|
:name => "foo",
|
87
87
|
:screenshot_directory => "bar"
|
88
88
|
)
|
89
|
+
app = stub
|
90
|
+
@b.initialize_capybara(app)
|
89
91
|
end
|
90
92
|
|
91
93
|
it "visits the path" do
|
@@ -132,6 +134,8 @@ describe Compatriot::Browser do
|
|
132
134
|
:name => "foo",
|
133
135
|
:screenshot_directory => "bar"
|
134
136
|
)
|
137
|
+
app = stub
|
138
|
+
@b.initialize_capybara(app)
|
135
139
|
end
|
136
140
|
|
137
141
|
it "returns nil if there is no screenshot for that path" do
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe Compatriot::ColorDiffer do
|
4
|
+
it "calls chunky_png on each image path" do
|
5
|
+
image1 = stub_everything("1", :width => 1, :height => 2)
|
6
|
+
image2 = stub_everything("2", :width => 3, :height => 4)
|
7
|
+
|
8
|
+
ChunkyPNG::Image.expects(:from_file).with("file_one").returns(image1)
|
9
|
+
ChunkyPNG::Image.expects(:from_file).with("file_two").returns(image2)
|
10
|
+
Compatriot::ColorDiffer.stubs(:save_diff_image)
|
11
|
+
|
12
|
+
Compatriot::ColorDiffer.diff("file_one", "file_two", "some/dir")
|
13
|
+
end
|
14
|
+
|
15
|
+
it "starts a new white image with the same dimensions" do
|
16
|
+
diff_image = stub_everything
|
17
|
+
ChunkyPNG::Image.expects(:new).with(
|
18
|
+
1,
|
19
|
+
2,
|
20
|
+
ChunkyPNG::Image::WHITE
|
21
|
+
).returns(diff_image)
|
22
|
+
|
23
|
+
image1 = stub_everything("1", :width => 1, :height => 2)
|
24
|
+
image2 = stub_everything("2", :width => 3, :height => 4)
|
25
|
+
|
26
|
+
ChunkyPNG::Image.stubs(:from_file).returns(image1, image2)
|
27
|
+
Compatriot::ColorDiffer.stubs(:save_diff_image)
|
28
|
+
|
29
|
+
differ = Compatriot::ColorDiffer.diff(image1, image2, "some/dir")
|
30
|
+
end
|
31
|
+
|
32
|
+
it "names the image based on the strategy and the browsers" do
|
33
|
+
name = Compatriot::ColorDiffer.diff_name(
|
34
|
+
"/something/firefox/1.png",
|
35
|
+
"/something/chrome/1.png"
|
36
|
+
)
|
37
|
+
name.must_equal("color_firefox_vs_chrome_1.png")
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
describe Compatriot::ImageDiffer do
|
4
|
+
describe "compute!" do
|
5
|
+
it "diffs each set of images and stores the location by path" do
|
6
|
+
Compatriot::ImageDiffer.any_instance.stubs(:create_diffs_path)
|
7
|
+
|
8
|
+
d = Compatriot::ImageDiffer.new(
|
9
|
+
:paths => ["/home"],
|
10
|
+
:browsers => [
|
11
|
+
stub(:absolute_screenshot_for => "1.png"),
|
12
|
+
stub(:absolute_screenshot_for => "2.png")
|
13
|
+
]
|
14
|
+
)
|
15
|
+
d.expects(:diff).with(["1.png", "2.png"]).returns("diff.png")
|
16
|
+
d.compute!
|
17
|
+
d.diff_for("/home").must_equal("diff.png")
|
18
|
+
end
|
19
|
+
|
20
|
+
it "creates a diffs dir" do
|
21
|
+
FileUtils.expects(:mkdir_p).with("foo/bar/diffs")
|
22
|
+
d = Compatriot::ImageDiffer.new(
|
23
|
+
:results_directory => "foo/bar"
|
24
|
+
)
|
25
|
+
d.diffs_path.must_equal("foo/bar/diffs")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "diff" do
|
30
|
+
it "returns the filename of the diff" do
|
31
|
+
file_one = stub
|
32
|
+
file_two = stub
|
33
|
+
strategy = stub(:diff => "diff_filename.png")
|
34
|
+
ChunkyPNG::Image.stubs(:from_file)
|
35
|
+
FileUtils.expects(:mkdir_p).with("something/diffs")
|
36
|
+
|
37
|
+
c = Compatriot::ImageDiffer.new(
|
38
|
+
:strategy => strategy,
|
39
|
+
:results_directory => "something"
|
40
|
+
)
|
41
|
+
|
42
|
+
c.diff([file_one, file_two]).must_equal("diff_filename.png")
|
43
|
+
end
|
44
|
+
|
45
|
+
it "uses the strategy passed in" do
|
46
|
+
file_one = stub
|
47
|
+
file_two = stub
|
48
|
+
strategy = stub
|
49
|
+
|
50
|
+
ChunkyPNG::Image.stubs(:from_file).returns(file_one, file_two)
|
51
|
+
FileUtils.expects(:mkdir_p).with("something/diffs")
|
52
|
+
|
53
|
+
strategy.expects(:diff).with(
|
54
|
+
file_one,
|
55
|
+
file_two,
|
56
|
+
"something"
|
57
|
+
).returns("diff_filename.png")
|
58
|
+
|
59
|
+
c = Compatriot::ImageDiffer.new(
|
60
|
+
:strategy => strategy,
|
61
|
+
:results_directory => "something"
|
62
|
+
)
|
63
|
+
|
64
|
+
c.diff([file_one, file_two]).must_equal("diff_filename.png")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/spec/unit/runner_spec.rb
CHANGED
@@ -55,7 +55,7 @@ describe Compatriot::Runner do
|
|
55
55
|
|
56
56
|
describe "#results_directory" do
|
57
57
|
it "names a results directory in tmp/results based on the clock" do
|
58
|
-
runner = Compatriot::Runner.new(
|
58
|
+
runner = Compatriot::Runner.new(SampleApp, ["/"], @fixed_clock)
|
59
59
|
|
60
60
|
runner.results_directory.must_equal(@results_dir_name)
|
61
61
|
end
|
metadata
CHANGED
@@ -1,82 +1,203 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: compatriot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.5
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Carol Nichols
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2015-11-04 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: minitest
|
16
|
-
requirement:
|
17
|
-
none: false
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
18
16
|
requirements:
|
19
|
-
- - ~>
|
17
|
+
- - "~>"
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
19
|
+
version: '5.8'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 5.8.2
|
22
23
|
type: :development
|
23
24
|
prerelease: false
|
24
|
-
version_requirements:
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '5.8'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 5.8.2
|
25
33
|
- !ruby/object:Gem::Dependency
|
26
34
|
name: sinatra
|
27
|
-
requirement:
|
28
|
-
none: false
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
29
36
|
requirements:
|
30
|
-
- - ~>
|
37
|
+
- - "~>"
|
31
38
|
- !ruby/object:Gem::Version
|
32
|
-
version: 1.
|
39
|
+
version: '1.4'
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 1.4.6
|
33
43
|
type: :development
|
34
44
|
prerelease: false
|
35
|
-
version_requirements:
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '1.4'
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 1.4.6
|
36
53
|
- !ruby/object:Gem::Dependency
|
37
54
|
name: mocha
|
38
|
-
requirement:
|
39
|
-
none: false
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
40
56
|
requirements:
|
41
|
-
- - ~>
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '1.1'
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 1.1.0
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '1.1'
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 1.1.0
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: cucumber
|
75
|
+
requirement: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - "~>"
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '2.1'
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.1.0
|
83
|
+
type: :development
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '2.1'
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 2.1.0
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: aruba
|
95
|
+
requirement: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - "~>"
|
42
98
|
- !ruby/object:Gem::Version
|
43
99
|
version: 0.10.0
|
44
100
|
type: :development
|
45
101
|
prerelease: false
|
46
|
-
version_requirements:
|
102
|
+
version_requirements: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - "~>"
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: 0.10.0
|
107
|
+
- !ruby/object:Gem::Dependency
|
108
|
+
name: relish
|
109
|
+
requirement: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - "~>"
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: 0.7.1
|
114
|
+
type: :development
|
115
|
+
prerelease: false
|
116
|
+
version_requirements: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - "~>"
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: 0.7.1
|
47
121
|
- !ruby/object:Gem::Dependency
|
48
122
|
name: capybara
|
49
|
-
requirement:
|
50
|
-
|
123
|
+
requirement: !ruby/object:Gem::Requirement
|
124
|
+
requirements:
|
125
|
+
- - "~>"
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '2.5'
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: 2.5.0
|
131
|
+
type: :runtime
|
132
|
+
prerelease: false
|
133
|
+
version_requirements: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - "~>"
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '2.5'
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: 2.5.0
|
141
|
+
- !ruby/object:Gem::Dependency
|
142
|
+
name: selenium-webdriver
|
143
|
+
requirement: !ruby/object:Gem::Requirement
|
51
144
|
requirements:
|
52
|
-
- - ~>
|
145
|
+
- - "~>"
|
53
146
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
147
|
+
version: '2.48'
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: 2.48.1
|
55
151
|
type: :runtime
|
56
152
|
prerelease: false
|
57
|
-
version_requirements:
|
153
|
+
version_requirements: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - "~>"
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '2.48'
|
158
|
+
- - ">="
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: 2.48.1
|
58
161
|
- !ruby/object:Gem::Dependency
|
59
162
|
name: rake
|
60
|
-
requirement:
|
61
|
-
none: false
|
163
|
+
requirement: !ruby/object:Gem::Requirement
|
62
164
|
requirements:
|
63
|
-
- - ~>
|
165
|
+
- - "~>"
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '10.4'
|
168
|
+
- - ">="
|
64
169
|
- !ruby/object:Gem::Version
|
65
|
-
version:
|
170
|
+
version: 10.4.2
|
66
171
|
type: :runtime
|
67
172
|
prerelease: false
|
68
|
-
version_requirements:
|
173
|
+
version_requirements: !ruby/object:Gem::Requirement
|
174
|
+
requirements:
|
175
|
+
- - "~>"
|
176
|
+
- !ruby/object:Gem::Version
|
177
|
+
version: '10.4'
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: 10.4.2
|
69
181
|
- !ruby/object:Gem::Dependency
|
70
182
|
name: chunky_png
|
71
|
-
requirement:
|
72
|
-
none: false
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
73
184
|
requirements:
|
74
|
-
- - ~>
|
185
|
+
- - "~>"
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '1.3'
|
188
|
+
- - ">="
|
75
189
|
- !ruby/object:Gem::Version
|
76
|
-
version: 1.
|
190
|
+
version: 1.3.5
|
77
191
|
type: :runtime
|
78
192
|
prerelease: false
|
79
|
-
version_requirements:
|
193
|
+
version_requirements: !ruby/object:Gem::Requirement
|
194
|
+
requirements:
|
195
|
+
- - "~>"
|
196
|
+
- !ruby/object:Gem::Version
|
197
|
+
version: '1.3'
|
198
|
+
- - ">="
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
version: 1.3.5
|
80
201
|
description: Finds likely UI browser cross-compatibility issues.
|
81
202
|
email:
|
82
203
|
- carol.nichols@gmail.com
|
@@ -84,57 +205,66 @@ executables: []
|
|
84
205
|
extensions: []
|
85
206
|
extra_rdoc_files: []
|
86
207
|
files:
|
87
|
-
- .gitignore
|
88
|
-
- .
|
208
|
+
- ".gitignore"
|
209
|
+
- ".ruby-gemset"
|
210
|
+
- ".ruby-version"
|
211
|
+
- ".travis.yml"
|
89
212
|
- CHANGELOG.md
|
90
213
|
- Gemfile
|
91
214
|
- README.md
|
92
215
|
- Rakefile
|
93
216
|
- compatriot.gemspec
|
94
217
|
- examples/compatriot_tests.rb
|
218
|
+
- features/list_of_urls.feature
|
219
|
+
- features/step_definitions/cli_steps.rb
|
220
|
+
- features/support/env.rb
|
95
221
|
- lib/compatriot.rb
|
96
222
|
- lib/compatriot/browser.rb
|
97
|
-
- lib/compatriot/image_differ.rb
|
223
|
+
- lib/compatriot/image_differ/color_differ.rb
|
224
|
+
- lib/compatriot/image_differ/image_differ.rb
|
98
225
|
- lib/compatriot/results_presenter.rb
|
99
226
|
- lib/compatriot/runner.rb
|
100
227
|
- lib/compatriot/version.rb
|
101
|
-
- spec/integration/full_stack_spec.rb
|
102
228
|
- spec/sample_app/public/images/smileyface.jpg
|
103
|
-
- spec/sample_app/
|
229
|
+
- spec/sample_app/sample_app.rb
|
104
230
|
- spec/spec_helper.rb
|
105
231
|
- spec/unit/browser_spec.rb
|
106
|
-
- spec/unit/
|
232
|
+
- spec/unit/image_differ/color_differ_spec.rb
|
233
|
+
- spec/unit/image_differ/image_differ_spec.rb
|
107
234
|
- spec/unit/runner_spec.rb
|
108
235
|
homepage: https://github.com/clnclarinet/compatriot
|
109
|
-
licenses:
|
236
|
+
licenses:
|
237
|
+
- MIT
|
238
|
+
metadata: {}
|
110
239
|
post_install_message:
|
111
240
|
rdoc_options: []
|
112
241
|
require_paths:
|
113
242
|
- lib
|
114
243
|
required_ruby_version: !ruby/object:Gem::Requirement
|
115
|
-
none: false
|
116
244
|
requirements:
|
117
|
-
- -
|
245
|
+
- - ">="
|
118
246
|
- !ruby/object:Gem::Version
|
119
247
|
version: '0'
|
120
248
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
249
|
requirements:
|
123
|
-
- -
|
250
|
+
- - ">="
|
124
251
|
- !ruby/object:Gem::Version
|
125
252
|
version: '0'
|
126
253
|
requirements: []
|
127
254
|
rubyforge_project:
|
128
|
-
rubygems_version:
|
255
|
+
rubygems_version: 2.4.8
|
129
256
|
signing_key:
|
130
|
-
specification_version:
|
257
|
+
specification_version: 4
|
131
258
|
summary: Runs a command in multiple browsers using selenium then compares the screenshots
|
132
259
|
and presents those likely to have cross-browser incompatibilities.
|
133
260
|
test_files:
|
134
|
-
-
|
261
|
+
- features/list_of_urls.feature
|
262
|
+
- features/step_definitions/cli_steps.rb
|
263
|
+
- features/support/env.rb
|
135
264
|
- spec/sample_app/public/images/smileyface.jpg
|
136
|
-
- spec/sample_app/
|
265
|
+
- spec/sample_app/sample_app.rb
|
137
266
|
- spec/spec_helper.rb
|
138
267
|
- spec/unit/browser_spec.rb
|
139
|
-
- spec/unit/
|
268
|
+
- spec/unit/image_differ/color_differ_spec.rb
|
269
|
+
- spec/unit/image_differ/image_differ_spec.rb
|
140
270
|
- spec/unit/runner_spec.rb
|
data/.rvmrc
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
#!/usr/bin/env bash
|
2
|
-
|
3
|
-
# This is an RVM Project .rvmrc file, used to automatically load the ruby
|
4
|
-
# development environment upon cd'ing into the directory
|
5
|
-
|
6
|
-
# First we specify our desired <ruby>[@<gemset>], the @gemset name is optional.
|
7
|
-
environment_id="ruby-1.9.2@compatriot"
|
8
|
-
|
9
|
-
#
|
10
|
-
# First we attempt to load the desired environment directly from the environment
|
11
|
-
# file, this is very fast and efficicent compared to running through the entire
|
12
|
-
# CLI and selector. If you want feedback on which environment was used then
|
13
|
-
# insert the word 'use' after --create as this triggers verbose mode.
|
14
|
-
#
|
15
|
-
if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
|
16
|
-
&& -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]] ; then
|
17
|
-
\. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
|
18
|
-
else
|
19
|
-
# If the environment file has not yet been created, use the RVM CLI to select.
|
20
|
-
rvm --create "$environment_id"
|
21
|
-
fi
|
22
|
-
|
23
|
-
#
|
24
|
-
# If you use an RVM gemset file to install a list of gems (*.gems), you can have
|
25
|
-
# it be automatically loaded, uncomment the following and adjust the filename if
|
26
|
-
# necessary.
|
27
|
-
#
|
28
|
-
# filename=".gems"
|
29
|
-
# if [[ -s "$filename" ]] ; then
|
30
|
-
# rvm gemset import "$filename" | grep -v already | grep -v listed | grep -v complete | sed '/^$/d'
|
31
|
-
# fi
|
32
|
-
|
33
|
-
#
|
34
|
-
# If you use bundler and would like to run bundle each time you enter the
|
35
|
-
# directory you can uncomment the following code.
|
36
|
-
#
|
37
|
-
# # Ensure that Bundler is installed, install it if it is not.
|
38
|
-
# if ! command -v bundle ; then
|
39
|
-
# printf "The rubygem 'bundler' is not installed, installing it now.\n"
|
40
|
-
# gem install bundler
|
41
|
-
# fi
|
42
|
-
#
|
43
|
-
# # Bundle while redcing excess noise.
|
44
|
-
# printf "Bundling your gems this may take a few minutes on a fresh clone.\n"
|
45
|
-
# bundle | grep -v 'Using' | grep -v 'complete' | sed '/^$/d'
|
46
|
-
#
|
47
|
-
|
@@ -1,100 +0,0 @@
|
|
1
|
-
require 'chunky_png'
|
2
|
-
include ChunkyPNG::Color
|
3
|
-
|
4
|
-
module Compatriot
|
5
|
-
class ImageDiffer
|
6
|
-
|
7
|
-
attr_reader :diffs
|
8
|
-
|
9
|
-
def initialize(params = {})
|
10
|
-
@paths = params[:paths]
|
11
|
-
@browsers = params[:browsers]
|
12
|
-
@strategy = params[:strategy] || :color_difference
|
13
|
-
@diffs = {}
|
14
|
-
end
|
15
|
-
|
16
|
-
def compute!
|
17
|
-
@paths.map do |path|
|
18
|
-
images_to_diff = @browsers.map { |b| b.absolute_screenshot_for(path) }
|
19
|
-
@diffs[path] = diff(images_to_diff)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def diff(results)
|
24
|
-
images = results.map{|r| ChunkyPNG::Image.from_file(r) }
|
25
|
-
self.send(@strategy, images.first, images.last, results.first)
|
26
|
-
end
|
27
|
-
|
28
|
-
def same_pixels_exactly(image1, image2, name)
|
29
|
-
output = ChunkyPNG::Image.new(image1.width, image2.height, WHITE)
|
30
|
-
diff = []
|
31
|
-
|
32
|
-
each_pixel(image1) do |x, y|
|
33
|
-
pixel1 = image1[x, y]
|
34
|
-
pixel2 = image2[x, y]
|
35
|
-
output[x,y] = pixel1
|
36
|
-
diff << [x,y] unless pixel1 == pixel2
|
37
|
-
end
|
38
|
-
|
39
|
-
pixels_total = image1.pixels.length
|
40
|
-
pixels_changed = diff.length
|
41
|
-
pixels_changed_percentage = (diff.length.to_f / image1.pixels.length) * 100
|
42
|
-
|
43
|
-
x, y = diff.map{ |xy| xy[0] }, diff.map{ |xy| xy[1] }
|
44
|
-
|
45
|
-
output.rect(x.min, y.min, x.max, y.max, ChunkyPNG::Color.rgb(0,255,0))
|
46
|
-
filename = "#{name}-same_exactly.png"
|
47
|
-
output.save(filename)
|
48
|
-
File.join(
|
49
|
-
File.basename(File.dirname(filename)),
|
50
|
-
File.basename(filename)
|
51
|
-
)
|
52
|
-
end
|
53
|
-
|
54
|
-
def color_difference(image1, image2, name)
|
55
|
-
output = ChunkyPNG::Image.new(image1.width, image1.height, WHITE)
|
56
|
-
diff = []
|
57
|
-
|
58
|
-
each_pixel(image1) do |x, y|
|
59
|
-
pixel1 = image1[x,y]
|
60
|
-
pixel2 = image2[x,y]
|
61
|
-
unless pixel1 == pixel2
|
62
|
-
output[x,y], score = color_difference_of_pixels(pixel1, pixel2)
|
63
|
-
diff << score
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
filename = "#{name}-color_difference.png"
|
68
|
-
output.save(filename)
|
69
|
-
File.join(
|
70
|
-
File.basename(File.dirname(filename)),
|
71
|
-
File.basename(filename)
|
72
|
-
)
|
73
|
-
end
|
74
|
-
|
75
|
-
def color_difference_of_pixels(pixel1, pixel2)
|
76
|
-
score = Math.sqrt(
|
77
|
-
(r(pixel2) - r(pixel1)) ** 2 +
|
78
|
-
(g(pixel2) - g(pixel1)) ** 2 +
|
79
|
-
(b(pixel2) - b(pixel1)) ** 2
|
80
|
-
) / Math.sqrt(MAX ** 2 * 3)
|
81
|
-
|
82
|
-
[grayscale(MAX - (score * MAX).round), score]
|
83
|
-
end
|
84
|
-
|
85
|
-
# Not called anywhere
|
86
|
-
def color_difference_total_score
|
87
|
-
pixels_total = image1.width * image1.height
|
88
|
-
pixels_changed = diff.length
|
89
|
-
pixels_changed_percentage = (diff.inject {|sum, value| sum + value} / pixels_total) * 100
|
90
|
-
end
|
91
|
-
|
92
|
-
def each_pixel(image)
|
93
|
-
image.width.times do |x|
|
94
|
-
image.height.times do |y|
|
95
|
-
yield(x, y)
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
require_relative '../spec_helper'
|
2
|
-
require 'fileutils'
|
3
|
-
require 'date'
|
4
|
-
require 'nokogiri'
|
5
|
-
|
6
|
-
describe "Hit a list of paths for this app" do
|
7
|
-
it "takes screenshots, diffs them, and creates an index" do
|
8
|
-
root_dir = Dir.getwd
|
9
|
-
Dir.chdir(File.join(File.dirname(__FILE__), '..', 'sample_app'))
|
10
|
-
|
11
|
-
results_tmp_dir = File.join("tmp", "results")
|
12
|
-
|
13
|
-
FileUtils.remove_dir(results_tmp_dir, true)
|
14
|
-
|
15
|
-
Compatriot.app = TestApp
|
16
|
-
Compatriot.run(%w[
|
17
|
-
/
|
18
|
-
/chrome-css-bug
|
19
|
-
])
|
20
|
-
|
21
|
-
current_results_dir = (Dir.entries(results_tmp_dir) - [".", ".."]).first
|
22
|
-
current_results_dir = File.join(results_tmp_dir, current_results_dir)
|
23
|
-
|
24
|
-
firefox_dir = File.join(current_results_dir, "firefox")
|
25
|
-
chrome_dir = File.join(current_results_dir, "chrome")
|
26
|
-
|
27
|
-
Dir.glob(File.join(firefox_dir, "*.png")).size.must_equal 4
|
28
|
-
Dir.glob(File.join(chrome_dir, "*.png")).size.must_equal 2
|
29
|
-
|
30
|
-
results_index = IO.read(File.join(current_results_dir, "index.html"))
|
31
|
-
xml = Nokogiri::XML(results_index)
|
32
|
-
xml.xpath("//tr[td]").size.must_equal(2)
|
33
|
-
|
34
|
-
Dir.chdir(root_dir)
|
35
|
-
end
|
36
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
require_relative '../spec_helper'
|
2
|
-
|
3
|
-
describe Compatriot::ImageDiffer do
|
4
|
-
describe "compute!" do
|
5
|
-
it "diffs each set of images and stores the location by path" do
|
6
|
-
d = Compatriot::ImageDiffer.new(
|
7
|
-
:paths => ["/home"],
|
8
|
-
:browsers => [
|
9
|
-
stub(:absolute_screenshot_for => "1.png"),
|
10
|
-
stub(:absolute_screenshot_for => "2.png")
|
11
|
-
]
|
12
|
-
)
|
13
|
-
d.expects(:diff).with(["1.png", "2.png"]).returns("diff.png")
|
14
|
-
d.compute!
|
15
|
-
d.diffs["/home"].must_equal("diff.png")
|
16
|
-
end
|
17
|
-
end
|
18
|
-
describe "diff" do
|
19
|
-
it "calls chunky_png on each image path" do
|
20
|
-
file_one = stub
|
21
|
-
file_two = stub
|
22
|
-
|
23
|
-
ChunkyPNG::Image.expects(:from_file).with(file_one)
|
24
|
-
ChunkyPNG::Image.expects(:from_file).with(file_two)
|
25
|
-
|
26
|
-
c = Compatriot::ImageDiffer.new
|
27
|
-
c.stubs(:color_difference)
|
28
|
-
c.diff([file_one, file_two])
|
29
|
-
end
|
30
|
-
|
31
|
-
it "returns the filename of the diff" do
|
32
|
-
end
|
33
|
-
|
34
|
-
it "uses the strategy passed in" do
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
describe "self#color_difference" do
|
39
|
-
it "starts a new white image with the same dimensions" do
|
40
|
-
diff = stub_everything
|
41
|
-
ChunkyPNG::Image.expects(:new).with(
|
42
|
-
1,
|
43
|
-
2,
|
44
|
-
ChunkyPNG::Image::WHITE
|
45
|
-
).returns(diff)
|
46
|
-
|
47
|
-
image1 = stub_everything("1", :width => 1, :height => 2)
|
48
|
-
image2 = stub_everything("2", :width => 3, :height => 4)
|
49
|
-
|
50
|
-
Compatriot::ImageDiffer.new.color_difference(image1, image2, stub)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|