motion-juxtapose 0.1.1 → 0.2.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: 0543dfe3a91b130a2a8faf863307dd63e3ba619d
4
- data.tar.gz: b12e0a693f99ef3d63eb0a73674f0ab94a232142
3
+ metadata.gz: a58dcf720096d73d57d3a904dee1bc216889ce5c
4
+ data.tar.gz: b54b20541785bfbcb8873f552021578e034ea12e
5
5
  SHA512:
6
- metadata.gz: f676239c5499c311ed923ab84de8aadd96092459db5a563136352be7d828d986bbf336973313d95192910446d3e5f461268976b48782c3ec775c7a353108fd33
7
- data.tar.gz: 013fe557fbbe9ebdcbc0a8dd1d5920a3fd89d312cca5f140936ec35fe97a989e57f96e96d92e3cf157278c2d4b92dea4c7cc855ec8cc9fc31d7a363767a40736
6
+ metadata.gz: 78e454b932c47f2f76cc27ba28e97c2016fe921f1b3febc6b05164236dd95af2ce5fc542b3a7198af7d3c96be7087e81be1e343b90118c79a83e619d9a6dd2b1
7
+ data.tar.gz: f2253d30b74513c06b7393734f7155be1c45c482d036328203e5d657d3a3a961596863d8b71a70f2446e703b04a0c5aa15ab5ee1ac2c27b106966daa32fe1347
data/README.md CHANGED
@@ -1,9 +1,13 @@
1
1
  # Juxtapose
2
2
 
3
- Screenshot-driven assertions for testing RubyMotion applications.
3
+ Screenshot-driven assertions for testing Rails and RubyMotion applications.
4
4
 
5
5
  ## Installation
6
6
 
7
+ Motion-juxtapose uses [ImageMagick](http://www.imagemagick.org/) under the hood for image comparison. If you're using [Homebrew](http://brew.sh/), you can install it with:
8
+
9
+ brew install imagemagick
10
+
7
11
  Add this line to your application's Gemfile:
8
12
 
9
13
  gem 'motion-juxtapose'
@@ -22,13 +26,15 @@ Juxtapose's workflow generally goes:
22
26
 
23
27
  1. Write a test that puts your app in the state you want to capture and take a screenshot (see below for how to do this in Bacon and Frank).
24
28
  2. The first time this screenshot is captured, your test will fail with the error "No accepted screen shot".
25
- 3. You must provide Juxtapose an accepted screenshot to match against in future test runs. Run the juxtapose server with `bundle exec juxtapose` and browse to http://localhost:4567 — you should the just-captured screenshot, like below.
29
+ 3. You must provide Juxtapose an accepted screenshot to match against in future test runs. Run the juxtapose server with `bundle exec juxtapose` and browse to http://localhost:4567 — you should see the just-captured screenshot, like below.
26
30
  4. If the screenshot looks like what you expect, click Accept to save the image. Future runs of this test will be compared against the accepted one. ![Initial view of screenshots.](images/initial-view.png)
27
31
  5. Run the tests again, and they should be green.
28
32
  6. Later, when you introduce a change (intentionally or not), the tests will fail with the message "Screenshot did not match". Open up the juxtapose server again, and you'll see a comparison of your accepted screenshot with what the test captured. ![Diff view of screenshots.](images/diff-view.png)
29
33
  7. If the change was intentional, you can accept the new screenshot - otherwise, you've got some fixin' to do!
30
34
 
31
35
 
36
+ ## Testing RubyMotion Apps
37
+
32
38
  ### MacBacon
33
39
 
34
40
  Juxtapose provides a single new matcher: `it_should_look_like` takes a single argument, a descriptive string predicate of what the screen should look like.
@@ -70,6 +76,53 @@ Then /^the screen should match "([^\"]*)"$/ do |template|
70
76
  end
71
77
  ```
72
78
 
79
+ ## Testing Rails Apps
80
+
81
+ ### Capybara
82
+
83
+ Any Capybara driver that supports screenshot capture should work, but I've only tested this with [Poltergeist](https://github.com/teampoltergeist/poltergeist) so far.
84
+
85
+ In your `spec_helper.rb`, add:
86
+
87
+ ```ruby
88
+ require 'juxtapose/capybara'
89
+
90
+ # if you're using Rspec, you can get the `look_like?` custom matcher with:
91
+ require 'juxtapose/rspec'
92
+ ```
93
+
94
+ Now the Capybara page object will have a `looks_like?(predicate)` method that can call to make screenshot assertions:
95
+
96
+ ```ruby
97
+ feature "viewing locations", js: true do
98
+ scenario "should only show books at first location" do
99
+ visit location_path Location.find_by_name("Cambridge")
100
+ expect(page).to look_like("books at Cambridge")
101
+ end
102
+ end
103
+ ```
104
+
105
+ ### Fuzzy matching
106
+
107
+ Sometimes screenshots will differ slightly due to things like animation timing. Juxtapose will try to match an existing screenshot multiple times to help counteract this, but it can still be useful to be able to match screenshots using a percent similarity threshold.
108
+
109
+ In bacon specs, you can pass a fuzz factor from 0 to 100 to `it_should_look_like`, 0 meaning an exact match and 100 matching anything of the same size. The default is 0.
110
+
111
+ ```ruby
112
+ # matches images that are 15% similar
113
+ it_should_look_like 'a fancy animation', 15
114
+ ```
115
+
116
+ In Frank, pass the fuzz factor in as the third argument to the Screenshotter constructor. A more exacting Frank step could be written as:
117
+
118
+ ```ruby
119
+ Then /^the screen should match "([^\"]*)" within (\d+)% in (\d+) attempts$/ do |template, fuzz_factor, max_attempts|
120
+ wait_for_nothing_to_be_animating
121
+ screenshotter = Juxtapose::Screenshotter.new(self, template, fuzz_factor)
122
+ expect(screenshotter.attempt_verify(max_attempts)).to eq(true)
123
+ end
124
+ ```
125
+
73
126
  ### Juxtapose Server
74
127
 
75
128
  Juxtapose comes with a small webapp that you can use to view your screenshot specs, see diffs between accepted and failing specs and accept any changed images that are expected changes.
@@ -78,6 +131,10 @@ To start it, run `bundle exec juxtapose` in the root of your project and browse
78
131
 
79
132
  ## Release Notes
80
133
 
134
+ #### v.0.2.0
135
+ * Rails/rspec support
136
+ * Fixes to work under newest version of ImageMagick
137
+
81
138
  #### v.0.1.1
82
139
 
83
140
  * Raise error if screenshot sizes don't match ([@mdenomy](http://github.com/mdenomy))
@@ -46,7 +46,13 @@ angular.module('juxtapose.controllers').controller('ProjectsCtrl', ['$scope', '$
46
46
  });
47
47
 
48
48
  $scope.iOSVersion = function(spec){
49
- return spec.directory.match(/([^\/]*)\/[^\/]+\/[^\/]+$/)[1].match(/[\d\.]+/)[0]
49
+ version = spec.directory.match(/([^\/]*)\/[^\/]+\/[^\/]+$/)[1]
50
+ iosVersion = version.match(/[\d\.]+/)
51
+ if(iosVersion){
52
+ return iosVersion[0];
53
+ } else {
54
+ return version;
55
+ }
50
56
  }
51
57
 
52
58
  var versions = _.uniq(_.map($scope.project.specs, $scope.iOSVersion))
@@ -0,0 +1,5 @@
1
+ if defined?(Capybara::Session)
2
+ class Capybara::Session
3
+ include Juxtapose
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ if defined?(RSpec::Matchers)
2
+ RSpec::Matchers.define :look_like do |predicate|
3
+ match do |page|
4
+ page.looks_like?(predicate) == true
5
+ end
6
+ end
7
+ end
@@ -19,8 +19,12 @@ module Juxtapose
19
19
 
20
20
  MAX_ATTEMPTS = 20
21
21
 
22
+ def looks_like?(template, fuzz_factor=0)
23
+ Screenshotter.new(self, template, fuzz_factor).attempt_verify(MAX_ATTEMPTS)
24
+ end
25
+
22
26
  def it_should_look_like(template, fuzz_factor = 0)
23
- Screenshotter.new(self, template, fuzz_factor).attempt_verify(MAX_ATTEMPTS).should.be.true
27
+ looks_like?(template, fuzz_factor).should.be.true
24
28
  end
25
29
 
26
30
  class Screenshotter
@@ -44,11 +48,17 @@ module Juxtapose
44
48
  Juxtapose::MacBaconStrategy.new(context)
45
49
  elsif context.respond_to? :frankly_ping
46
50
  Juxtapose::FrankStrategy.new(context)
51
+ elsif defined?(Capybara)
52
+ Juxtapose::CapybaraStrategy.new(context)
47
53
  end
48
54
  end
49
55
 
50
56
  def project_root
51
- ENV["RUBYMOTION_PROJECT_DIR"]
57
+ if defined? Rails
58
+ Rails.root
59
+ else
60
+ ENV["RUBYMOTION_PROJECT_DIR"]
61
+ end
52
62
  end
53
63
 
54
64
  def test_name
@@ -80,6 +90,8 @@ module Juxtapose
80
90
  end
81
91
 
82
92
  def attempt_verify(max_attempts)
93
+ ensure_imagemagick_installed
94
+
83
95
  attempts = 0
84
96
  while attempts < max_attempts
85
97
  return true if verify
@@ -90,6 +102,8 @@ module Juxtapose
90
102
  end
91
103
 
92
104
  def verify
105
+ ensure_imagemagick_installed
106
+
93
107
  strategy.save_current filename(:current)
94
108
  accept_current if ENV['ACCEPT_ALL_SCREENSHOTS']
95
109
 
@@ -104,6 +118,16 @@ module Juxtapose
104
118
  success
105
119
  end
106
120
 
121
+ def ensure_imagemagick_installed
122
+ unless imagemagick_installed?
123
+ raise "Executable for 'convert' not installed or not found on $PATH. Please install Imagemagick or add it to your $PATH."
124
+ end
125
+ end
126
+
127
+ def imagemagick_installed?
128
+ `command -v convert`.length > 0
129
+ end
130
+
107
131
  private
108
132
 
109
133
  def same_size?
@@ -113,20 +137,30 @@ module Juxtapose
113
137
  sizes.length == 2 && sizes.uniq.length == 1
114
138
  end
115
139
 
116
- def screenshots_match?
117
- match = true
140
+ def create_diff
141
+ `compare -fuzz #{fuzz_factor}% -dissimilarity-threshold 1 -subimage-search \"#{filename :current}\" \"#{filename :accepted}\" \"#{filename :diff}\" 2>&1`
142
+ end
143
+
144
+ def cleanup
145
+ `rm #{filename(:current)}`
146
+ `rm #{filename(:diff)}`
147
+ end
148
+
149
+ def identical_images?
118
150
  compare_command = "compare -fuzz #{fuzz_factor}% -metric AE -dissimilarity-threshold 1 -subimage-search"
119
151
  out = `#{compare_command} \"#{filename :current}\" \"#{filename :accepted}\" \"#{filename :diff}\" 2>&1`
120
152
  out.chomp!
121
- (out == '0').tap do |verified|
122
- if verified
123
- `rm #{filename(:current)}`
124
- `rm #{filename(:diff)}`
125
- else
126
- match = false
127
- end
153
+ out.start_with?('0')
154
+ end
155
+
156
+ def screenshots_match?
157
+ if identical_images?
158
+ cleanup
159
+ true
160
+ else
161
+ create_diff
162
+ false
128
163
  end
129
- match
130
164
  end
131
165
  end
132
166
  end
@@ -0,0 +1,31 @@
1
+ module Juxtapose
2
+ class CapybaraStrategy
3
+
4
+ attr_accessor :context
5
+ def initialize(context)
6
+ self.context = context
7
+ end
8
+
9
+ def version
10
+ @version ||= "web"
11
+ end
12
+
13
+ def current_spec_description
14
+ "spec-description"
15
+ #context.instance_variable_get('@__scenario').name
16
+ end
17
+
18
+ def device_name
19
+ "capybara"
20
+ end
21
+
22
+ def save_current(filename)
23
+ Capybara.save_screenshot filename
24
+ end
25
+
26
+ def spec_dir
27
+ "spec/screens"
28
+ end
29
+
30
+ end
31
+ end
@@ -1,3 +1,3 @@
1
1
  module Juxtapose
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,6 +1,7 @@
1
1
  require "juxtapose/version"
2
2
  require "juxtapose/screenshotter"
3
3
  require "juxtapose/strategy/frank_strategy"
4
+ require "juxtapose/strategy/capybara_strategy"
4
5
 
5
6
  if defined?(Motion::Project::Config)
6
7
  Motion::Project::App.setup do |app|
@@ -33,14 +33,14 @@ describe 'screenshot testing under bacon' do
33
33
  error.should.not.be.nil
34
34
  error.message.should =~ /Screenshot did not match/
35
35
 
36
- spec_dir = "spec/screens/iphone-retina/ios_7.0.3/screenshot-testing-under-bacon-raises-an-error-and-produces-diffs-on-failure/going-to-differ-screenshot"
36
+ spec_dir = "spec/screens/iphone-retina/ios_7.1/screenshot-testing-under-bacon-raises-an-error-and-produces-diffs-on-failure/going-to-differ-screenshot"
37
37
 
38
38
  File.should.exist(File.join( ENV["RUBYMOTION_PROJECT_DIR"], spec_dir, "current.png"))
39
39
  File.should.exist(File.join( ENV["RUBYMOTION_PROJECT_DIR"], spec_dir, "diff.png"))
40
40
  end
41
41
  end
42
42
 
43
- it "raises an error when screens are different sizes" do
43
+ it "raises an error when screens are different sizes" do
44
44
  error = nil
45
45
  begin
46
46
  it_should_look_like "different sized screenshot"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: motion-juxtapose
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe Lind
@@ -10,90 +10,90 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-03-10 00:00:00.000000000 Z
13
+ date: 2014-08-27 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: sinatra
17
17
  requirement: !ruby/object:Gem::Requirement
18
18
  requirements:
19
- - - ~>
19
+ - - "~>"
20
20
  - !ruby/object:Gem::Version
21
21
  version: '1.4'
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
- - - ~>
26
+ - - "~>"
27
27
  - !ruby/object:Gem::Version
28
28
  version: '1.4'
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: haml
31
31
  requirement: !ruby/object:Gem::Requirement
32
32
  requirements:
33
- - - '>='
33
+ - - ">="
34
34
  - !ruby/object:Gem::Version
35
35
  version: '0'
36
36
  type: :runtime
37
37
  prerelease: false
38
38
  version_requirements: !ruby/object:Gem::Requirement
39
39
  requirements:
40
- - - '>='
40
+ - - ">="
41
41
  - !ruby/object:Gem::Version
42
42
  version: '0'
43
43
  - !ruby/object:Gem::Dependency
44
44
  name: bundler
45
45
  requirement: !ruby/object:Gem::Requirement
46
46
  requirements:
47
- - - ~>
47
+ - - "~>"
48
48
  - !ruby/object:Gem::Version
49
49
  version: '1.3'
50
50
  type: :development
51
51
  prerelease: false
52
52
  version_requirements: !ruby/object:Gem::Requirement
53
53
  requirements:
54
- - - ~>
54
+ - - "~>"
55
55
  - !ruby/object:Gem::Version
56
56
  version: '1.3'
57
57
  - !ruby/object:Gem::Dependency
58
58
  name: rake
59
59
  requirement: !ruby/object:Gem::Requirement
60
60
  requirements:
61
- - - '>='
61
+ - - ">="
62
62
  - !ruby/object:Gem::Version
63
63
  version: '0'
64
64
  type: :development
65
65
  prerelease: false
66
66
  version_requirements: !ruby/object:Gem::Requirement
67
67
  requirements:
68
- - - '>='
68
+ - - ">="
69
69
  - !ruby/object:Gem::Version
70
70
  version: '0'
71
71
  - !ruby/object:Gem::Dependency
72
72
  name: rspec
73
73
  requirement: !ruby/object:Gem::Requirement
74
74
  requirements:
75
- - - '>='
75
+ - - ">="
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0'
78
78
  type: :development
79
79
  prerelease: false
80
80
  version_requirements: !ruby/object:Gem::Requirement
81
81
  requirements:
82
- - - '>='
82
+ - - ">="
83
83
  - !ruby/object:Gem::Version
84
84
  version: '0'
85
85
  - !ruby/object:Gem::Dependency
86
86
  name: fakefs
87
87
  requirement: !ruby/object:Gem::Requirement
88
88
  requirements:
89
- - - '>='
89
+ - - ">="
90
90
  - !ruby/object:Gem::Version
91
91
  version: '0'
92
92
  type: :development
93
93
  prerelease: false
94
94
  version_requirements: !ruby/object:Gem::Requirement
95
95
  requirements:
96
- - - '>='
96
+ - - ">="
97
97
  - !ruby/object:Gem::Version
98
98
  version: '0'
99
99
  description: Screenshot-based assertions for RubyMotion projects
@@ -104,7 +104,7 @@ executables:
104
104
  extensions: []
105
105
  extra_rdoc_files: []
106
106
  files:
107
- - .gitignore
107
+ - ".gitignore"
108
108
  - Gemfile
109
109
  - LICENSE.txt
110
110
  - README.md
@@ -151,16 +151,19 @@ files:
151
151
  - lib/juxtapose/application/spec/models/spec_spec.rb
152
152
  - lib/juxtapose/application/spec/spec_helper.rb
153
153
  - lib/juxtapose/application/views/index.html.haml
154
+ - lib/juxtapose/capybara.rb
155
+ - lib/juxtapose/rspec.rb
154
156
  - lib/juxtapose/screenshotter.rb
157
+ - lib/juxtapose/strategy/capybara_strategy.rb
155
158
  - lib/juxtapose/strategy/frank_strategy.rb
156
159
  - lib/juxtapose/strategy/mac_bacon_strategy.rb
157
160
  - lib/juxtapose/version.rb
158
161
  - lib/motion-juxtapose.rb
159
162
  - motion-juxtapose.gemspec
160
163
  - spec/controllers/test_controller_spec.rb
161
- - spec/screens/iphone-retina/ios_7.0.3/screenshot-testing-under-bacon-passes-when-there-is-an-identical-accepted-screenshot/accepted-screenshot/accepted.png
162
- - spec/screens/iphone-retina/ios_7.0.3/screenshot-testing-under-bacon-raises-an-error-and-produces-diffs-on-failure/going-to-differ-screenshot/accepted.png
163
- - spec/screens/iphone-retina/ios_7.0.3/screenshot-testing-under-bacon-raises-an-error-when-screens-are-different-sizes/different-sized-screenshot/accepted.png
164
+ - spec/screens/iphone-retina/ios_7.1/screenshot-testing-under-bacon-passes-when-there-is-an-identical-accepted-screenshot/accepted-screenshot/accepted.png
165
+ - spec/screens/iphone-retina/ios_7.1/screenshot-testing-under-bacon-raises-an-error-and-produces-diffs-on-failure/going-to-differ-screenshot/accepted.png
166
+ - spec/screens/iphone-retina/ios_7.1/screenshot-testing-under-bacon-raises-an-error-when-screens-are-different-sizes/different-sized-screenshot/accepted.png
164
167
  homepage: https://github.com/terriblelabs/motion-juxtapose
165
168
  licenses:
166
169
  - MIT
@@ -171,12 +174,12 @@ require_paths:
171
174
  - lib
172
175
  required_ruby_version: !ruby/object:Gem::Requirement
173
176
  requirements:
174
- - - '>='
177
+ - - ">="
175
178
  - !ruby/object:Gem::Version
176
179
  version: '0'
177
180
  required_rubygems_version: !ruby/object:Gem::Requirement
178
181
  requirements:
179
- - - '>='
182
+ - - ">="
180
183
  - !ruby/object:Gem::Version
181
184
  version: '0'
182
185
  requirements: []
@@ -187,6 +190,6 @@ specification_version: 4
187
190
  summary: Screenshot-based assertions for RubyMotion projects
188
191
  test_files:
189
192
  - spec/controllers/test_controller_spec.rb
190
- - spec/screens/iphone-retina/ios_7.0.3/screenshot-testing-under-bacon-passes-when-there-is-an-identical-accepted-screenshot/accepted-screenshot/accepted.png
191
- - spec/screens/iphone-retina/ios_7.0.3/screenshot-testing-under-bacon-raises-an-error-and-produces-diffs-on-failure/going-to-differ-screenshot/accepted.png
192
- - spec/screens/iphone-retina/ios_7.0.3/screenshot-testing-under-bacon-raises-an-error-when-screens-are-different-sizes/different-sized-screenshot/accepted.png
193
+ - spec/screens/iphone-retina/ios_7.1/screenshot-testing-under-bacon-passes-when-there-is-an-identical-accepted-screenshot/accepted-screenshot/accepted.png
194
+ - spec/screens/iphone-retina/ios_7.1/screenshot-testing-under-bacon-raises-an-error-and-produces-diffs-on-failure/going-to-differ-screenshot/accepted.png
195
+ - spec/screens/iphone-retina/ios_7.1/screenshot-testing-under-bacon-raises-an-error-when-screens-are-different-sizes/different-sized-screenshot/accepted.png