capybara-screenshot-diff 0.1.0 → 0.2.1

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: 3c7078265d4d0fc01429989f9b8d67a60773ccab
4
- data.tar.gz: 0bee455268a6e5ecf65549a22ff35c85c5b56327
3
+ metadata.gz: d8c517212dfc9af8af735a354862dcaba9adc96a
4
+ data.tar.gz: 7828ae0bfa1c9aea2e8814288989288c43c8f64e
5
5
  SHA512:
6
- metadata.gz: 9003b9fb66fa3e2206ee771d288963d26a85a2bb26b0d643dc357b5647e5b5915083b44e547daf6e2cafa4aba5791853b9496c8dce3a79372214da1a50a13343
7
- data.tar.gz: 8fcfca1b48a99fa3b14b8b1270d48af12ecd1dc9f30ffc002c0fdaaff79fdfb728cb3e6516fb2724aec7ca921ede6dc00a9165607c2d4f7e024776f446423aec
6
+ metadata.gz: 27179f167cc8d6b77850033dd0e5291ae89e7dd4182586e22269a66619fca6e02d891e257c6c7041e51adb13a4b7097e8017e7c6e543ef7f11a6cf02fefef2e9
7
+ data.tar.gz: be58b147f1948e3136975f1320caa8cbfeeca7d5e5f27651bd8736fe31da35384d950165e8b560c0fdc4b2fe1975e382511ac565cc9f8314a2145982c11d3de0
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ *~
1
2
  /.bundle/
2
3
  /.yardoc
3
4
  /Gemfile.lock
@@ -1,8 +1,28 @@
1
1
  inherit_from: .rubocop_todo.yml
2
2
 
3
+ AllCops:
4
+ DisplayCopNames: true
5
+ DisplayStyleGuide: true
6
+
7
+ Lint/Debugger:
8
+ Enabled: false
9
+
10
+ Metrics/ClassLength:
11
+ Max: 101
12
+
13
+ Metrics/LineLength:
14
+ Max: 110
15
+
3
16
  Style/MultilineMethodCallIndentation:
4
17
  EnforcedStyle: indented
5
18
  IndentationWidth: 4
6
19
 
20
+ Style/NumericPredicate:
21
+ Enabled: false
22
+
7
23
  Style/SignalException:
8
24
  EnforcedStyle: semantic
25
+
26
+ Style/AlignParameters:
27
+ EnforcedStyle: with_fixed_indentation
28
+ IndentationWidth: 4
@@ -0,0 +1,79 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2016-04-22 14:35:36 +0200 using RuboCop version 0.39.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ Style/TrivialAccessors:
10
+ Enabled: false
11
+
12
+ # Offense count: 2
13
+ Lint/AmbiguousRegexpLiteral:
14
+ Exclude:
15
+ - 'lib/capybara/screenshot/diff/capybara_setup.rb'
16
+
17
+ # Offense count: 3
18
+ Metrics/AbcSize:
19
+ Max: 55
20
+
21
+ # Offense count: 1
22
+ Metrics/CyclomaticComplexity:
23
+ Max: 15
24
+
25
+ # Offense count: 3
26
+ # Configuration parameters: CountComments.
27
+ Metrics/MethodLength:
28
+ Max: 42
29
+
30
+ # Offense count: 1
31
+ # Configuration parameters: CountKeywordArgs.
32
+ Metrics/ParameterLists:
33
+ Max: 6
34
+
35
+ # Offense count: 1
36
+ Metrics/PerceivedComplexity:
37
+ Max: 17
38
+
39
+ # Offense count: 1
40
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
41
+ # SupportedStyles: nested, compact
42
+ Style/ClassAndModuleChildren:
43
+ Exclude:
44
+ - 'lib/capybara/screenshot/diff/capybara_setup.rb'
45
+
46
+ # Offense count: 2
47
+ Style/Documentation:
48
+ Exclude:
49
+ - 'spec/**/*'
50
+ - 'test/**/*'
51
+ - 'lib/capybara/screenshot/diff.rb'
52
+ - 'lib/capybara/screenshot/diff/image_compare.rb'
53
+
54
+ # Offense count: 1
55
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
56
+ # SupportedStyles: format, sprintf, percent
57
+ Style/FormatString:
58
+ Exclude:
59
+ - 'lib/capybara/screenshot/diff/capybara_setup.rb'
60
+
61
+ # Offense count: 1
62
+ # Configuration parameters: MinBodyLength.
63
+ Style/GuardClause:
64
+ Exclude:
65
+ - 'capybara-screenshot-diff.gemspec'
66
+
67
+ # Offense count: 1
68
+ # Cop supports --auto-correct.
69
+ # Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
70
+ # SupportedStyles: aligned, indented
71
+ Style/MultilineMethodCallIndentation:
72
+ Enabled: false
73
+
74
+ # Offense count: 1
75
+ # Cop supports --auto-correct.
76
+ # Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
77
+ # SupportedStyles: aligned, indented
78
+ Style/MultilineOperationIndentation:
79
+ Enabled: false
@@ -1,10 +1,16 @@
1
1
  language: ruby
2
2
  rvm:
3
- - jruby-9.0.4.0
4
- - jruby-9.0.5.0
5
3
  - jruby-head
4
+ - jruby-9.1.2.0
5
+ - jruby-9.1.5.0
6
+ - 2.3.1
7
+ - 2.2.5
6
8
  - 2.1.8
7
- - 2.2.4
8
- - 2.3.0
9
9
  - ruby-head
10
- before_install: gem install bundler -v 1.11.2
10
+ before_install: gem query -i -n ^bundler$ >/dev/null || gem install bundler
11
+
12
+ env:
13
+ - JRUBY_OPTS="--dev --debug"
14
+
15
+ jdk:
16
+ - oraclejdk8
data/README.md CHANGED
@@ -1,11 +1,13 @@
1
+ [![Build Status](https://travis-ci.org/donv/capybara-screenshot-diff.svg?branch=master)](https://travis-ci.org/donv/capybara-screenshot-diff)
2
+
1
3
  # Capybara::Screenshot::Diff
2
4
 
3
5
  Ever wondered what your project looked like two years ago? To answer that, you
4
6
  start taking screen shots during your tests. Capybara provides the
5
7
  `save_screenshot` method for this. Very good.
6
8
 
7
- Ever introduced a graphical chnage unintended? Never want it to happen again?
8
- Then this gem is gfor you! Use this gem to detect changes in your pages by
9
+ Ever introduced a graphical change unintended? Never want it to happen again?
10
+ Then this gem is for you! Use this gem to detect changes in your pages by
9
11
  taking screen shots and comparing them to the previous revision.
10
12
 
11
13
  ## Installation
@@ -84,6 +86,44 @@ doc
84
86
  02-action_performed
85
87
  ```
86
88
 
89
+ **All files in the screenshot group directory will be deleted when
90
+ `screenshot_group` is called.**
91
+
92
+
93
+ #### Screenshot sections
94
+
95
+ You can introduce another level above the screenshot group called a
96
+ `screenshot_section`. The section name is inserted just before the group name
97
+ in the save path. If called in the setup of the test, all screenshots in
98
+ that test will get the same prefix:
99
+
100
+ ```ruby
101
+ setup do
102
+ screenshot_section 'my_feature'
103
+ end
104
+ test 'my subfeature' do
105
+ screenshot_group 'subfeature'
106
+ visit '/feature'
107
+ click_button 'Interresting button'
108
+ screenshot 'subfeature_index'
109
+ click_button 'Perform action'
110
+ screenshot 'action_performed'
111
+ end
112
+ ```
113
+
114
+ This will produce a sequence of images like this
115
+
116
+ ```
117
+ doc
118
+ screenshots
119
+ my_feature
120
+ subfeature
121
+ 00-subfeature_index
122
+ 01-action_performed
123
+ ```
124
+
125
+
126
+
87
127
  ### Multiple Capybara drivers
88
128
 
89
129
  Often it is useful to test your app using different browsers. To avoid the
@@ -189,12 +229,25 @@ If you would like the screen shots to be saved in a different location set
189
229
  Capybara::Screenshot.save_path = "#{Rails.root}/doc/gui"
190
230
  ```
191
231
 
232
+ ### Screen shot stability
233
+
234
+ To ensure that animations are finished before saving a screen shot, you can add
235
+ a stability time limit. If the stability time limit is set, a second screen
236
+ shot will be taken and compared to the first. This is repeated until two
237
+ subsequent screen shots are identical.
238
+
239
+ ```ruby
240
+ Capybara::Screenshot.stability_time_limit = 0.5
241
+ ```
242
+
192
243
 
193
244
  ## Development
194
245
 
195
246
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
196
247
 
197
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
248
+ To install this gem onto your local machine, run `bundle exec rake install`.
249
+
250
+ To release a new version, update the version number in `lib/capybara/screenshot/diff/version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
198
251
 
199
252
  ## Contributing
200
253
 
data/Rakefile CHANGED
@@ -12,4 +12,4 @@ end
12
12
 
13
13
  RuboCop::RakeTask.new
14
14
 
15
- Rake::Task[:test].enhance [:rubocop]
15
+ Rake::Task[:test].enhance [:'rubocop:auto_correct']
@@ -8,31 +8,24 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Capybara::Screenshot::Diff::VERSION
9
9
  spec.authors = ['Uwe Kubosch']
10
10
  spec.email = ['uwe@kubosch.no']
11
-
12
11
  spec.summary = 'Track your GUI changes with diff assertions'
13
12
  spec.description = 'Save screen shots and track changes with graphical diff'
14
13
  spec.homepage = 'https://github.com/donv/capybara-screenshot-diff'
15
14
  spec.license = 'MIT'
16
-
17
- # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
18
- # delete this section to allow pushing this gem to any host.
19
- if spec.respond_to?(:metadata)
20
- spec.metadata['allowed_push_host'] = 'https://rubygems.org/'
21
- else
22
- fail 'RubyGems 2.0 or newer is required to protect against public gem push.'
23
- end
24
-
25
- spec.files = `git ls-files -z`.split("\x0")
26
- .reject { |f| f.match(%r{^(test|spec|features)/}) }
15
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org/'
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
17
  spec.bindir = 'exe'
28
18
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
19
  spec.require_paths = ['lib']
30
20
 
21
+ spec.add_runtime_dependency 'actionpack', '~> 4.1'
31
22
  spec.add_runtime_dependency 'capybara', '~> 2.0'
23
+ spec.add_runtime_dependency 'chunky_png', '~> 1.3'
32
24
 
33
25
  spec.add_development_dependency 'bundler', '~> 1.11'
34
- spec.add_development_dependency 'rake', '~> 10.0'
35
26
  spec.add_development_dependency 'minitest', '~> 5.0'
36
27
  spec.add_development_dependency 'minitest-reporters'
28
+ spec.add_development_dependency 'rake', '~> 10.0'
37
29
  spec.add_development_dependency 'rubocop', '~> 0.39'
30
+ spec.add_development_dependency 'simplecov', '~> 0.11'
38
31
  end
@@ -4,10 +4,16 @@ require 'capybara/screenshot/diff/capybara_setup'
4
4
 
5
5
  module Capybara
6
6
  module Screenshot
7
- mattr_accessor :enabled
8
- mattr_accessor :window_size
9
7
  mattr_accessor :add_driver_path
10
8
  mattr_accessor :add_os_path
9
+ mattr_accessor :enabled
10
+ mattr_accessor :screenshot_root
11
+ mattr_accessor :stability_time_limit
12
+ mattr_accessor :window_size
13
+
14
+ def self.active?
15
+ enabled || (enabled.nil? && Diff.enabled)
16
+ end
11
17
 
12
18
  # Module to track screen shot changes
13
19
  module Diff
@@ -1,7 +1,12 @@
1
1
  require 'capybara'
2
2
  require 'capybara/screenshot/diff/image_compare'
3
+ require 'action_controller'
4
+ require 'action_dispatch'
3
5
 
4
- # Add the `screenshot`method to ActionDispatch::IntegrationTest
6
+ # TODO(uwe): Move this code to module Capybara::Screenshot::Diff::TestMethods,
7
+ # and use Module#prepend/include to insert.
8
+ # Add the `screenshot` method to ActionDispatch::IntegrationTest
9
+ # rubocop:disable Metrics/ClassLength
5
10
  class ActionDispatch::IntegrationTest
6
11
  ON_WINDOWS = RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
7
12
  SILENCE_ERRORS = ON_WINDOWS ? '2>nul' : '2>/dev/null'
@@ -19,22 +24,51 @@ class ActionDispatch::IntegrationTest
19
24
  end
20
25
  end
21
26
 
22
- def self.screenshot_dir
27
+ def self.screenshot_root
28
+ Capybara::Screenshot.screenshot_root ||
29
+ (defined?(Rails.root) && Rails.root) || File.expand_path('.')
30
+ end
31
+
32
+ def self.screenshot_area
23
33
  parts = ['doc/screenshots']
24
34
  parts << Capybara.default_driver.to_s if Capybara::Screenshot.add_driver_path
25
35
  parts << os_name if Capybara::Screenshot.add_os_path
26
36
  File.join parts
27
37
  end
28
38
 
29
- def self.screenshot_dir_abs
30
- "#{Rails.root}/#{screenshot_dir}".freeze
39
+ def self.screenshot_area_abs
40
+ "#{screenshot_root}/#{screenshot_area}".freeze
41
+ end
42
+
43
+ def initialize(*)
44
+ super
45
+ @screenshot_counter = nil
46
+ @screenshot_group = nil
47
+ @screenshot_section = nil
48
+ @test_screenshot_errors = nil
49
+ @test_screenshots = nil
50
+ end
51
+
52
+ def group_parts
53
+ parts = []
54
+ parts << @screenshot_section if @screenshot_section.present?
55
+ parts << @screenshot_group if @screenshot_group.present?
56
+ parts
57
+ end
58
+
59
+ def full_name(name)
60
+ File.join group_parts.<<(name).map(&:to_s)
61
+ end
62
+
63
+ def screenshot_dir
64
+ File.join [self.class.screenshot_area] + group_parts
31
65
  end
32
66
 
33
67
  setup do
34
68
  if Capybara::Screenshot.window_size
35
69
  if Capybara.default_driver == :selenium
36
70
  page.driver.browser.manage.window.resize_to(*Capybara::Screenshot.window_size)
37
- else
71
+ elsif Capybara.default_driver == :poltergeist
38
72
  page.driver.resize(*Capybara::Screenshot.window_size)
39
73
  end
40
74
  end
@@ -47,14 +81,19 @@ class ActionDispatch::IntegrationTest
47
81
  fail(@test_screenshot_errors.join("\n\n")) if @test_screenshot_errors
48
82
  end
49
83
 
84
+ def screenshot_section(name)
85
+ @screenshot_section = name.to_s
86
+ end
87
+
50
88
  def screenshot_group(name)
51
- @screenshot_group = name
89
+ @screenshot_group = name.to_s
52
90
  @screenshot_counter = 0
53
- FileUtils.rm_rf "#{self.class.screenshot_dir_abs}/#{name}" if name.present?
91
+ return unless Capybara::Screenshot.active? && name.present?
92
+ FileUtils.rm_rf screenshot_dir
54
93
  end
55
94
 
56
95
  def screenshot(name)
57
- return unless Capybara::Screenshot.enabled || (Capybara::Screenshot.enabled.nil? && Capybara::Screenshot::Diff.enabled)
96
+ return unless Capybara::Screenshot.active?
58
97
  if Capybara.default_driver == :selenium && Capybara::Screenshot.window_size
59
98
  return unless page.driver.browser.manage.window
60
99
  .size == Selenium::WebDriver::Dimension.new(*Capybara::Screenshot.window_size)
@@ -63,46 +102,79 @@ class ActionDispatch::IntegrationTest
63
102
  name = "#{'%02i' % @screenshot_counter}_#{name}"
64
103
  @screenshot_counter += 1
65
104
  end
66
- name = "#{@screenshot_group}/#{name}" if @screenshot_group.present?
67
- file_name = "#{self.class.screenshot_dir_abs}/#{name}.png"
68
- org_name = "#{self.class.screenshot_dir_abs}/#{name}_0.png~"
69
- new_name = "#{self.class.screenshot_dir_abs}/#{name}_1.png~"
105
+ name = full_name(name)
106
+ file_name = "#{self.class.screenshot_area_abs}/#{name}.png"
107
+ org_name = "#{self.class.screenshot_area_abs}/#{name}_0.png~"
108
+ new_name = "#{self.class.screenshot_area_abs}/#{name}_1.png~"
70
109
 
71
110
  FileUtils.mkdir_p File.dirname(file_name)
72
- svn_file_name = "#{self.class.screenshot_dir_abs}/.svn/text-base/#{name}.png.svn-base"
111
+ svn_file_name = "#{self.class.screenshot_area_abs}/.svn/text-base/#{name}.png.svn-base"
73
112
  if File.exist?(svn_file_name)
74
113
  committed_file_name = svn_file_name
75
114
  else
76
115
  svn_info = `svn info #{file_name} #{SILENCE_ERRORS}`
77
116
  if svn_info.present?
78
- wc_root = svn_info.slice /(?<=Working Copy Root Path: ).*$/
79
- checksum = svn_info.slice /(?<=Checksum: ).*$/
117
+ wc_root = svn_info.slice(/(?<=Working Copy Root Path: ).*$/)
118
+ checksum = svn_info.slice(/(?<=Checksum: ).*$/)
80
119
  if checksum
81
120
  committed_file_name = "#{wc_root}/.svn/pristine/#{checksum[0..1]}/#{checksum}.svn-base"
82
121
  end
83
122
  else
84
123
  committed_file_name = org_name
85
- `git show HEAD~0:#{self.class.screenshot_dir}/#{name}.png > #{committed_file_name} #{SILENCE_ERRORS}`
124
+ `git show HEAD~0:#{self.class.screenshot_area}/#{name}.png > #{committed_file_name} #{SILENCE_ERRORS}`
86
125
  if File.size(committed_file_name) == 0
87
126
  FileUtils.rm_f committed_file_name
88
127
  end
89
128
  end
90
129
  end
130
+ take_stable_screenshot(file_name)
131
+ return unless committed_file_name && File.exist?(committed_file_name)
132
+ (@test_screenshots ||= []) << [caller[0], name, file_name, committed_file_name, new_name, org_name]
133
+ end
134
+
135
+ IMAGE_WAIT_SCRIPT = <<EOF.freeze
136
+ function pending_image() {
137
+ var images = document.images;
138
+ for (var i = 0; i < images.length; i++) {
139
+ if (!images[i].complete) {
140
+ return images[i].src;
141
+ }
142
+ }
143
+ return false;
144
+ }()
145
+ EOF
146
+
147
+ def assert_images_loaded(timeout: Capybara.default_max_wait_time)
148
+ return unless respond_to? :evaluate_script
149
+ start = Time.now
150
+ loop do
151
+ pending_image = evaluate_script IMAGE_WAIT_SCRIPT
152
+ break unless pending_image
153
+ assert (Time.now - start) < timeout,
154
+ "Image not loaded after #{timeout}s: #{pending_image.inspect}"
155
+ sleep 0.1
156
+ end
157
+ end
158
+
159
+ def take_stable_screenshot(file_name)
160
+ assert_images_loaded
91
161
  old_file_size = nil
92
162
  loop do
93
- page.save_screenshot(file_name)
94
- break if old_file_size == File.size(file_name)
95
- old_file_size = File.size(file_name)
96
- sleep 0.5
163
+ save_screenshot(file_name)
164
+ break unless Capybara::Screenshot.stability_time_limit
165
+ new_file_size = File.size(file_name)
166
+ break if new_file_size == old_file_size
167
+ old_file_size = new_file_size
168
+ sleep Capybara::Screenshot.stability_time_limit
97
169
  end
98
- return unless File.exist?(committed_file_name)
99
- (@test_screenshots ||= []) << [caller[0], name, file_name, committed_file_name, new_name, org_name]
100
170
  end
101
171
 
102
172
  def assert_image_not_changed(caller, name, file_name, committed_file_name, new_name, org_name)
103
- if Capybara::Screenshot::Diff::ImageCompare.compare(file_name, committed_file_name, Capybara::Screenshot.window_size)
173
+ if Capybara::Screenshot::Diff::ImageCompare.compare(committed_file_name, file_name,
174
+ Capybara::Screenshot.window_size)
104
175
  (@test_screenshot_errors ||= []) <<
105
- "Screenshot does not match for #{name.inspect}\n#{file_name}\n#{org_name}\n#{new_name}\nat #{caller}"
176
+ "Screenshot does not match for '#{name}'\n#{file_name}\n#{org_name}\n#{new_name}\nat #{caller}"
106
177
  end
107
178
  end
108
179
  end
180
+ # rubocop:enable Metrics/ClassLength
@@ -6,21 +6,31 @@ module Capybara
6
6
  class ImageCompare
7
7
  include ChunkyPNG::Color
8
8
 
9
- def self.compare(file_name, old_file_name, dimensions = nil)
10
- name = file_name.chomp('.png')
9
+ def self.compare(*args)
10
+ new(*args).compare
11
+ end
12
+
13
+ def initialize(old_file_name, new_file_name, dimensions = nil)
14
+ @old_file_name = old_file_name
15
+ @file_name = new_file_name
16
+ @dimensions = dimensions
17
+ end
18
+
19
+ def compare
20
+ name = @file_name.chomp('.png')
11
21
  org_file_name = "#{name}_0.png~"
12
22
  new_file_name = "#{name}_1.png~"
13
23
 
14
- return nil unless File.exist? old_file_name
24
+ return nil unless File.exist? @old_file_name
15
25
 
16
- images = load_images(old_file_name, file_name)
26
+ images = load_images(@old_file_name, @file_name)
17
27
 
18
28
  unless images
19
29
  clean_tmp_files(new_file_name, org_file_name)
20
30
  return false
21
31
  end
22
32
 
23
- crop_images(images, dimensions) if dimensions
33
+ crop_images(images, @dimensions) if @dimensions
24
34
  org_img = images.first
25
35
  new_img = images.last
26
36
  if sizes_changed?(org_img, new_img, name)
@@ -33,41 +43,45 @@ module Capybara
33
43
  return false
34
44
  end
35
45
 
36
- bottom, left, right, top = find_diff_rectangle(org_img, new_img)
37
- draw_rectangles(images, bottom, left, right, top)
46
+ @left, @top, @right, @bottom = find_diff_rectangle(org_img, new_img)
47
+ draw_rectangles(images, @bottom, @left, @right, @top)
38
48
  save_images(new_file_name, new_img, org_file_name, org_img)
39
49
  true
40
50
  end
41
51
 
42
- def self.save_images(new_file_name, new_img, org_file_name, org_img)
52
+ def dimensions
53
+ [@left, @top, @right, @bottom]
54
+ end
55
+
56
+ private
57
+
58
+ def save_images(new_file_name, new_img, org_file_name, org_img)
43
59
  org_img.save(org_file_name)
44
60
  new_img.save(new_file_name)
45
61
  end
46
62
 
47
- def self.clean_tmp_files(new_file_name, org_file_name)
48
- File.delete(org_file_name) if File.exists?(org_file_name)
49
- File.delete(new_file_name) if File.exists?(new_file_name)
63
+ def clean_tmp_files(new_file_name, org_file_name)
64
+ File.delete(org_file_name) if File.exist?(org_file_name)
65
+ File.delete(new_file_name) if File.exist?(new_file_name)
50
66
  end
51
67
 
52
- private
53
-
54
- def self.load_images(old_file_name, file_name)
55
- old_file = File.read(old_file_name)
56
- new_file = File.read(file_name)
68
+ def load_images(old_file_name, file_name)
69
+ old_file = File.binread(old_file_name)
70
+ new_file = File.binread(file_name)
57
71
 
58
72
  return false if old_file == new_file
59
73
 
60
74
  [ChunkyPNG::Image.from_blob(old_file), ChunkyPNG::Image.from_blob(new_file)]
61
75
  end
62
76
 
63
- def self.sizes_changed?(org_image, new_image, name)
64
- if org_image.dimension != new_image.dimension
65
- puts "Image size has changed for #{name}: #{[org_image, new_image].map { |i| "#{i.width}x#{i.height}" }.join(' => ')}"
66
- return true
67
- end
77
+ def sizes_changed?(org_image, new_image, name)
78
+ return unless org_image.dimension != new_image.dimension
79
+ change_msg = [org_image, new_image].map { |i| "#{i.width}x#{i.height}" }.join(' => ')
80
+ puts "Image size has changed for #{name}: #{change_msg}"
81
+ true
68
82
  end
69
83
 
70
- def self.crop_images(images, dimensions)
84
+ def crop_images(images, dimensions)
71
85
  images.map! do |i|
72
86
  if i.dimension.to_a == dimensions || i.width < dimensions[0] || i.height < dimensions[1]
73
87
  i
@@ -77,26 +91,24 @@ module Capybara
77
91
  end
78
92
  end
79
93
 
80
- def self.draw_rectangles(images, bottom, left, right, top)
81
- (1..2).each do |i|
82
- images.each do |image|
83
- image.rect(left - 1, top - 1, right + 1, bottom + 1, ChunkyPNG::Color.rgb(255, 0, 0))
84
- end
94
+ def draw_rectangles(images, bottom, left, right, top)
95
+ images.each do |image|
96
+ image.rect(left - 1, top - 1, right + 1, bottom + 1, ChunkyPNG::Color.rgb(255, 0, 0))
85
97
  end
86
98
  end
87
99
 
88
- def self.find_diff_rectangle(org_img, new_img)
100
+ def find_diff_rectangle(org_img, new_img)
89
101
  top = bottom = nil
90
102
  left = org_img.width
91
103
  right = -1
92
104
  org_img.height.times do |y|
93
105
  (0...left).find do |x|
94
- if org_img[x, y] != new_img[x, y]
95
- top ||= y
96
- bottom = y
97
- left = x
98
- right = x if x > right
99
- end
106
+ next if org_img[x, y] == new_img[x, y]
107
+ top ||= y
108
+ bottom = y
109
+ left = x
110
+ right = x if x > right
111
+ x
100
112
  end
101
113
  (org_img.width - 1).step(right + 1, -1).find do |x|
102
114
  if org_img[x, y] != new_img[x, y]
@@ -107,12 +119,10 @@ module Capybara
107
119
  end
108
120
  (org_img.height - 1).step(bottom + 1, -1).find do |y|
109
121
  ((left + 1)..(right - 1)).find do |x|
110
- if org_img[x, y] != new_img[x, y]
111
- bottom = y
112
- end
122
+ bottom = y if org_img[x, y] != new_img[x, y]
113
123
  end
114
124
  end
115
- return bottom, left, right, top
125
+ [left, top, right, bottom]
116
126
  end
117
127
  end
118
128
  end
@@ -2,7 +2,7 @@
2
2
  module Capybara
3
3
  module Screenshot
4
4
  module Diff
5
- VERSION = '0.1.0'.freeze
5
+ VERSION = '0.2.1'.freeze
6
6
  end
7
7
  end
8
8
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capybara-screenshot-diff
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Uwe Kubosch
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-04-20 00:00:00.000000000 Z
11
+ date: 2016-12-20 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: actionpack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '4.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4.1'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: capybara
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -25,33 +39,33 @@ dependencies:
25
39
  - !ruby/object:Gem::Version
26
40
  version: '2.0'
27
41
  - !ruby/object:Gem::Dependency
28
- name: bundler
42
+ name: chunky_png
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - "~>"
32
46
  - !ruby/object:Gem::Version
33
- version: '1.11'
34
- type: :development
47
+ version: '1.3'
48
+ type: :runtime
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
- version: '1.11'
54
+ version: '1.3'
41
55
  - !ruby/object:Gem::Dependency
42
- name: rake
56
+ name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: '10.0'
61
+ version: '1.11'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '10.0'
68
+ version: '1.11'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: minitest
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +94,20 @@ dependencies:
80
94
  - - ">="
81
95
  - !ruby/object:Gem::Version
82
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '10.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '10.0'
83
111
  - !ruby/object:Gem::Dependency
84
112
  name: rubocop
85
113
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +122,20 @@ dependencies:
94
122
  - - "~>"
95
123
  - !ruby/object:Gem::Version
96
124
  version: '0.39'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.11'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.11'
97
139
  description: Save screen shots and track changes with graphical diff
98
140
  email:
99
141
  - uwe@kubosch.no