cezanne 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5722f440d0998e44a91a5bcaa8c7281d410c4f0c
4
- data.tar.gz: ebb5cd76d7c9d148d86e4c98c6888fba798fa0c9
3
+ metadata.gz: 48f5a265febb456ad0009ecb84e3694193f35102
4
+ data.tar.gz: b58c201977a549037e09bb46f5f7215469c93044
5
5
  SHA512:
6
- metadata.gz: 9d9cca0a8a7177adc4a561487e68cb431164ca17d22098f269f5c35ab9347ac512a0b1998d84751c3b5558396fc4e26faa53d860fbb9a5954a13d4c3825ec61d
7
- data.tar.gz: 46031a34b2013d200151972f515a4da07522cabc93ac8cc9c712f26555347eab5389f2476cd134e2ce45c26d1d2cf5f5c1506f54bcbb0322c47720e7aa6a65d8
6
+ metadata.gz: a3f03972e4a378d9b696b70cb358e7a7cf2c4cf2769e9cebebeac56e212b923fd1f31669578c554440f50fb67b49ead5cc3677d335874a43576629249b7468c7
7
+ data.tar.gz: cda92d1bf25ae8cccb9f62f121161d0ff030e8f0e7fcf4e95a77d950d18bc80b6734369870bf020428cd6beb8960b93a9606b6dfe8652550aa54c7623f09a718
data/.gitignore CHANGED
@@ -19,3 +19,4 @@ artifacts
19
19
  *.swp
20
20
  .DS_Store
21
21
  .env
22
+ .rspec
data/LICENSE ADDED
@@ -0,0 +1,30 @@
1
+ BSD License
2
+
3
+ For Cezanne software
4
+
5
+ Copyright (c) 2014, BSkyB. All rights reserved.
6
+
7
+ Redistribution and use in source and binary forms, with or without
8
+ modification, are permitted provided that the following conditions are met:
9
+
10
+ * Redistributions of source code must retain the above copyright notice, this
11
+ list of conditions and the following disclaimer.
12
+
13
+ * Redistributions in binary form must reproduce the above copyright notice,
14
+ this list of conditions and the following disclaimer in the documentation
15
+ and/or other materials provided with the distribution.
16
+
17
+ * Neither the name BSkyB nor the names of its contributors may be used to
18
+ endorse or promote products derived from this software without specific
19
+ prior written permission.
20
+
21
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
25
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![Build Status](https://travis-ci.org/bskyb-commerce/cezanne.svg?branch=master)](https://travis-ci.org/bskyb-commerce/cezanne)
1
+ [![Build Status](https://travis-ci.org/BSkyB/cezanne.svg?branch=master)](https://travis-ci.org/BSkyB/cezanne)
2
2
 
3
3
  # Cezanne
4
4
 
@@ -26,10 +26,14 @@ In your spec_helper.rb
26
26
 
27
27
  RSpec.configure do |config|
28
28
  config.include Cezanne
29
- config.cezanne = { uid: ENV['build_number'], project_name: 'awesome_app' }
30
29
  end
31
30
 
32
- The uid should be a unique identifier. We use the build number, but it can be a static string if you don't need
31
+ Cezanne.configure do |config|
32
+ config.uid = ENV['build_number']
33
+ config.project_name = 'awesome_app'
34
+ end
35
+
36
+ The should be a unique identifier. We use the build number, but it can be a static string if you don't need
33
37
  to keep multiple versions of the screenshots.
34
38
 
35
39
  In your tests
@@ -48,7 +52,7 @@ and the browser name & version, to make it easy to check visual regressions on m
48
52
 
49
53
  ## Dependencies
50
54
 
51
- Cezanne uses ImageMagick to compare images. Check with your package manager.
55
+ Cezanne uses ImageMagick. Check with your package manager.
52
56
 
53
57
  Screenshots are stored on Dropbox through the Dropscreen gem. Follow the instructions at https://github.com/bskyb-commerce/dropscreen and make sure to export the access_token
54
58
 
data/cezanne.gemspec CHANGED
@@ -27,4 +27,5 @@ Gem::Specification.new do |spec|
27
27
 
28
28
  spec.add_dependency "rmagick"
29
29
  spec.add_dependency "dropscreen"
30
+ spec.add_dependency "phashion"
30
31
  end
@@ -1,14 +1,11 @@
1
- require 'RMagick'
2
-
3
1
  module Cezanne
4
2
 
5
- SIMILARITY_THRESHOLD = 42
6
-
7
3
  def spot_differences_between this, that
8
4
  width = [this.width, that.width].min
9
5
  height = [this.height, that.height].min
10
6
  [this, that].each { |img| img.crop!(width, height) }
11
- this.picture.compare_channel(that.picture, Magick::PeakSignalToNoiseRatioMetric)[1] < SIMILARITY_THRESHOLD
7
+
8
+ not(this.duplicate? that)
12
9
  end
13
10
 
14
11
  end
@@ -0,0 +1,33 @@
1
+ module Cezanne
2
+
3
+ Config = Struct.new(:uid, :project_name, :local_root, :remote_root, :local_files, :remote_files, :comparison_method, :similarity_threshold)
4
+
5
+ def self.config
6
+ @config ||= Cezanne::Config.new
7
+ end
8
+
9
+
10
+ def self.configure
11
+ config = Cezanne.config
12
+
13
+ yield config if block_given?
14
+
15
+ config.comparison_method ||= :peak_signal_to_noise_ratio
16
+ config.similarity_threshold ||= (config.comparison_method.eql?(:peak_signal_to_noise_ratio) ? 42 : 15)
17
+ config.local_root ||= 'artifacts'
18
+ config.remote_root ||= config.project_name
19
+ config.local_files ||= Cezanne::LocalFiles.new(config.uid, config.local_root)
20
+ config.remote_files ||= Cezanne::RemoteFiles.new(config.uid, config.remote_root)
21
+ end
22
+
23
+ private
24
+
25
+ def local_files
26
+ Cezanne.config.local_files
27
+ end
28
+
29
+ def remote_files
30
+ Cezanne.config.remote_files
31
+ end
32
+
33
+ end
data/lib/cezanne/image.rb CHANGED
@@ -1,11 +1,12 @@
1
1
  require 'RMagick'
2
+ require 'phashion'
2
3
 
3
4
  module Cezanne
4
5
 
5
6
  class Image
6
7
  attr_reader :path, :picture
7
8
 
8
- def initialize path, opts
9
+ def initialize path, opts = {}
9
10
  @path = path
10
11
  @picture = Magick::Image.read(@path).first
11
12
  if opts[:crop]
@@ -27,6 +28,23 @@ module Cezanne
27
28
  def height
28
29
  @picture.rows
29
30
  end
30
- end
31
31
 
32
+ def duplicate? other
33
+ send(Cezanne.config.comparison_method, other)
34
+ end
35
+
36
+ alias_method :==, :duplicate?
37
+
38
+ private
39
+
40
+ def peak_signal_to_noise_ratio other
41
+ @picture.compare_channel(other.picture, Magick::PeakSignalToNoiseRatioMetric)[1] > Cezanne.config.similarity_threshold
42
+ end
43
+
44
+ def phash_hamming_distance other
45
+ Phashion::Image.new(@path).duplicate? Phashion::Image.new(other.path), threshold: Cezanne.config.similarity_threshold
46
+ end
47
+
48
+ end
49
+
32
50
  end
@@ -22,6 +22,10 @@ module Cezanne
22
22
  @adapter.push path, @remote_folders[key]
23
23
  end
24
24
 
25
+ def exists? key
26
+ @adapter.exists? @remote_folders[key]
27
+ end
28
+
25
29
  end
26
30
 
27
31
  end
data/lib/cezanne/rspec.rb CHANGED
@@ -3,41 +3,23 @@ require 'rspec/core'
3
3
 
4
4
  RSpec.configure do |config|
5
5
 
6
- config.add_setting :cezanne
7
-
8
6
  config.before(:all, screenshots: true) do
9
7
  if self.class.include?(Cezanne)
10
- uid = config.cezanne[:uid]
11
- project_name = config.cezanne[:project_name]
12
- config.cezanne[:local_files] = Cezanne::LocalFiles.new(uid, 'artifacts')
13
- config.cezanne[:remote_files] = Cezanne::RemoteFiles.new(uid, project_name)
14
- begin
15
- config.cezanne[:remote_files].pull(:ref, config.cezanne[:local_files].path_for(:ref))
16
- rescue
17
- puts "no reference screenshot exist for project #{project_name}"
18
- end
8
+ if Cezanne.config.remote_files.exists? :ref
9
+ Cezanne.config.remote_files.pull(:ref, Cezanne.config.local_files.path_for(:ref))
10
+ else
11
+ Cezanne.config.remote_files.push(Cezanne.config.local_files.path_for(:ref), :ref)
12
+ end
19
13
  end
20
14
  end
21
15
 
22
16
  config.after(:all, screenshots: true) do
23
17
  if self.class.include?(Cezanne)
24
18
  [:new, :diff].each do |key|
25
- config.cezanne[:remote_files].push(config.cezanne[:local_files].path_for(key), key)
19
+ Cezanne.config.remote_files.push(Cezanne.config.local_files.path_for(key), key) unless Dir.glob(Cezanne.config.local_files.path_for(key)).empty?
26
20
  end
27
- config.cezanne[:local_files].clean
21
+ Cezanne.config.local_files.clean
28
22
  end
29
23
  end
30
24
 
31
25
  end
32
-
33
- module Cezanne
34
-
35
- def local_files
36
- RSpec.configuration.cezanne[:local_files]
37
- end
38
-
39
- def remote_files
40
- RSpec.configuration.cezanne[:remote_files]
41
- end
42
-
43
- end
@@ -1,3 +1,3 @@
1
1
  module Cezanne
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/cezanne.rb CHANGED
@@ -1,10 +1,12 @@
1
1
  require "cezanne/version"
2
+ require "cezanne/config"
2
3
  require "cezanne/local_files"
3
4
  require "cezanne/remote_files"
4
5
  require "cezanne/image"
5
6
  require "cezanne/comparison"
6
7
 
7
8
  module Cezanne
9
+
8
10
 
9
11
  def check_visual_regression_for page_name, opts = {}
10
12
  screenshot = take_screenshot page_name, opts
@@ -25,7 +27,7 @@ module Cezanne
25
27
 
26
28
  private
27
29
 
28
- def take_screenshot page_name, opts
30
+ def take_screenshot page_name, opts = {}
29
31
  path = File.join( local_files.path_for(:tmp), file_name_for(page_name) )
30
32
  page.driver.browser.save_screenshot(path)
31
33
  image(path, opts)
@@ -71,5 +71,15 @@ describe Cezanne::RemoteFiles do
71
71
  end
72
72
  end
73
73
 
74
+ describe '#exists?' do
75
+
76
+ it 'is a proxy to Dropscreen::Client#exists?' do
77
+ expect(dropscreen_client).to receive(:exists?).at_least(1).times.with(kind_of(String))
78
+ [:ref, :diff, :new].each do |key|
79
+ @remote_files.exists? key
80
+ end
81
+ end
82
+
83
+ end
74
84
  end
75
85
 
@@ -4,6 +4,7 @@ describe Cezanne::Image do
4
4
 
5
5
  let(:image) { Cezanne::Image.new('spec/images/page_name_browser_version.gif', {}) }
6
6
 
7
+
7
8
  describe '#initialize' do
8
9
 
9
10
  it 'wraps Magick::Image' do
@@ -11,14 +12,14 @@ describe Cezanne::Image do
11
12
  end
12
13
 
13
14
  it 'return an error if there is no file at path' do
14
- expect { Cezanne::Image.new('unexistent_file_path') }.to raise_error
15
+ expect { Cezanne::Image.new('inexistent_file_path') }.to raise_error
15
16
  end
16
17
  end
17
18
 
18
19
  describe '#width' do
19
20
 
20
21
  it 'has a width' do
21
- expect(image.width).to be 763
22
+ expect(image.width).to be 712
22
23
  end
23
24
 
24
25
  end
@@ -33,14 +34,18 @@ describe Cezanne::Image do
33
34
 
34
35
  describe '#crop!' do
35
36
 
37
+ before(:each) do
38
+ FileUtils.cp('spec/images/page_name_browser_version.gif', 'spec/images/page_name_browser_version.bak')
39
+ end
40
+
36
41
  it 'accepts 4 parameters x, y, width, height' do
37
42
  x = 1
38
43
  y = 2
39
44
  width = 5
40
45
  height = 10
41
46
  image.crop!(x,y,width,height)
42
- expect(image.width).to be 4
43
- expect(image.height).to be 8
47
+ expect(image.width).to be 5
48
+ expect(image.height).to be 10
44
49
  end
45
50
 
46
51
  it 'accepts width and height alone' do
@@ -51,5 +56,44 @@ describe Cezanne::Image do
51
56
  expect(image.height).to be 5
52
57
  end
53
58
 
59
+ it 'write the cropped image to disk' do
60
+ expect(image.picture).to receive(:write)
61
+ image.crop!(10,10)
62
+ end
63
+
64
+ after(:each) do
65
+ FileUtils.mv('spec/images/page_name_browser_version.bak', 'spec/images/page_name_browser_version.gif', force: true)
66
+ end
67
+
68
+ end
69
+
70
+ describe '#duplicate?' do
71
+ let(:other_image) { double('Cezanne::Image') }
72
+
73
+ it 'compare two images' do
74
+ Cezanne.config.comparison_method = :comparison_method
75
+ allow(image).to receive(:comparison_method)
76
+ expect(image).to receive(:comparison_method).with(other_image)
77
+ image.duplicate? other_image
78
+ end
79
+
80
+ it 'can use peak signal to noise ratio' do
81
+ Cezanne.config.comparison_method = :peak_signal_to_noise_ratio
82
+ Cezanne.config.similarity_threshold = 42
83
+
84
+ allow(other_image).to receive(:picture)
85
+ expect(image.picture).to receive(:compare_channel).with(other_image.picture, Magick::PeakSignalToNoiseRatioMetric).and_return([nil, 10])
86
+ image.duplicate? other_image
87
+ end
88
+
89
+ it 'can use phash hamming distance' do
90
+ Cezanne.config.comparison_method = :phash_hamming_distance
91
+ Cezanne.config.similarity_threshold = 15
92
+
93
+ allow(other_image).to receive(:path)
94
+ expect_any_instance_of(Phashion::Image).to receive(:duplicate?)
95
+ image.duplicate? other_image
96
+ end
97
+
54
98
  end
55
99
  end
@@ -1,100 +1,131 @@
1
1
  require 'cezanne/rspec'
2
2
  require 'capybara/rspec'
3
3
  require 'selenium-webdriver'
4
- require 'pry'
5
-
6
4
 
7
5
  Capybara.app = Rack::Directory.new('spec/images')
8
6
  Capybara.default_driver = :selenium
9
7
 
10
8
  RSpec.configure do |config|
11
9
  config.include Cezanne
12
- config.cezanne = { uid: 'test', project_name: 'cezanne' }
13
10
  end
14
11
 
15
- describe 'Cezanne RSpec integration', type: :feature, screenshots: true, integration: true do
16
-
17
- # wrap each test with before(:all) and after(:all)
18
12
 
19
- after(:all) do |example|
20
- RSpec.configuration.after(:all, screenshots: true).last.instance_variable_set(:@block, Proc.new {}) # disable the after(:all) hook
21
- end
13
+ describe 'Cezanne RSpec integration', type: :feature, integration: true do
22
14
 
23
- before(:each) do |example|
24
- RSpec.configuration.before(:all, screenshots: true).first.run(example)
15
+ before(:all) do
16
+ Cezanne.configure do |config|
17
+ config.uid = 'test'
18
+ config.project_name = 'cezanne'
19
+ end
25
20
  end
26
21
 
27
- after(:each) do |example|
28
- RSpec.configuration.after(:all, screenshots: true).last.run(example) unless example.metadata[:after_hook_test]
29
- end
22
+ context('Screenshot tests', screenshots: true) do
23
+
24
+ after(:all) do |example|
25
+ RSpec.configuration.after(:all, screenshots: true).last.instance_variable_set(:@block, Proc.new {}) # disable the after(:all) hook
26
+ Cezanne.config.local_files.clean
27
+ end
28
+
29
+ before(:each) do |example|
30
+ RSpec.configuration.before(:all, screenshots: true).first.run(example) unless example.metadata[:before_hook_test]
31
+ end
30
32
 
33
+ after(:each) do |example|
34
+ RSpec.configuration.after(:all, screenshots: true).last.run(example) unless example.metadata[:after_hook_test]
35
+ # the after(:all) hook that we just called will clean the local folders, so we need to recreate them so next test will find them
36
+ Cezanne.config.local_files = Cezanne::LocalFiles.new(Cezanne.config.uid, Cezanne.config.local_root)
37
+ end
31
38
 
39
+ describe 'initialization' do
40
+
41
+ it 'create local folders' do
42
+ expect(File.exist?('artifacts/reference_screenshots')).to be true
43
+ expect(File.exist?('artifacts/test/tmp_screenshots')).to be true
44
+ expect(File.exist?('artifacts/test/different_screenshots')).to be true
45
+ expect(File.exist?('artifacts/test/new_screenshots')).to be true
46
+ end
47
+
32
48
 
49
+ it 'pull reference_screenshots' do
50
+ expect(File.exist?('artifacts/reference_screenshots/similar_firefox_34.0.5.gif')).to be true
51
+ expect(File.exist?('artifacts/reference_screenshots/different_firefox_34.0.5.gif')).to be true
52
+ end
53
+
54
+ it 'create the remote reference folder if it does not exist', before_hook_test: true do |example|
55
+ allow(Cezanne.config.remote_files).to receive(:exists?).and_return(false)
56
+ allow(Cezanne.config.remote_files).to receive(:push)
57
+ expect(Cezanne.config.remote_files).to receive(:push).with(Cezanne.config.local_files.path_for(:ref), :ref);
58
+ RSpec.configuration.before(:all, screenshots: true).first.run(example)
59
+ end
60
+ end
61
+
62
+ describe 'take screenshots' do
33
63
 
64
+ {phash_hamming_distance: 'phash hamming distance', peak_signal_to_noise_ratio: 'peak signal to noise ratio'}.each do |key, value|
65
+
66
+ context value do
67
+
68
+ before(:all) do
69
+ Cezanne.config.similarity_threshold = nil
70
+ Cezanne.configure do |config|
71
+ config.comparison_method = key
72
+ end
73
+ end
34
74
 
75
+ context 'similar' do
35
76
 
36
- describe 'initialization' do
37
-
38
- it 'create local folders' do
39
- expect(File.exist?('artifacts/reference_screenshots')).to be true
40
- expect(File.exist?('artifacts/test/tmp_screenshots')).to be true
41
- expect(File.exist?('artifacts/test/different_screenshots')).to be true
42
- expect(File.exist?('artifacts/test/new_screenshots')).to be true
43
- end
44
-
77
+ it 'pass the test' do
78
+ visit '/similar.html'
79
+ expect { check_visual_regression_for 'similar' }.not_to raise_error
80
+ end
45
81
 
46
- it 'pull reference_screenshots' do
47
- expect(File.exist?('artifacts/reference_screenshots/similar_firefox_31.0.gif')).to be true
48
- expect(File.exist?('artifacts/reference_screenshots/different_firefox_31.0.gif')).to be true
49
- end
50
-
51
- end
52
-
53
- describe 'take screenshots' do
82
+ end
83
+
84
+ context 'different' do
54
85
 
55
- context 'similar' do
86
+ it 'fail the test' do
87
+ visit '/different.html'
88
+ expect { check_visual_regression_for 'different' }.to raise_error
89
+ end
56
90
 
57
- it 'pass the test' do
58
- visit '/similar.html'
59
- expect { check_visual_regression_for 'similar' }.not_to raise_error
60
- end
91
+ end
61
92
 
62
- end
63
-
64
- context 'different' do
93
+
94
+ context 'new' do
65
95
 
66
- it 'fail the test' do
67
- visit '/different.html'
68
- expect { check_visual_regression_for 'different' }.to raise_error
69
- end
96
+ it 'fail the test' do
97
+ visit '/new.html'
98
+ expect { check_visual_regression_for 'new' }.to raise_error
99
+ end
70
100
 
71
- end
101
+ end
102
+
103
+ end
72
104
 
105
+ end
73
106
 
74
- context 'new' do
107
+ end
75
108
 
76
- it 'fail the test' do
77
- visit '/new.html'
78
- expect { check_visual_regression_for 'new' }.to raise_error
109
+ describe 'finalization', after_hook_test: true do
110
+
111
+ it 'push new, diff screenshots to remote' do |example|
112
+ expect(Cezanne.config.remote_files).to receive(:push).with(kind_of(String), :diff).and_call_original
113
+ expect(Cezanne.config.remote_files).to receive(:push).with(kind_of(String), :new).and_call_original
114
+ RSpec.configuration.after(:all, screenshots: true).last.run(example)
79
115
  end
80
116
 
81
- end
82
-
83
- end
117
+ it 'does not push empty folders' do
118
+ allow(Dir).to receive(:glob).and_return([])
119
+ expect(Cezanne.config.remote_files).not_to receive(:push)
120
+ end
84
121
 
85
- describe 'finalization', after_hook_test: true do
86
-
87
- it 'push new, diff screenshots to remote' do |example|
88
- expect(RSpec.configuration.cezanne[:remote_files]).to receive('push').with(kind_of(String), :diff).and_call_original
89
- expect(RSpec.configuration.cezanne[:remote_files]).to receive('push').with(kind_of(String), :new).and_call_original
90
- RSpec.configuration.after(:all, screenshots: true).last.run(example)
91
- end
92
122
 
93
- it 'clean local folders' do |example|
94
- RSpec.configuration.after(:all, screenshots: true).last.run(example)
95
- expect(File.exists?('artifacts')).to be false
123
+ it 'clean local folders' do |example|
124
+ RSpec.configuration.after(:all, screenshots: true).last.run(example)
125
+ expect(File.exists?('artifacts')).to be false
126
+ end
127
+
96
128
  end
97
129
 
98
130
  end
99
-
100
- end
131
+ end
data/spec/cezanne_spec.rb CHANGED
@@ -2,7 +2,16 @@ require 'spec_helper'
2
2
 
3
3
  describe Cezanne do
4
4
 
5
- let(:class_with_cezanne) { Class.include(Cezanne).new }
5
+ let(:class_with_cezanne) {
6
+ Cezanne.configure do |config|
7
+ config.uid = 'test'
8
+ config.project_name = 'cezanne'
9
+ config.local_files = 'mock'
10
+ config.remote_files = 'mock'
11
+ end
12
+ Class.include(Cezanne).new
13
+ }
14
+
6
15
  # Capybara mocks
7
16
  let(:page) { double('page') }
8
17
  let(:driver) { double('driver') }
@@ -27,6 +36,45 @@ describe Cezanne do
27
36
  allow(class_with_cezanne).to receive('image').and_return(image)
28
37
  end
29
38
 
39
+ describe '#configure' do
40
+
41
+ it 'can be configured with a block' do
42
+
43
+ Cezanne.configure do |config|
44
+ config.uid = 'uid'
45
+ config.project_name = 'project_name'
46
+ config.local_root = 'local_root'
47
+ config.remote_root = 'remote_root'
48
+ config.local_files = 'local_files'
49
+ config.remote_files = 'remote_files'
50
+ config.comparison_method = 'comparison_method'
51
+ config.similarity_threshold = 'similarity_threshold'
52
+ end
53
+
54
+ expected_config = Cezanne::Config.new('uid', 'project_name', 'local_root', 'remote_root', 'local_files', 'remote_files', 'comparison_method', 'similarity_threshold')
55
+
56
+ expect(Cezanne.config).to eq(expected_config)
57
+ end
58
+
59
+ it 'local_files helper' do
60
+
61
+ Cezanne.configure do |config|
62
+ config.local_files = 'local_files'
63
+ end
64
+
65
+ expect(Class.include(Cezanne).new.send(:local_files)).to eq 'local_files'
66
+ end
67
+
68
+ it 'remote_files helper' do
69
+
70
+ Cezanne.configure do |config|
71
+ config.remote_files = 'remote_files'
72
+ end
73
+
74
+ expect(Class.include(Cezanne).new.send(:remote_files)).to eq 'remote_files'
75
+ end
76
+ end
77
+
30
78
  describe '#take_screenshot' do
31
79
 
32
80
  it 'take a screenshot using the browser driver' do
@@ -58,9 +106,9 @@ describe Cezanne do
58
106
  let(:that) { this.clone }
59
107
 
60
108
  before(:each) do
61
- allow(image).to receive('picture').and_return(picture)
109
+ allow(image).to receive('duplicate?')
62
110
  allow(image).to receive('crop!')
63
- allow(picture).to receive('compare_channel').with(picture, Magick::PeakSignalToNoiseRatioMetric).and_return([nil, 1])
111
+ allow(picture).to receive('duplicate?').with(picture).and_return(true)
64
112
  allow(this).to receive('width').and_return(1)
65
113
  allow(this).to receive('height').and_return(2)
66
114
  allow(that).to receive('width').and_return(2)
@@ -76,7 +124,7 @@ describe Cezanne do
76
124
  context 'similar images' do
77
125
 
78
126
  it 'return false' do
79
- expect(this.picture).to receive('compare_channel').and_return([nil, Cezanne::SIMILARITY_THRESHOLD + 1])
127
+ expect(this).to receive('duplicate?').and_return(true)
80
128
  expect(class_with_cezanne.send(:spot_differences_between, this, that)).to be false
81
129
  end
82
130
 
@@ -85,7 +133,7 @@ describe Cezanne do
85
133
  context 'different images' do
86
134
 
87
135
  it 'return true' do
88
- expect(this.picture).to receive('compare_channel').and_return([nil, Cezanne::SIMILARITY_THRESHOLD - 1])
136
+ expect(this).to receive('duplicate?').and_return(false)
89
137
  expect(class_with_cezanne.send(:spot_differences_between, this, that)).to be true
90
138
  end
91
139
 
@@ -158,6 +206,11 @@ describe Cezanne do
158
206
 
159
207
  before(:each) do
160
208
  allow(class_with_cezanne).to receive('get_reference_screenshot_for').and_return(Cezanne::Image.new('spec/images/page_name_browser_version.gif'))
209
+
210
+ Cezanne.configure do |config|
211
+ config.comparison_method = :peak_signal_to_noise_ratio
212
+ config.similarity_threshold = 42
213
+ end
161
214
  end
162
215
 
163
216
  context 'succesful match' do
@@ -214,5 +267,17 @@ describe Cezanne do
214
267
  end
215
268
 
216
269
  end
270
+
271
+ context 'accepts options' do
272
+
273
+ it 'let you specify a rectangle to crop' do
274
+ opts = { crop: [0,0,10,10]}
275
+ allow(class_with_cezanne).to receive(:spot_differences_between).and_return(false)
276
+ expect(class_with_cezanne).to receive(:take_screenshot).with(anything, opts).and_call_original
277
+ expect(class_with_cezanne).to receive(:image).with(anything, opts)
278
+ class_with_cezanne.check_visual_regression_for('page_name', opts)
279
+ end
280
+
281
+ end
217
282
  end
218
283
  end
@@ -4,6 +4,6 @@
4
4
  <title>DIFFERENT</title>
5
5
  </head>
6
6
  <body>
7
- <img src="page_name_browser_version.gif" />
7
+ <img src="page_name_browser_version.gif" style="transform: rotate(180deg);" />
8
8
  </body>
9
9
  </html>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cezanne
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sky Haiku
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-18 00:00:00.000000000 Z
11
+ date: 2015-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: phashion
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
125
139
  description: Let Cezanne help you make sure your views look alright
126
140
  email:
127
141
  - skyhaikuteam@gmail.com
@@ -132,12 +146,13 @@ files:
132
146
  - ".gitignore"
133
147
  - ".travis.yml"
134
148
  - Gemfile
135
- - LICENSE.txt
149
+ - LICENSE
136
150
  - README.md
137
151
  - Rakefile
138
152
  - cezanne.gemspec
139
153
  - lib/cezanne.rb
140
154
  - lib/cezanne/comparison.rb
155
+ - lib/cezanne/config.rb
141
156
  - lib/cezanne/image.rb
142
157
  - lib/cezanne/local_files.rb
143
158
  - lib/cezanne/remote_files.rb
data/LICENSE.txt DELETED
@@ -1,22 +0,0 @@
1
- Copyright (c) 2014 Andrea Pigato
2
-
3
- MIT License
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
12
-
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
15
-
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.