screenpress 0.1.1 → 0.2.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.
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 1.9.3-p194
data/README.md CHANGED
@@ -67,10 +67,11 @@ end
67
67
  * Maybe be more deliberate like Huxley and set modes (ENV variables?) for recording
68
68
  * Enable mode that fails test if image changes
69
69
  * Enable tools to easily compare without Github (locally)
70
-
70
+ * Is there a good way to automatically take screenshots or when example is tagged?
71
71
 
72
72
  ### Inspiration
73
73
 
74
74
  * [Huxley](https://github.com/facebook/huxley)
75
75
  * [Wraith](https://github.com/BBC-News/wraith)
76
+ * [Green Onion](https://github.com/intridea/green_onion)
76
77
  * [Capybara Screenshot](https://github.com/mattheworiordan/capybara-screenshot)
data/lib/screenpress.rb CHANGED
@@ -3,6 +3,7 @@ require "capybara"
3
3
 
4
4
  module Screenpress
5
5
  autoload :Config, 'screenpress/config'
6
+ autoload :Compare, 'screenpress/compare'
6
7
  autoload :DSL, 'screenpress/dsl'
7
8
  autoload :Saver, 'screenpress/saver'
8
9
 
@@ -0,0 +1,115 @@
1
+ # based on: https://github.com/intridea/green_onion/blob/master/lib/green_onion/compare.rb
2
+
3
+ require "oily_png"
4
+
5
+ module Screenpress
6
+ class Compare
7
+ include ChunkyPNG::Color
8
+
9
+ attr_reader :orig_image, :fresh_image, :threshold
10
+ def initialize(orig_path, fresh_path, threshold)
11
+ @orig_path = orig_path
12
+ @fresh_path = fresh_path
13
+ @threshold ||= threshold
14
+ end
15
+
16
+ def same?
17
+ return !File.exists?(@fresh_path) if !File.exists?(@orig_path)
18
+ setup
19
+
20
+ return false unless diff_iterator
21
+
22
+
23
+ if percentage_diff > 0
24
+ puts "Image Percentage Different #{@orig_path}: #{percentage_diff}"
25
+ if percentage_diff > self.threshold
26
+ puts " Image different!"
27
+ return false
28
+ end
29
+ end
30
+
31
+ true
32
+ end
33
+
34
+ protected
35
+
36
+ def setup
37
+ return if @diff_index
38
+ @orig_image = ChunkyPNG::Image.from_file(@orig_path)
39
+ @fresh_image = ChunkyPNG::Image.from_file(@fresh_path)
40
+ @diff_index = []
41
+ end
42
+
43
+
44
+ # Pulled from Jeff Kreeftmeijer's post here: http://jeffkreeftmeijer.com/2011/comparing-images-and-creating-image-diffs/
45
+ # Run through all of the pixels on both org image, and fresh image. Change the pixel color accordingly.
46
+ def update_diff_index(x, y, pixel)
47
+ lowest_score = 1
48
+ return if pixel == fresh_image[x,y]
49
+
50
+ # try a bit in each direction to account for differences
51
+ [-2, -1, 0, 1, 2].each do |yd|
52
+ [-1, 0, 1].each do |xd|
53
+ begin
54
+ # to do based on more nuanced score
55
+ #score = Math.sqrt(
56
+ # (r(fresh_image[x+xd,y+yd]) - r(pixel)) ** 2 +
57
+ # (g(fresh_image[x+xd,y+yd]) - g(pixel)) ** 2 +
58
+ # (b(fresh_image[x+xd,y+yd]) - b(pixel)) ** 2
59
+ # ) / Math.sqrt(MAX ** 2 * 3)
60
+
61
+ return if pixel == fresh_image[x+xd,y+yd]
62
+
63
+ score = 1
64
+
65
+ lowest_score = score if score < lowest_score
66
+ rescue ChunkyPNG::OutOfBounds
67
+ # off the edge!
68
+ end
69
+ end
70
+ end
71
+
72
+ @diff_index << [x,y,lowest_score] if lowest_score > 0
73
+ end
74
+
75
+ def diff_iterator
76
+ orig_image.height.times do |y|
77
+ orig_image.row(y).each_with_index do |pixel, x|
78
+ update_diff_index(x, y, pixel)
79
+ end
80
+ end
81
+
82
+ return true
83
+ end
84
+
85
+ # Returns the numeric results of the diff of 2 images
86
+ def percentage_diff
87
+ return @percentage_changed if @percentage_changed
88
+ total_px = orig_image.pixels.length
89
+ changed_px = @diff_index.length
90
+
91
+ # to do based on more nuanced score
92
+ #changed_px = 0.0
93
+ #@diff_index.each do |x,y,score|
94
+ # could use the actual score
95
+ # changed_px += score
96
+ #end
97
+ @percentage_changed = ((changed_px.to_f*100) / total_px)
98
+ end
99
+
100
+ # Saves the visual diff as a separate file
101
+ def save_visual_diff
102
+ x, y = @diff_index.map{ |xy| xy[0] }, @diff_index.map{ |xy| xy[1] }
103
+ diff_path = @orig_path.insert(-5, '_diff')
104
+
105
+ begin
106
+ fresh_image.rect(x.min, y.min, x.max, y.max, ChunkyPNG::Color.rgb(0,255,0))
107
+ rescue NoMethodError
108
+ puts "Both images are the same."
109
+ end
110
+
111
+ fresh_image.save(diff_path)
112
+ end
113
+
114
+ end
115
+ end
@@ -1,5 +1,7 @@
1
1
  module Screenpress
2
2
  class Config
3
+ attr_accessor :enabled
4
+
3
5
  def path=val
4
6
  self.full_path = root.join(val)
5
7
  end
@@ -13,13 +15,31 @@ module Screenpress
13
15
  @full_path
14
16
  end
15
17
 
16
- def enabled=val
17
- @enabled = val
18
+ def tmp_path=val
19
+ self.full_tmp_path=root.join(val)
20
+ end
21
+
22
+ def full_tmp_path=val
23
+ @full_tmp_path = Pathname.new(val).expand_path
24
+ end
25
+
26
+ def full_tmp_path
27
+ self.tmp_path = "tmp" unless @full_tmp_path
28
+ @full_tmp_path
18
29
  end
19
30
 
20
31
  def enabled?
21
- return !!@enabled if defined?(@enabled)
22
- @enabled = calc_enabled
32
+ return !!@calc_enabled if defined?(@calc_enabled)
33
+ @calc_enabled = calc_enabled
34
+ end
35
+
36
+ def threshold=val
37
+ # number between 0.0 and 100.0 for percentage of image that can change
38
+ @threshold = val.to_f
39
+ end
40
+
41
+ def threshold
42
+ @threshold ||= 0.1
23
43
  end
24
44
 
25
45
  protected
@@ -17,13 +17,28 @@ module Screenpress
17
17
  end
18
18
 
19
19
  def save_screenshot
20
+ tmp_file = self.tmp_filename
21
+
20
22
  # settings to nil because of issues in some version of capybara
21
23
  old_path = Capybara.save_and_open_page_path
22
24
  Capybara.save_and_open_page_path = nil
23
25
 
24
26
  ensure_directory
25
27
 
26
- Screenpress::Saver::Proxy.save!(capybara.current_driver, page.driver, filename)
28
+ return false unless Screenpress::Saver::Proxy.save!(capybara.current_driver, page.driver, tmp_file)
29
+
30
+ # is it different?
31
+ compare = Screenpress::Compare.new(filename, tmp_file, Screenpress.config.threshold)
32
+ if compare.same?
33
+ File.delete(tmp_file)
34
+ else
35
+ FileUtils.mv(tmp_file, filename)
36
+ end
37
+ return true
38
+
39
+ rescue Exception => e
40
+ File.delete(tmp_file) if tmp_file && File.exists?(tmp_file)
41
+ raise e
27
42
  end
28
43
 
29
44
  def ensure_directory
@@ -32,6 +47,12 @@ module Screenpress
32
47
  FileUtils.mkdir_p(folder)
33
48
  end
34
49
 
50
+ def tmp_filename
51
+ tmp_dir = Screenpress.config.full_tmp_path.to_s
52
+ tmp_file = "#{tmp_dir}/screenpress_#{File.basename(filename)}"
53
+ tmp_file
54
+ end
55
+
35
56
  class Proxy
36
57
  class << self
37
58
  def save!(name, driver, filename)
@@ -1,3 +1,3 @@
1
1
  module Screenpress
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
data/screenpress.gemspec CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency "capybara"
22
+ spec.add_dependency "oily_png"
22
23
 
23
24
  spec.add_development_dependency "bundler", "~> 1.3"
24
25
  spec.add_development_dependency "rake"
metadata CHANGED
@@ -1,32 +1,52 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: screenpress
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Brian Leonard
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2013-12-06 00:00:00.000000000 Z
12
+ date: 2013-12-09 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: capybara
15
16
  requirement: !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
- - - '>='
19
+ - - ! '>='
18
20
  - !ruby/object:Gem::Version
19
21
  version: '0'
20
22
  type: :runtime
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
23
26
  requirements:
24
- - - '>='
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: oily_png
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
25
44
  - !ruby/object:Gem::Version
26
45
  version: '0'
27
46
  - !ruby/object:Gem::Dependency
28
47
  name: bundler
29
48
  requirement: !ruby/object:Gem::Requirement
49
+ none: false
30
50
  requirements:
31
51
  - - ~>
32
52
  - !ruby/object:Gem::Version
@@ -34,6 +54,7 @@ dependencies:
34
54
  type: :development
35
55
  prerelease: false
36
56
  version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
37
58
  requirements:
38
59
  - - ~>
39
60
  - !ruby/object:Gem::Version
@@ -41,43 +62,49 @@ dependencies:
41
62
  - !ruby/object:Gem::Dependency
42
63
  name: rake
43
64
  requirement: !ruby/object:Gem::Requirement
65
+ none: false
44
66
  requirements:
45
- - - '>='
67
+ - - ! '>='
46
68
  - !ruby/object:Gem::Version
47
69
  version: '0'
48
70
  type: :development
49
71
  prerelease: false
50
72
  version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
51
74
  requirements:
52
- - - '>='
75
+ - - ! '>='
53
76
  - !ruby/object:Gem::Version
54
77
  version: '0'
55
78
  - !ruby/object:Gem::Dependency
56
79
  name: rspec
57
80
  requirement: !ruby/object:Gem::Requirement
81
+ none: false
58
82
  requirements:
59
- - - '>='
83
+ - - ! '>='
60
84
  - !ruby/object:Gem::Version
61
85
  version: '0'
62
86
  type: :development
63
87
  prerelease: false
64
88
  version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
65
90
  requirements:
66
- - - '>='
91
+ - - ! '>='
67
92
  - !ruby/object:Gem::Version
68
93
  version: '0'
69
94
  - !ruby/object:Gem::Dependency
70
95
  name: debugger
71
96
  requirement: !ruby/object:Gem::Requirement
97
+ none: false
72
98
  requirements:
73
- - - '>='
99
+ - - ! '>='
74
100
  - !ruby/object:Gem::Version
75
101
  version: '0'
76
102
  type: :development
77
103
  prerelease: false
78
104
  version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
79
106
  requirements:
80
- - - '>='
107
+ - - ! '>='
81
108
  - !ruby/object:Gem::Version
82
109
  version: '0'
83
110
  description: Workflow and Capybara extension that takes screenshots of your tests
@@ -90,11 +117,13 @@ extra_rdoc_files: []
90
117
  files:
91
118
  - .gitignore
92
119
  - .rspec
120
+ - .ruby-version
93
121
  - Gemfile
94
122
  - LICENSE.txt
95
123
  - README.md
96
124
  - Rakefile
97
125
  - lib/screenpress.rb
126
+ - lib/screenpress/compare.rb
98
127
  - lib/screenpress/config.rb
99
128
  - lib/screenpress/dsl.rb
100
129
  - lib/screenpress/saver.rb
@@ -107,29 +136,31 @@ files:
107
136
  homepage: https://github.com/taskrabbit/screenpress
108
137
  licenses:
109
138
  - MIT
110
- metadata: {}
111
139
  post_install_message:
112
140
  rdoc_options: []
113
141
  require_paths:
114
142
  - lib
115
143
  required_ruby_version: !ruby/object:Gem::Requirement
144
+ none: false
116
145
  requirements:
117
- - - '>='
146
+ - - ! '>='
118
147
  - !ruby/object:Gem::Version
119
148
  version: '0'
120
149
  required_rubygems_version: !ruby/object:Gem::Requirement
150
+ none: false
121
151
  requirements:
122
- - - '>='
152
+ - - ! '>='
123
153
  - !ruby/object:Gem::Version
124
154
  version: '0'
125
155
  requirements: []
126
156
  rubyforge_project:
127
- rubygems_version: 2.0.3
157
+ rubygems_version: 1.8.23
128
158
  signing_key:
129
- specification_version: 4
159
+ specification_version: 3
130
160
  summary: Prevent visual regressions
131
161
  test_files:
132
162
  - spec/config_spec.rb
133
163
  - spec/dsl_spec.rb
134
164
  - spec/saver_spec.rb
135
165
  - spec/spec_helper.rb
166
+ has_rdoc:
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 0e788d87ac38505a9a4a0a18c763ed7b90090510
4
- data.tar.gz: 700ac9fd342eb0a9f471813840eaf65b6b5c87a0
5
- SHA512:
6
- metadata.gz: cafa83682004a4c115dbaa6417d5628cb7c69396a154f68bb6af49e4e584cba612d54560393bbec33e00f301e4bc769da1c978ab7a1a398a1618e4f9b74bda33
7
- data.tar.gz: 1bfeca9e8bcdc5b4b72f3144fc3c98bc59ae6edad94874795ffbca383643783ff8dd4df240255b949cfa0233db33808baf518b337ddaf19151246d53dff67bb3