goggles 0.9.1 → 0.10.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 +4 -4
- data/.gitignore +20 -0
- data/.travis.yml +6 -0
- data/CHANGELOG.md +46 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +153 -0
- data/Rakefile +9 -0
- data/features/goggles.feature +23 -0
- data/features/step_definitions/goggles_steps.rb +27 -0
- data/features/support/env.rb +5 -0
- data/goggles.gemspec +28 -0
- data/lib/goggles.rb +62 -0
- data/lib/goggles/comparison.rb +186 -0
- data/lib/goggles/configuration.rb +37 -0
- data/lib/goggles/iteration.rb +64 -0
- data/lib/goggles/version.rb +3 -0
- data/spec/goggles/comparison_spec.rb +99 -0
- data/spec/goggles/configuration_spec.rb +54 -0
- data/spec/goggles/iteration_spec.rb +32 -0
- data/spec/goggles_spec.rb +133 -0
- data/spec/spec_helper.rb +2 -0
- metadata +33 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a461694240042737a93be6b6431a638bc7add76
|
4
|
+
data.tar.gz: 5651d5328ba134942e7f9e7a5d09a162b954c247
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 96a924a64413611a034f06bf262ed2f0123810c5b85c2c42b6204e318a5dc5f050320fe9e3dc0482ac277d3b1d6f836483cea151ae80f14cc541363c2910f113
|
7
|
+
data.tar.gz: d9f08ed3a405f18ff049d4491a22b28d6c9e120ff1dc32e2aca34323411f469ffd9ea9bbafa1ca89d66139111cba46e5e672043544c79c2fd8320c736070bba1
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# CHANGELOG
|
2
|
+
|
3
|
+
## v0.10.0 (Apr 16, 2015)
|
4
|
+
* Throw EmptyDirectoryError on iteration with unconfigured directory setting.
|
5
|
+
|
6
|
+
## v0.9.1 (Apr 14, 2015)
|
7
|
+
* Add YARD documentation.
|
8
|
+
|
9
|
+
## v0.9.0 (Apr 14, 2015)
|
10
|
+
* `Goggles.each` accepts Array, Integer, String, and Symbol arguments.
|
11
|
+
* Arguments passed to `Goggles.each` extend configured settings instead of replacing them.
|
12
|
+
* Add Cucumber tests.
|
13
|
+
|
14
|
+
## v0.8.2 (Apr 10, 2015)
|
15
|
+
* Fix another typo in the gem description.
|
16
|
+
|
17
|
+
## v0.8.1 (Apr 10, 2015)
|
18
|
+
* Fix typo in gem description.
|
19
|
+
|
20
|
+
## v0.8.0 (Apr 10, 2015)
|
21
|
+
* Remove `swim` executable.
|
22
|
+
* Remove YAML configuration.
|
23
|
+
* Add `Goggles.configure` for configuration through a block (like RSpec).
|
24
|
+
* Remove reserved instance variables like `@gg_url`.
|
25
|
+
* Scripts are executed via blocks passed to `Goggles.each`.
|
26
|
+
* `Goggles.each` yields a browser instance with the `#grab_screenshot` method.
|
27
|
+
* README updates.
|
28
|
+
* Add this CHANGELOG.
|
29
|
+
|
30
|
+
## v0.1.4 (Jan 28, 2014)
|
31
|
+
* Small code enhancements with no user impact.
|
32
|
+
|
33
|
+
## v0.1.3 (Jan 23, 2014)
|
34
|
+
* Do not delete cookies before each script.
|
35
|
+
* Make `@gg_url` variable available to scripts.
|
36
|
+
|
37
|
+
## v0.1.2 (Jan 21, 2014)
|
38
|
+
* Add diff color configuration setting.
|
39
|
+
* Default color setting to blue.
|
40
|
+
* Prepend all instance variables with `gg_`.
|
41
|
+
|
42
|
+
## v0.1.1 (Jan 20, 2014)
|
43
|
+
* Add command line option for generating default project
|
44
|
+
|
45
|
+
## v0.1.0 (Jan 20, 2014)
|
46
|
+
* Initial release
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Johnson Denen
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
# goggles
|
2
|
+
[](http://badge.fury.io/rb/goggles)
|
3
|
+
[](https://travis-ci.org/jdenen/goggles)
|
4
|
+
|
5
|
+
Goggles is a visual testing tool inspired by [wraith](http://github.com/bbc-news/wraith) and powered by [watir-webdriver](http://github.com/watir/watir-webdriver). It compares screenshots of your web applications in different browsers at differents sizes.
|
6
|
+
|
7
|
+
## Usage
|
8
|
+
|
9
|
+
### Configuration
|
10
|
+
|
11
|
+
Configure Goggles with a block passed to the `Goggles.configure` method, which will yield a config object to your block for manipulation. The `directory` setting must be configured for Goggles to work. You'll also need to provide `browsers` and `sizes` that you'd like to compare, but those can be configured with the script.
|
12
|
+
|
13
|
+
The `fuzzing` and `color` attributes default to "blue" and "20%" respectively.
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
Goggles.configure do |config|
|
17
|
+
config.directory = "/path/to/my/results"
|
18
|
+
config.browsers = [:chrome, :firefox, :phantomjs]
|
19
|
+
config.sizes = [1080, 600]
|
20
|
+
config.color = "red"
|
21
|
+
end
|
22
|
+
```
|
23
|
+
|
24
|
+
### Scripting
|
25
|
+
|
26
|
+
Your Scripts are passed to `Goggles.each` as blocks. Goggles will iterate over the block with each combination of browser/browser size configured, and the method will yield a browser object to your script block.
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
Goggles.each do |browser|
|
30
|
+
browser.goto "http://www.google.com"
|
31
|
+
browser.text_field(id: "lst-ib").value = "Google"
|
32
|
+
end
|
33
|
+
```
|
34
|
+
|
35
|
+
#### Browsers and sizes
|
36
|
+
|
37
|
+
You can pass additional browsers or browser sizes to `Goggles.each` as arrays. These arguments extend your configuration for this instance's script block only.
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
Goggles.configure do |c|
|
41
|
+
c.directory = "/some/directory"
|
42
|
+
c.browsers = [:chrome, :firefox]
|
43
|
+
c.sizes = [1080]
|
44
|
+
end
|
45
|
+
|
46
|
+
Goggles.each(:phantomjs, 500) do |browser|
|
47
|
+
# Script to be executed with Chrome, Firefox,
|
48
|
+
# and PhantomJS at widths of 1080 and 500.
|
49
|
+
end
|
50
|
+
|
51
|
+
Goggles.each do |browser|
|
52
|
+
# Script to be executed with Chrome and
|
53
|
+
# Firefox at a width of 1080.
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
#### Screenshots
|
58
|
+
|
59
|
+
Your script blocks should include the `Watir::Browser#grab_screenshot` method, which has been patched onto the browser objects yielded to your blocks. Simply give the method a description argument and the screenshot will be saved to your configured directory.
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
Goggles.each do |browser|
|
63
|
+
browser.goto "http://www.google.com"
|
64
|
+
browser.grab_screenshot "homepage"
|
65
|
+
end
|
66
|
+
```
|
67
|
+
|
68
|
+
#### Closing the browser
|
69
|
+
|
70
|
+
There's no need to explicitly close the browser objects in your script blocks. Goggles will handle that.
|
71
|
+
|
72
|
+
#### Results
|
73
|
+
|
74
|
+
Screenshots are saved to your configured directory. Screenshot comparison results are saved to a sub-folder based on the screenshot description and browser size. Results include a diff image and data file.
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
Goggles.configure do |c|
|
78
|
+
c.directory = "/goggles/results"
|
79
|
+
c.browsers = [:chrome, :firefox, :phantomjs]
|
80
|
+
c.sizes = [1080, 600]
|
81
|
+
end
|
82
|
+
|
83
|
+
Goggles.each do |browser|
|
84
|
+
browser.goto "http://www.google.com"
|
85
|
+
browser.grab_screenshot "google"
|
86
|
+
end
|
87
|
+
```
|
88
|
+
|
89
|
+
|
90
|
+
```
|
91
|
+
/goggles/results
|
92
|
+
|- google_1080_chrome.png
|
93
|
+
|- google_1080_firefox.png
|
94
|
+
|- google_1080_phantomjs.png
|
95
|
+
|- google_600_chrome.png
|
96
|
+
|- google_600_firefox.png
|
97
|
+
|- google_600_phantomjs.png
|
98
|
+
|- /google_1080
|
99
|
+
|- chrome_firefox_data.txt
|
100
|
+
|- chrome_firefox_diff.png
|
101
|
+
|- chrome_phantomjs_data.txt
|
102
|
+
|- chrome_phantomjs_diff.png
|
103
|
+
|- firefox_phantomjs_data.txt
|
104
|
+
|- firefox_phantomjs_diff.png
|
105
|
+
|- /google_600
|
106
|
+
|- chrome_firefox_data.txt
|
107
|
+
|- chrome_firefox_diff.png
|
108
|
+
|- chrome_phantomjs_data.txt
|
109
|
+
|- chrome_phantomjs_diff.png
|
110
|
+
|- firefox_phantomjs_data.txt
|
111
|
+
|- firefox_phantomjs_diff.png
|
112
|
+
```
|
113
|
+
|
114
|
+
## Road to 1.0.0
|
115
|
+
|
116
|
+
I've made a lot of changes recently and bumped the version up to 0.9.1. Check the [CHANGELOG](CHANGELOG.md) for more information about those changes.
|
117
|
+
|
118
|
+
### v1.0.0
|
119
|
+
|
120
|
+
* Documentation
|
121
|
+
* Examples
|
122
|
+
* TravisCI integration for specs (but not features)
|
123
|
+
|
124
|
+
## Installation
|
125
|
+
|
126
|
+
Install ImageMagick:
|
127
|
+
|
128
|
+
* OSX: `$ brew install imagemagick`
|
129
|
+
* Ubuntu: `$ sudo apt-get install imagemagick`
|
130
|
+
* Windows: [Download](http://www.imagemagick.org/script/binary-releases.php#windows) installer and add to your PATH.
|
131
|
+
|
132
|
+
Add this line to your application's Gemfile:
|
133
|
+
|
134
|
+
gem 'goggles'
|
135
|
+
|
136
|
+
And then execute:
|
137
|
+
|
138
|
+
$ bundle
|
139
|
+
|
140
|
+
Or install it yourself with:
|
141
|
+
|
142
|
+
$ gem install goggles
|
143
|
+
|
144
|
+
## Contributing
|
145
|
+
|
146
|
+
1. Fork it ( http://github.com/jdenen/goggles/fork )
|
147
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
148
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
149
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
150
|
+
5. Create new Pull Request
|
151
|
+
|
152
|
+
## Questions, Comments, Concerns
|
153
|
+
Find me on Twitter ([@jpdenen](http://twitter.com/jpdenen)) or write up an issue.
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Feature: Screenshot comparison
|
2
|
+
As a software professional
|
3
|
+
I want to automate the collection and comparison of screenshots on my application
|
4
|
+
So I can efficiently assess visual regression
|
5
|
+
|
6
|
+
Background:
|
7
|
+
Given I have configured Goggles with a valid directory
|
8
|
+
Given I have configured Goggles for browsers at 1080 width
|
9
|
+
|
10
|
+
Scenario: Compare screenshots in two browsers at one size
|
11
|
+
When I use "repo" to describe my screenshot of "github.com/jdenen/goggles"
|
12
|
+
Then file "repo_1080/chrome_firefox_diff.png" exists
|
13
|
+
And file "repo_1080/chrome_firefox_data.txt" exists
|
14
|
+
|
15
|
+
Scenario: Extending a script with more browsers and sizes
|
16
|
+
When I extend configuration with arguments "phantomjs, 500"
|
17
|
+
And I use "search" to describe my screenshot of "google.com"
|
18
|
+
Then file "search_1080/chrome_firefox_diff.png" exists
|
19
|
+
And file "search_1080/chrome_firefox_data.txt" exists
|
20
|
+
And file "search_1080/chrome_phantomjs_diff.png" exists
|
21
|
+
And file "search_1080/chrome_phantomjs_data.txt" exists
|
22
|
+
And file "search_1080/firefox_phantomjs_diff.png" exists
|
23
|
+
And file "search_1080/firefox_phantomjs_data.txt" exists
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Given /^I have configured Goggles with a valid directory$/ do
|
2
|
+
@results = Pathname.new("./results").realdirpath.to_s
|
3
|
+
Goggles.configure { |c| c.directory = @results }
|
4
|
+
end
|
5
|
+
|
6
|
+
Given /^I have configured Goggles for browsers at (\d+) width$/ do |width|
|
7
|
+
Goggles.configure do |c|
|
8
|
+
c.browsers = [:chrome, :firefox]
|
9
|
+
c.sizes = [width]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
When /^I extend configuration with arguments "(.*)"$/ do |args|
|
14
|
+
@args = args.split(/,/).map(&:strip)
|
15
|
+
end
|
16
|
+
|
17
|
+
When /^I use "(.*)" to describe my screenshot of "(.*)"$/ do |desc, site|
|
18
|
+
Goggles.each(@args) do |browser|
|
19
|
+
browser.goto "http://#{site}"
|
20
|
+
browser.grab_screenshot desc
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
Then /^file "(.*)" exists$/ do |file|
|
25
|
+
filepath = "#{@results}/#{file}"
|
26
|
+
File.exists? filepath
|
27
|
+
end
|
data/goggles.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'goggles/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "goggles"
|
8
|
+
spec.version = Goggles::VERSION
|
9
|
+
spec.authors = ["Johnson Denen"]
|
10
|
+
spec.email = ["johnson.denen@gmail.com"]
|
11
|
+
spec.summary = %q{Compare screenshots in different browsers at different sizes}
|
12
|
+
spec.description = %q{Compare screenshots in different browsers at different sizes}
|
13
|
+
spec.homepage = "http://github.com/jdenen/goggles"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
21
|
+
spec.add_development_dependency "rake"
|
22
|
+
spec.add_development_dependency "rspec"
|
23
|
+
spec.add_development_dependency "cucumber"
|
24
|
+
spec.add_development_dependency "yard"
|
25
|
+
|
26
|
+
spec.add_runtime_dependency "watir-webdriver"
|
27
|
+
spec.add_runtime_dependency "image_size"
|
28
|
+
end
|
data/lib/goggles.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require "goggles/configuration"
|
2
|
+
require "goggles/comparison"
|
3
|
+
require "goggles/iteration"
|
4
|
+
|
5
|
+
module Goggles
|
6
|
+
extend self
|
7
|
+
|
8
|
+
#
|
9
|
+
# Raise when the configuration attribute is unconfigured at runtime.
|
10
|
+
#
|
11
|
+
class EmptyDirectoryError < StandardError; end
|
12
|
+
|
13
|
+
#
|
14
|
+
# Yields the global configuration object to a block.
|
15
|
+
#
|
16
|
+
# @yield [Goggles::Configuration] global configuration
|
17
|
+
# @return [Goggles::Configuration] global configuration
|
18
|
+
#
|
19
|
+
def configure &block
|
20
|
+
configuration.tap { |conf| yield conf }
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# Creates an Iteration object for each combination of browser and width derived from global
|
25
|
+
# configuration and given arguments.
|
26
|
+
#
|
27
|
+
# @param instance [Array<String,Fixnum,Symbol>, String, Fixnum, Symbol] configuration extension
|
28
|
+
# @return [Goggles::Comparison]
|
29
|
+
# @see Goggles::Iteration
|
30
|
+
#
|
31
|
+
def each *instance, &block
|
32
|
+
validate_directory_setting
|
33
|
+
args = instance.flatten.map(&:to_s)
|
34
|
+
|
35
|
+
sizes = configuration.sizes + args.grep(/\d+/).map(&:to_i)
|
36
|
+
browsers = configuration.browsers + args.grep(/[^\d+]/).map(&:to_sym)
|
37
|
+
|
38
|
+
browsers.product(sizes).each do |browser, size|
|
39
|
+
Iteration.new browser, size, configuration, &block
|
40
|
+
end
|
41
|
+
|
42
|
+
Comparison.new(configuration).tap { |comparison| comparison.make! }
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
#
|
48
|
+
# @api private
|
49
|
+
#
|
50
|
+
def configuration
|
51
|
+
@configuration ||= Configuration.new
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# @api private
|
56
|
+
#
|
57
|
+
def validate_directory_setting
|
58
|
+
message = "Expected configured directory setting, got: #{configuration.directory}"
|
59
|
+
raise EmptyDirectoryError, message if configuration.directory.nil?
|
60
|
+
raise EmptyDirectoryError, message if configuration.directory.empty?
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
require "image_size"
|
2
|
+
|
3
|
+
module Goggles
|
4
|
+
|
5
|
+
#
|
6
|
+
# Generates a diff image and data file from two images.
|
7
|
+
#
|
8
|
+
# Results are saved to a new directory derived from the configured directory setting,
|
9
|
+
# a description given to `Watir::Browser.grab_screenshot`, browser size, and the
|
10
|
+
# browsers used to take the screenshots.
|
11
|
+
#
|
12
|
+
# @example Results
|
13
|
+
# Goggles.configure do |c|
|
14
|
+
# c.directory = "/path/results"
|
15
|
+
# c.browsers = [:chrome, :firefox]
|
16
|
+
# c.sizes = [100]
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# Goggles.each do |b|
|
20
|
+
# b.goto "www.google.com"
|
21
|
+
# b.grab_screenshot "search"
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# #=> /path/results
|
25
|
+
# # |- /search_100
|
26
|
+
# # |- chrome_firefox_data.txt
|
27
|
+
# # |- chrome_firefox_diff.png
|
28
|
+
#
|
29
|
+
class Comparison
|
30
|
+
attr_reader :directory, :fuzzing, :color, :groups, :results_dir
|
31
|
+
|
32
|
+
def initialize config
|
33
|
+
@directory = config.directory
|
34
|
+
@fuzzing = config.fuzzing
|
35
|
+
@color = config.color
|
36
|
+
@groups = config.groups
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# Sizes and compare screenshots.
|
41
|
+
#
|
42
|
+
# @return [nil]
|
43
|
+
#
|
44
|
+
def make!
|
45
|
+
cut_to_common_size
|
46
|
+
highlight_differences
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# Sizes comparable screenshots to a common height and width.
|
51
|
+
#
|
52
|
+
# @return [nil]
|
53
|
+
#
|
54
|
+
def cut_to_common_size
|
55
|
+
groups.each_with_object([]) do |group, sizes|
|
56
|
+
collection = find_comparable group
|
57
|
+
|
58
|
+
collection.each do |img|
|
59
|
+
File.open(img, 'rb'){ |file| sizes << read_size(file) }
|
60
|
+
end
|
61
|
+
|
62
|
+
cut! collection, sizes
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# Generates diff images for comparable screenshots.
|
68
|
+
#
|
69
|
+
# @return [nil]
|
70
|
+
#
|
71
|
+
def highlight_differences
|
72
|
+
groups.each do |desc|
|
73
|
+
ensure_result_directory desc
|
74
|
+
find_comparable(desc).combination(2).to_a.each { |imgs| diff imgs[0], imgs[1] }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Finds comparable screenshots for sizing and comparing.
|
80
|
+
#
|
81
|
+
# @param description [String] screenshot description
|
82
|
+
# @return [Array<String>] paths to comparable screenshots
|
83
|
+
#
|
84
|
+
def find_comparable description
|
85
|
+
Dir.glob("#{directory}/*.png").grep(/#{description}_/).sort
|
86
|
+
end
|
87
|
+
|
88
|
+
#
|
89
|
+
# Finds the smallest first element for all arrays in the given array. This is
|
90
|
+
# the screenshot width attribute. Used for resizing.
|
91
|
+
#
|
92
|
+
# @param array [Array<Array>] collection of screenshot sizes
|
93
|
+
# @return [Fixnum] smallest width
|
94
|
+
#
|
95
|
+
def find_common_width array
|
96
|
+
array.collect(&:first).sort.first
|
97
|
+
end
|
98
|
+
|
99
|
+
#
|
100
|
+
# Finds the smallest second element for all arrays in the given array. This is
|
101
|
+
# the screenshot height attribute. Used for resizing.
|
102
|
+
#
|
103
|
+
# @param array [Array<Array>] collection of screenshot sizes
|
104
|
+
# @return [Fixnum] smallest screenshot height
|
105
|
+
#
|
106
|
+
def find_common_height array
|
107
|
+
array.collect(&:last).sort.first
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
attr_writer :results_dir
|
113
|
+
|
114
|
+
#
|
115
|
+
# @api private
|
116
|
+
#
|
117
|
+
# Cuts comparable screenshots to smallest width by smallest height with ImageMagick.
|
118
|
+
#
|
119
|
+
# @param images [Array<String>] comparable screenshots
|
120
|
+
# @param sizes [Array<Fixnum>] sizes (width, height) of comparable screenshots
|
121
|
+
# @return [nil]
|
122
|
+
#
|
123
|
+
def cut! images, sizes
|
124
|
+
w = find_common_width sizes
|
125
|
+
h = find_common_height sizes
|
126
|
+
images.each { |img| `convert #{img} -background none -extent #{w}x#{h} #{img}` }
|
127
|
+
end
|
128
|
+
|
129
|
+
#
|
130
|
+
# @api private
|
131
|
+
#
|
132
|
+
# Generates comparison data for two screenshots with ImageMagick.
|
133
|
+
#
|
134
|
+
# @param img_one [String] first screenshot path
|
135
|
+
# @param img_two [String] second screenshot path
|
136
|
+
# @return [nil]
|
137
|
+
#
|
138
|
+
def diff img_one, img_two
|
139
|
+
b1 = diffed img_one
|
140
|
+
b2 = diffed img_two
|
141
|
+
|
142
|
+
fuzz = "#{results_dir}/#{b1}_#{b2}_diff.png"
|
143
|
+
data = "#{results_dir}/#{b1}_#{b2}_data.txt"
|
144
|
+
|
145
|
+
`compare -fuzz #{fuzzing} -metric AE -highlight-color #{color} #{img_one} #{img_two} #{fuzz} 2>#{data}`
|
146
|
+
end
|
147
|
+
|
148
|
+
#
|
149
|
+
# @api private
|
150
|
+
#
|
151
|
+
# Parses a browser from a screenshot filepath.
|
152
|
+
#
|
153
|
+
# @param img [String] screenshot path
|
154
|
+
# @return [String] browser
|
155
|
+
#
|
156
|
+
def diffed img
|
157
|
+
File.basename(img).match(/\d+_(.*)\.png/)[1]
|
158
|
+
end
|
159
|
+
|
160
|
+
#
|
161
|
+
# @api private
|
162
|
+
#
|
163
|
+
# Finds the width and height of an image.
|
164
|
+
#
|
165
|
+
# @param file [File] image
|
166
|
+
# @return [Array<Fixnum>] width and height
|
167
|
+
#
|
168
|
+
def read_size file
|
169
|
+
ImageSize.new(file.read).size
|
170
|
+
end
|
171
|
+
|
172
|
+
#
|
173
|
+
# @api private
|
174
|
+
#
|
175
|
+
# Ensures the results directory for comparable screenshots exists.
|
176
|
+
#
|
177
|
+
# @param description [String] screenshot description
|
178
|
+
# @return [nil]
|
179
|
+
#
|
180
|
+
def ensure_result_directory description
|
181
|
+
self.results_dir = "#{directory}/#{description}"
|
182
|
+
FileUtils.rm_rf results_dir
|
183
|
+
FileUtils.mkdir_p results_dir
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Goggles
|
2
|
+
|
3
|
+
#
|
4
|
+
# Stores configuration information for runtime.
|
5
|
+
#
|
6
|
+
# The `directory` setting +must+ be configured.
|
7
|
+
#
|
8
|
+
# The `browsers` and `sizes` settings can be extended through `Goggles.each` as arguments.
|
9
|
+
#
|
10
|
+
# @see Goggles.each
|
11
|
+
# @see Goggles.configure
|
12
|
+
#
|
13
|
+
class Configuration
|
14
|
+
attr_accessor :browsers, :sizes, :fuzzing, :color, :groups
|
15
|
+
attr_reader :directory
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@browsers = []
|
19
|
+
@sizes = []
|
20
|
+
@groups = []
|
21
|
+
@directory = ""
|
22
|
+
@color = "blue"
|
23
|
+
@fuzzing = "20%"
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Ensures the configured path exists, but otherwise acts as a normal
|
28
|
+
# attr_accessor. Path argument must be an absolute path.
|
29
|
+
#
|
30
|
+
# @param path [String] directory path
|
31
|
+
#
|
32
|
+
def directory=(path)
|
33
|
+
@directory = path
|
34
|
+
FileUtils.mkdir_p path unless path.nil? or path.empty?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require "watir-webdriver"
|
2
|
+
|
3
|
+
module Watir
|
4
|
+
class Browser
|
5
|
+
attr_accessor :goggles, :iteration
|
6
|
+
|
7
|
+
#
|
8
|
+
# Saves a screenshot as "given-description_width.png" in the configured results
|
9
|
+
# directory.
|
10
|
+
#
|
11
|
+
# @param name [String] screenshot description
|
12
|
+
# @return [nil]
|
13
|
+
#
|
14
|
+
def grab_screenshot name
|
15
|
+
description = "#{name}_#{iteration.size}"
|
16
|
+
goggles.groups << description unless goggles.groups.include? description
|
17
|
+
screenshot.save "#{goggles.directory}/#{description}_#{iteration.browser_name}.png"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module Goggles
|
23
|
+
|
24
|
+
#
|
25
|
+
# Executes the block passed to `Goggles.each` with every configured combination of browser
|
26
|
+
# and browser size.
|
27
|
+
#
|
28
|
+
# @see Goggles.each
|
29
|
+
#
|
30
|
+
class Iteration
|
31
|
+
attr_reader :browser, :browser_name, :size, :config
|
32
|
+
|
33
|
+
#
|
34
|
+
# Creates a script iteration instance, building yielded browser object from the
|
35
|
+
# given arguments. Closes the browser instance after yielding to the block.
|
36
|
+
#
|
37
|
+
# @param driver [String, Symbol] browser name
|
38
|
+
# @param width [Fixnum] browser width
|
39
|
+
# @param config [Goggles::Configuration] global configuration
|
40
|
+
# @yield [Watir::Browser] browser object
|
41
|
+
#
|
42
|
+
def initialize driver, width, config, &block
|
43
|
+
@browser_name = driver
|
44
|
+
@config = config
|
45
|
+
@size = width
|
46
|
+
build_browser
|
47
|
+
yield browser
|
48
|
+
browser.close
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
#
|
54
|
+
# @api private
|
55
|
+
#
|
56
|
+
def build_browser
|
57
|
+
@browser = Watir::Browser.new(browser_name).tap do |engine|
|
58
|
+
engine.goggles = config
|
59
|
+
engine.iteration = self
|
60
|
+
engine.driver.manage.window.resize_to size, 768
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Goggles::Comparison do
|
4
|
+
let(:config){ instance_double "configuration" }
|
5
|
+
let(:comparison){ Goggles::Comparison.new config }
|
6
|
+
|
7
|
+
before do
|
8
|
+
allow(config).to receive_messages(
|
9
|
+
directory: "dir",
|
10
|
+
fuzzing: "20%",
|
11
|
+
color: "blue",
|
12
|
+
groups: [1])
|
13
|
+
end
|
14
|
+
|
15
|
+
it "reads attributes from a given configuration object" do
|
16
|
+
expect(config).to receive(:directory)
|
17
|
+
expect(config).to receive(:fuzzing)
|
18
|
+
expect(config).to receive(:color)
|
19
|
+
Goggles::Comparison.new config
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#make!" do
|
23
|
+
it "cuts images and highlights their differences" do
|
24
|
+
expect(comparison).to receive(:cut_to_common_size)
|
25
|
+
expect(comparison).to receive(:highlight_differences)
|
26
|
+
comparison.make!
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#cut_to_common_size" do
|
31
|
+
it "iterates over screenshot descriptions" do
|
32
|
+
groups = instance_double "[groups]"
|
33
|
+
expect(comparison).to receive(:groups).and_return groups
|
34
|
+
expect(groups).to receive(:each_with_object).with([])
|
35
|
+
comparison.cut_to_common_size
|
36
|
+
end
|
37
|
+
|
38
|
+
it "collects comparable screenshots" do
|
39
|
+
expect(comparison).to receive(:groups).and_return [1, 2]
|
40
|
+
expect(comparison).to receive(:find_comparable).with(1).and_return([])
|
41
|
+
expect(comparison).to receive(:find_comparable).with(2).and_return([])
|
42
|
+
comparison.cut_to_common_size
|
43
|
+
end
|
44
|
+
|
45
|
+
context "with collection of comparable screenshots" do
|
46
|
+
it "iterates over the collection" do
|
47
|
+
screens = instance_double "[screenshots]"
|
48
|
+
expect(comparison).to receive(:groups).and_return ["foo"]
|
49
|
+
expect(comparison).to receive(:find_comparable).and_return screens
|
50
|
+
expect(screens).to receive(:each)
|
51
|
+
expect(comparison).to receive(:cut!).with(screens, [])
|
52
|
+
comparison.cut_to_common_size
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "while iterating over collected comparable images" do
|
57
|
+
it "opens each image in binary mode" do
|
58
|
+
expect(comparison).to receive(:find_comparable).and_return [:foo]
|
59
|
+
expect(File).to receive(:open).with(:foo, 'rb')
|
60
|
+
expect(comparison).to receive(:cut!)
|
61
|
+
comparison.cut_to_common_size
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#highlight_differences" do
|
67
|
+
it "diffs every combination of comparable screenshots" do
|
68
|
+
images = ["foo_1.png", "foo_2.png", "foo_3.png"]
|
69
|
+
expect(comparison).to receive(:groups).and_return ["foo"]
|
70
|
+
expect(comparison).to receive(:find_comparable).with("foo").and_return images
|
71
|
+
images.combination(2).to_a.each do |i|
|
72
|
+
expect(comparison).to receive(:diff).with i[0], i[1]
|
73
|
+
end
|
74
|
+
comparison.highlight_differences
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "#find_comparable" do
|
79
|
+
it "returns an array of file paths" do
|
80
|
+
array = ["/foo_chrome.png", "/bar_chrome.png", "/foo_ff.png", "/bar_ff.png"]
|
81
|
+
expect(Dir).to receive(:glob).and_return array
|
82
|
+
expect(comparison.find_comparable "foo").to eq ["/foo_chrome.png", "/foo_ff.png"]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#find_common_width" do
|
87
|
+
it "returns the smallest number from first items in an array of arrays" do
|
88
|
+
arrays = [[100,40], [68,300], [104,98]]
|
89
|
+
expect(comparison.find_common_width arrays).to eq 68
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "#find_common_height" do
|
94
|
+
it "returns the smallest number from second items in an array of arrays" do
|
95
|
+
arrays = [[100,40], [68,300], [104,98]]
|
96
|
+
expect(comparison.find_common_height arrays).to eq 40
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Goggles::Configuration do
|
4
|
+
let(:config) { Goggles::Configuration.new }
|
5
|
+
|
6
|
+
it "has attributes by default" do
|
7
|
+
expect(config).to have_attributes(
|
8
|
+
:browsers => [],
|
9
|
+
:sizes => [],
|
10
|
+
:groups => [],
|
11
|
+
:directory => "",
|
12
|
+
:color => "blue",
|
13
|
+
:fuzzing => "20%"
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "has attributes that can be set" do
|
18
|
+
config.browsers << "chrome"
|
19
|
+
config.sizes << 100
|
20
|
+
config.groups << "foo"
|
21
|
+
config.color = "red"
|
22
|
+
config.fuzzing = "10%"
|
23
|
+
|
24
|
+
expect(config).to have_attributes(
|
25
|
+
:browsers => ["chrome"],
|
26
|
+
:sizes => [100],
|
27
|
+
:groups => ["foo"],
|
28
|
+
:color => "red",
|
29
|
+
:fuzzing => "10%"
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#directory=" do
|
34
|
+
it "ensures the directory exists" do
|
35
|
+
expect(FileUtils).to receive(:mkdir_p).with "/foo/bar"
|
36
|
+
config.directory = "/foo/bar"
|
37
|
+
expect(config.directory).to eq "/foo/bar"
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when attribute is empty" do
|
41
|
+
it "does not create the directory" do
|
42
|
+
expect(FileUtils).to_not receive(:mkdir_p)
|
43
|
+
config.directory = ""
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "when attribute is nil" do
|
48
|
+
it "does not create the directory" do
|
49
|
+
expect(FileUtils).to_not receive(:mkdir_p)
|
50
|
+
config.directory = nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Goggles::Iteration do
|
4
|
+
let(:watir) { instance_double("browser") }
|
5
|
+
|
6
|
+
before do
|
7
|
+
allow(watir).to receive_messages(
|
8
|
+
:driver => watir,
|
9
|
+
:manage => watir,
|
10
|
+
:window => watir,
|
11
|
+
:goggles= => nil,
|
12
|
+
:iteration= => nil,
|
13
|
+
:resize_to => nil,
|
14
|
+
:close => nil)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "yields an instantiated browser" do
|
18
|
+
expect(Watir::Browser).to receive(:new).and_return watir
|
19
|
+
expect { |b| Goggles::Iteration.new "", "", "", &b }.to yield_with_args watir
|
20
|
+
end
|
21
|
+
|
22
|
+
it "yields the browser based on the browser_name attribute" do
|
23
|
+
expect(Watir::Browser).to receive(:new).with(:foo).and_return watir
|
24
|
+
Goggles::Iteration.new(:foo, "", ""){ "bar" }
|
25
|
+
end
|
26
|
+
|
27
|
+
it "resizes the browser based on the size attribute" do
|
28
|
+
expect(Watir::Browser).to receive(:new).with(:foo).and_return watir
|
29
|
+
expect(watir).to receive(:resize_to).with(500, 768)
|
30
|
+
Goggles::Iteration.new(:foo, 500, ""){ "bar" }
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Goggles do
|
4
|
+
before { allow(FileUtils).to receive(:mkdir_p) }
|
5
|
+
|
6
|
+
describe ".configure" do
|
7
|
+
it "yields a configuration object" do
|
8
|
+
expect { |b| Goggles.configure &b }.to yield_with_args Goggles::Configuration
|
9
|
+
end
|
10
|
+
|
11
|
+
it "returns a configuration object" do
|
12
|
+
expect(Goggles.configure { "foo" }).to be_a Goggles::Configuration
|
13
|
+
end
|
14
|
+
|
15
|
+
it "memoizes the configuration object" do
|
16
|
+
expect(Goggles.configure { "foo" }).to equal Goggles.configure { "bar" }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe ".each" do
|
21
|
+
let(:config) do
|
22
|
+
Goggles.configure do |conf|
|
23
|
+
conf.browsers = [:foo]
|
24
|
+
conf.sizes = [500]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
before do
|
29
|
+
allow(config).to receive_messages(directory: "/dir", fuzzing: "20%", color: "blue", groups: [])
|
30
|
+
end
|
31
|
+
|
32
|
+
it "passes browser, width, and configuration to an iteration object" do
|
33
|
+
expect(Goggles::Iteration).to receive(:new).with(:foo, 500, config)
|
34
|
+
Goggles.each { "foo" }
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when directory setting is nil" do
|
38
|
+
it "throws an EmptyDirectoryError" do
|
39
|
+
allow(config).to receive(:directory).and_return(nil)
|
40
|
+
expect do
|
41
|
+
Goggles.each { "foo" }
|
42
|
+
end.to raise_error(Goggles::EmptyDirectoryError)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "when directory setting is empty" do
|
47
|
+
it "throws an EmptyDirectoryError" do
|
48
|
+
allow(config).to receive(:directory).and_return("")
|
49
|
+
expect do
|
50
|
+
Goggles.each { "foo" }
|
51
|
+
end.to raise_error(Goggles::EmptyDirectoryError)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context "when given a browser argument" do
|
56
|
+
it "extends the configured browser list with the given browser" do
|
57
|
+
expect(Goggles::Iteration).to receive(:new).with(:foo, 500, config)
|
58
|
+
expect(Goggles::Iteration).to receive(:new).with(:bar, 500, config)
|
59
|
+
Goggles.each(:bar) { "foo" }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context "when given a size argument" do
|
64
|
+
it "extends the configured size list with the given size" do
|
65
|
+
expect(Goggles::Iteration).to receive(:new).with(:foo, 500, config)
|
66
|
+
expect(Goggles::Iteration).to receive(:new).with(:foo, 250, config)
|
67
|
+
Goggles.each(250) { "foo" }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "when given multiple browser and size arguments" do
|
72
|
+
it "extends the configuration with correctly" do
|
73
|
+
[:foo, :bar, :baz].product([500, 1000, 250]).each do |b, s|
|
74
|
+
expect(Goggles::Iteration).to receive(:new).with(b, s, config)
|
75
|
+
end
|
76
|
+
Goggles.each(:bar, :baz, 1000, 250) { "foo" }
|
77
|
+
end
|
78
|
+
|
79
|
+
context "in no particular order" do
|
80
|
+
it "extends the configuration with the correct arguments" do
|
81
|
+
[:foo, :bar, :baz].product([500, 1000, 250]).each do |b, s|
|
82
|
+
expect(Goggles::Iteration).to receive(:new).with(b, s, config)
|
83
|
+
end
|
84
|
+
Goggles.each(1000, :bar, :baz, 250) { "foo" }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context "when given arguments in arrays" do
|
90
|
+
it "extends the configuration correctly" do
|
91
|
+
[:foo, :bar, :baz].product([500, 1000, 250]).each do |b, s|
|
92
|
+
expect(Goggles::Iteration).to receive(:new).with(b, s, config)
|
93
|
+
end
|
94
|
+
Goggles.each([:bar, :baz], [250, 1000]) { "foo" }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context "when given arguments of various classes" do
|
99
|
+
it "extends the configuration correctly" do
|
100
|
+
[:foo, :bar, :baz].product([500, 1000, 250]).each do |b, s|
|
101
|
+
expect(Goggles::Iteration).to receive(:new).with(b, s, config)
|
102
|
+
end
|
103
|
+
Goggles.each([:bar, "baz"], 250, "1000") { "foo" }
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
it "returns a comparison object" do
|
108
|
+
expect(Goggles::Iteration).to receive(:new).with(:foo, 500, config)
|
109
|
+
expect(Goggles.each { "foo" }).to be_a Goggles::Comparison
|
110
|
+
end
|
111
|
+
|
112
|
+
context "when configured for browsers at one size" do
|
113
|
+
it "creates an iteration for each browser with the width" do
|
114
|
+
config.browsers << :bar
|
115
|
+
[:foo, :bar].each { |browser| expect(Goggles::Iteration).to receive(:new).with browser, 500, config }
|
116
|
+
Goggles.each { "foo" }
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context "when configured for browsers at different sizes" do
|
121
|
+
it "creates an iteration for every browser and width combination" do
|
122
|
+
config.browsers << :bar
|
123
|
+
config.sizes << 1000
|
124
|
+
|
125
|
+
[:foo, :bar].product([500, 1000]).each do |browser, width|
|
126
|
+
expect(Goggles::Iteration).to receive(:new).with browser, width, Object
|
127
|
+
end
|
128
|
+
|
129
|
+
Goggles.each { "foo" }
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: goggles
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Johnson Denen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -114,7 +114,28 @@ email:
|
|
114
114
|
executables: []
|
115
115
|
extensions: []
|
116
116
|
extra_rdoc_files: []
|
117
|
-
files:
|
117
|
+
files:
|
118
|
+
- .gitignore
|
119
|
+
- .travis.yml
|
120
|
+
- CHANGELOG.md
|
121
|
+
- Gemfile
|
122
|
+
- LICENSE.txt
|
123
|
+
- README.md
|
124
|
+
- Rakefile
|
125
|
+
- features/goggles.feature
|
126
|
+
- features/step_definitions/goggles_steps.rb
|
127
|
+
- features/support/env.rb
|
128
|
+
- goggles.gemspec
|
129
|
+
- lib/goggles.rb
|
130
|
+
- lib/goggles/comparison.rb
|
131
|
+
- lib/goggles/configuration.rb
|
132
|
+
- lib/goggles/iteration.rb
|
133
|
+
- lib/goggles/version.rb
|
134
|
+
- spec/goggles/comparison_spec.rb
|
135
|
+
- spec/goggles/configuration_spec.rb
|
136
|
+
- spec/goggles/iteration_spec.rb
|
137
|
+
- spec/goggles_spec.rb
|
138
|
+
- spec/spec_helper.rb
|
118
139
|
homepage: http://github.com/jdenen/goggles
|
119
140
|
licenses:
|
120
141
|
- MIT
|
@@ -139,5 +160,13 @@ rubygems_version: 2.0.14
|
|
139
160
|
signing_key:
|
140
161
|
specification_version: 4
|
141
162
|
summary: Compare screenshots in different browsers at different sizes
|
142
|
-
test_files:
|
163
|
+
test_files:
|
164
|
+
- features/goggles.feature
|
165
|
+
- features/step_definitions/goggles_steps.rb
|
166
|
+
- features/support/env.rb
|
167
|
+
- spec/goggles/comparison_spec.rb
|
168
|
+
- spec/goggles/configuration_spec.rb
|
169
|
+
- spec/goggles/iteration_spec.rb
|
170
|
+
- spec/goggles_spec.rb
|
171
|
+
- spec/spec_helper.rb
|
143
172
|
has_rdoc:
|