cezanne 0.0.3 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.