goggles 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ *.png
4
+ *_data.txt
5
+ .bundle
6
+ .config
7
+ .yardoc
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ test/tmp
18
+ test/version_tmp
19
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in goggles.gemspec
4
+ gemspec
@@ -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.
@@ -0,0 +1,86 @@
1
+ # goggles
2
+
3
+ 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 allows you to compare screenshots of your web application in different browsers, and you can execute Ruby scripts to setup as many screenshots as you need.
4
+
5
+ ## Installation
6
+
7
+ Install ImageMagick:
8
+
9
+ * OSX: `$ brew install imagemagick`
10
+ * Linux: `$ sudo apt-get install imagemagick`
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ gem 'goggles'
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself with:
21
+
22
+ $ gem install goggles
23
+
24
+ ## Usage
25
+
26
+ Create a config file to point goggles in the right direction.
27
+ ``` yaml
28
+ # config.yaml
29
+ # Directory where you want to store your results. Required.
30
+ results_directory: "/home/results"
31
+
32
+ # Directory where you're storing your scripts. Optional.
33
+ scripts_directory: "/home/scripts"
34
+
35
+ # Scripts to execute in the scripts directory. Optional.
36
+ scripts_to_execute:
37
+ - "search.rb"
38
+ - "login.rb"
39
+
40
+ # Domain to test. Required.
41
+ domain_under_test: "http://www.manta.com"
42
+
43
+ # Paths to pages you want to test. Label them with a page name. Required.
44
+ paths_to_capture:
45
+ home: "/"
46
+ search: "/mb"
47
+
48
+ # Browsers you want to compare. Cannot specify more than two (yet). Required.
49
+ browsers:
50
+ - "chrome"
51
+ - "firefox"
52
+
53
+ # Widths at which you would like screenshots compared. All screenshots will be taken at a height of 768. Required.
54
+ browser_widths:
55
+ - 1024
56
+ - 600
57
+ - 320
58
+
59
+ # Fuzzing percentage. Play around with this to find the right fit. Required.
60
+ image_fuzzing: "20%"
61
+ ```
62
+
63
+ If you pass scripts to goggles as part of your testing, you **must** specify when screenshots should be taken with the `#grab_screenshot` method. Otherwise, goggles will open each of your paths and take a screenshot.
64
+
65
+ NOTE: I've tried to keep variable names as unlikely to interrupt your code as possible, but `@watir` is reserved for the browser instance currently executing scripts.
66
+
67
+ ``` ruby
68
+ # script_to_execute.rb
69
+ require 'goggles'
70
+ @watir.cookies.add("cookie_name", "cookie_value")
71
+
72
+ # Pass a short description to the method for naming the resultant screenshot
73
+ Goggles.grab_screenshot("with_cookie_set")
74
+ ```
75
+
76
+ Execute a goggles test through the command line with `swim --config CONFIG_FILE` or use `swim --help` to see command options.
77
+
78
+ $ swim -c config.yml
79
+
80
+ ## Contributing
81
+
82
+ 1. Fork it ( http://github.com/jdenen/goggles/fork )
83
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
84
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
85
+ 4. Push to the branch (`git push origin my-new-feature`)
86
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'goggles/cli'
4
+
5
+ Goggles::CLI.new ARGV
@@ -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 = ["jdenen@manta.com"]
11
+ spec.summary = %q{comparing responsive screenshots under watir-webdriver}
12
+ spec.description = %q{comparing responsive screenshots under watir-webdriver}
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
+
24
+ spec.add_runtime_dependency "watir-webdriver"
25
+ spec.add_runtime_dependency "image_size"
26
+
27
+ spec.executables << "swim"
28
+ end
@@ -0,0 +1,80 @@
1
+ require "goggles/version"
2
+ require "goggles/comparison"
3
+ require "goggles/scripter"
4
+ require "goggles/error"
5
+
6
+ require "watir-webdriver"
7
+ require "yaml"
8
+ require "fileutils"
9
+
10
+ module Goggles
11
+ extend self
12
+
13
+ def swim(config_path)
14
+ conf = YAML::load(File.open(config_path))
15
+
16
+ @goggles_result_dir = conf['results_directory']
17
+ @goggles_script_dir = conf['scripts_directory']
18
+ @goggles_domain = conf['domain_under_test']
19
+ @goggles_paths = conf['paths_to_capture']
20
+ @goggles_scripts = conf['scripts_to_execute']
21
+ @goggles_platforms = conf['browsers']
22
+ @goggles_widths = conf['browser_widths']
23
+ @goggles_fuzz = conf['image_fuzzing']
24
+
25
+ embark!
26
+ diff_images
27
+ end
28
+
29
+ def grab_screenshot(detail)
30
+ make_result_dir
31
+
32
+ image_dir = "#{@goggles_result_dir}/#{@gg_label}"
33
+ image_name = "#{detail}_#{@gg_size}_#{@gg_browser}"
34
+
35
+ @watir.screenshot.save "#{image_dir}/#{image_name}.png"
36
+ end
37
+
38
+ private
39
+
40
+ def embark!
41
+ ensure_fresh_start
42
+
43
+ @goggles_widths.each do |size|
44
+ @gg_size = size.to_i
45
+
46
+ @goggles_platforms.each do |pf|
47
+ @gg_browser = pf
48
+
49
+ @watir = Watir::Browser.new pf.to_sym
50
+ @watir.driver.manage.window.resize_to(@gg_size, 768)
51
+
52
+ @goggles_paths.each do |label, path|
53
+ @gg_label = label
54
+ url = "#{@goggles_domain}#{path}"
55
+
56
+ if @goggles_scripts.nil?
57
+ @watir.goto url
58
+ grab_screenshot("screenshot")
59
+ else
60
+ @goggles_scripts.each do |script|
61
+ script = "#{@goggles_script_dir}/#{script}"
62
+ execute_script(url, script)
63
+ end
64
+ end
65
+ end
66
+
67
+ @watir.close
68
+ end
69
+ end
70
+ end
71
+
72
+ def ensure_fresh_start
73
+ FileUtils.rm_rf("#{@goggles_result_dir}")
74
+ end
75
+
76
+ def make_result_dir
77
+ FileUtils.mkdir_p("#{@goggles_result_dir}/#{@gg_label}")
78
+ end
79
+
80
+ end
@@ -0,0 +1,38 @@
1
+ require 'goggles'
2
+ require 'optparse'
3
+
4
+ module Goggles
5
+ class CLI
6
+
7
+ def initialize(argv)
8
+ opt_parser = OptionParser.new do |opts|
9
+ opts.banner = "Goggles: Compare responsive screenshots in multiple browsers"
10
+ opts.separator ""
11
+ opts.separator "Options"
12
+
13
+ opts.on("-c", "--config CONFIG_FILE", "configuration to execute") do |config|
14
+ run_conf(config)
15
+ end
16
+
17
+ opts.on("-v", "--version", "Goggles::VERSION") do
18
+ puts Goggles::VERSION
19
+ end
20
+
21
+ opts.on("-h", "--help", "help text") do
22
+ puts opt_parser
23
+ end
24
+ end
25
+
26
+ opt_parser.parse!
27
+ end
28
+
29
+ def run_conf(config)
30
+ if File.exists? config
31
+ Goggles.swim config
32
+ else
33
+ puts "Not a valid configuration file: #{config}"
34
+ end
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,75 @@
1
+ require "image_size"
2
+
3
+ module Goggles
4
+
5
+ def diff_images
6
+ size_to_smallest!
7
+
8
+ images = Dir.glob("#{@goggles_result_dir}/*/*.png").sort
9
+
10
+ raise Goggles::EmptyResultError, "No screenshots found in results directory: #{@goggles_result_dir}" if images.empty?
11
+
12
+ until images.empty?
13
+ one = images.slice!(0)
14
+ two = images.slice!(0)
15
+
16
+ out_path = one.dup
17
+ discard = out_path.slice!(/[^_]*$/)
18
+
19
+ diff_out = "#{out_path}diff.png"
20
+ data_out = "#{out_path}data.txt"
21
+
22
+ `compare -fuzz #{@goggles_fuzz} -metric AE -highlight-color blue #{one} #{two} #{diff_out} 2>#{data_out}`
23
+ end
24
+ end
25
+
26
+ def size_to_smallest!
27
+ images = Dir.glob("#{@goggles_result_dir}/*/*.png").sort
28
+
29
+ until images.empty?
30
+ one = images.slice!(0)
31
+ two = images.slice!(0)
32
+
33
+ File.open(one, 'rb') do |file_one|
34
+ size_one = ImageSize.new(file_one.read).size
35
+ first_width = size_one[0]
36
+ first_height = size_one[1]
37
+
38
+ File.open(two, 'rb') do |file_two|
39
+ size_two = ImageSize.new(file_two.read).size
40
+ second_width = size_two[0]
41
+ second_height = size_two[1]
42
+
43
+ if first_width > second_width
44
+ width = second_width
45
+ w_file = one
46
+ else
47
+ width = first_width
48
+ w_file = two
49
+ end
50
+
51
+ if first_height > second_height
52
+ height = second_height
53
+ h_file = one
54
+ else
55
+ height = first_height
56
+ h_file = two
57
+ end
58
+
59
+ cut_to_width(w_file, width)
60
+ cut_to_height(h_file, height)
61
+
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ def cut_to_width(file, w)
68
+ `convert #{file} -background none -extent #{w}x0 #{file}`
69
+ end
70
+
71
+ def cut_to_height(file, h)
72
+ `convert #{file} -background none -extent 0x#{h} #{file}`
73
+ end
74
+
75
+ end
@@ -0,0 +1,3 @@
1
+ module Goggles
2
+ class EmptyResultError < StandardError; end
3
+ end
@@ -0,0 +1,10 @@
1
+ module Goggles
2
+
3
+ def execute_script(url, script)
4
+ @watir.goto url
5
+ @watir.cookies.clear
6
+ @watir.refresh
7
+
8
+ eval(File.read(script))
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module Goggles
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,34 @@
1
+ require "spec_helper"
2
+
3
+ describe Goggles do
4
+ Given(:config_path) { "./spec/support/configs" }
5
+ Given(:images) { Dir.glob("./spec/support/results/*/*.png") }
6
+ Given(:diffs) { Dir.glob("./spec/support/results/*/*diff.png") }
7
+ Given(:datas) { Dir.glob("./spec/support/results/*/*data.txt") }
8
+
9
+ context "swimming with one script at multiple sizes" do
10
+ describe "taking screenshots" do
11
+ Given(:sizes_config) { "#{config_path}/test_config_1024_600.yml" }
12
+ When { Goggles.swim(sizes_config) }
13
+ Then { images.size.should == 6 }
14
+ And { diffs.size.should == 2 }
15
+ And { datas.size.should == 2 }
16
+ end
17
+
18
+ describe "generating error" do
19
+ Given(:no_shot_config) { "#{config_path}/test_config_no_screenshot.yml" }
20
+ Then { expect{ Goggles.swim(no_shot_config) }.to raise_error(Goggles::EmptyResultError) }
21
+ end
22
+ end
23
+
24
+ context "swimming against multiple paths with no scripts" do
25
+ describe "taking screenshots when commanded" do
26
+ Given(:scriptless_config) { "#{config_path}/test_config_scriptless.yml" }
27
+ When { Goggles.swim(scriptless_config) }
28
+ Then { images.size.should == 6 }
29
+ And { diffs.size.should == 2 }
30
+ And { datas.size.should == 2 }
31
+ end
32
+ end
33
+
34
+ end
@@ -0,0 +1,10 @@
1
+ require 'rspec'
2
+ require 'rspec-given'
3
+
4
+ require 'goggles'
5
+
6
+ RSpec.configure do |config|
7
+ config.order = 'default'
8
+ config.treat_symbols_as_metadata_keys_with_true_values = true
9
+ config.filter_run_excluding :skip => true
10
+ end
@@ -0,0 +1,20 @@
1
+ results_directory: "spec/support/results"
2
+ scripts_directory: "spec/support/scripts"
3
+
4
+ domain_under_test: "http://www.google.com"
5
+
6
+ paths_to_capture:
7
+ home: "/"
8
+
9
+ scripts_to_execute:
10
+ - "google_search.rb"
11
+
12
+ browsers:
13
+ - "firefox"
14
+ - "chrome"
15
+
16
+ browser_widths:
17
+ - 1024
18
+ - 600
19
+
20
+ image_fuzzing: "20%"
@@ -0,0 +1,19 @@
1
+ results_directory: "spec/support/results"
2
+ scripts_directory: "spec/support/scripts"
3
+
4
+ domain_under_test: "http://www.google.com"
5
+
6
+ paths_to_capture:
7
+ home: "/"
8
+
9
+ scripts_to_execute:
10
+ - "no_screenshot.rb"
11
+
12
+ browsers:
13
+ - "firefox"
14
+ - "chrome"
15
+
16
+ browser_widths:
17
+ - 320
18
+
19
+ image_fuzzing: "20%"
@@ -0,0 +1,19 @@
1
+ results_directory: "spec/support/results"
2
+ scripts_directory: "spec/support/scripts"
3
+
4
+ domain_under_test: "http://www.google.com"
5
+
6
+ paths_to_capture:
7
+ home: "/"
8
+ email: "/gmail"
9
+
10
+ scripts_to_execute:
11
+
12
+ browsers:
13
+ - "firefox"
14
+ - "chrome"
15
+
16
+ browser_widths:
17
+ - 1024
18
+
19
+ image_fuzzing: "20%"
@@ -0,0 +1,14 @@
1
+ require 'goggles'
2
+ require 'page-object'
3
+
4
+ class Search
5
+ include PageObject
6
+
7
+ text_field(:search_box, :id => "gbqfq")
8
+ end
9
+
10
+ Goggles.grab_screenshot("homepage")
11
+
12
+ page = Search.new(@watir)
13
+ page.search_box = "manta"
14
+ sleep 1
@@ -0,0 +1,12 @@
1
+ require 'goggles'
2
+ require 'page-object'
3
+
4
+ class Search
5
+ include PageObject
6
+
7
+ text_field(:search_box, :id => "gbqfq")
8
+ end
9
+
10
+ page = Search.new(@watir)
11
+ page.search_box = "manta"
12
+ sleep 1
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: goggles
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Johnson Denen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-01-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.5'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.5'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rspec
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: watir-webdriver
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: image_size
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ description: comparing responsive screenshots under watir-webdriver
95
+ email:
96
+ - jdenen@manta.com
97
+ executables:
98
+ - swim
99
+ extensions: []
100
+ extra_rdoc_files: []
101
+ files:
102
+ - .gitignore
103
+ - Gemfile
104
+ - LICENSE.txt
105
+ - README.md
106
+ - Rakefile
107
+ - bin/swim
108
+ - goggles.gemspec
109
+ - lib/goggles.rb
110
+ - lib/goggles/cli.rb
111
+ - lib/goggles/comparison.rb
112
+ - lib/goggles/error.rb
113
+ - lib/goggles/scripter.rb
114
+ - lib/goggles/version.rb
115
+ - spec/goggles_spec.rb
116
+ - spec/spec_helper.rb
117
+ - spec/support/configs/test_config_1024_600.yml
118
+ - spec/support/configs/test_config_no_screenshot.yml
119
+ - spec/support/configs/test_config_scriptless.yml
120
+ - spec/support/scripts/google_search.rb
121
+ - spec/support/scripts/no_screenshot.rb
122
+ homepage: http://github.com/jdenen/goggles
123
+ licenses:
124
+ - MIT
125
+ post_install_message:
126
+ rdoc_options: []
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - ! '>='
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ none: false
137
+ requirements:
138
+ - - ! '>='
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ requirements: []
142
+ rubyforge_project:
143
+ rubygems_version: 1.8.23
144
+ signing_key:
145
+ specification_version: 3
146
+ summary: comparing responsive screenshots under watir-webdriver
147
+ test_files:
148
+ - spec/goggles_spec.rb
149
+ - spec/spec_helper.rb
150
+ - spec/support/configs/test_config_1024_600.yml
151
+ - spec/support/configs/test_config_no_screenshot.yml
152
+ - spec/support/configs/test_config_scriptless.yml
153
+ - spec/support/scripts/google_search.rb
154
+ - spec/support/scripts/no_screenshot.rb