watircats 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b5df83a0e30799d0a3c844005316edd2e0d5f87d
4
+ data.tar.gz: b7b07badae0c4ff54e8266afc594eac5cd3f6905
5
+ SHA512:
6
+ metadata.gz: 3285222f1d6dfcd699340ed5ddfddf4f83e1cab0c1be9ebe20d0b43758728fd0e0cd1cecba3db9c6c19315f7d956afe2034157cb742c1a93270a18b2bcc50560
7
+ data.tar.gz: bad339c10f794b8d610daeb67cc9e6c932ffcfacc4afcda6bc94c1df5267951f5e456e992b72ac1fe5c8756da68ab3367f96a24bd4fabe275479eb24df6ae59c
data/.autotest ADDED
@@ -0,0 +1,5 @@
1
+ require 'autotest/restart'
2
+
3
+ Autotest.add_hook :initialize do |at|
4
+ at.order = :random
5
+ end
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ ruby "2.0.0"
2
+
3
+ source "http://rubygems.org"
4
+
5
+ # Currently not specifying versions, but probably should
6
+
7
+ gem "require_all"
8
+ gem "xml-simple"
9
+ gem "watir-webdriver"
10
+ gem "thor"
11
+ gem "haml"
12
+ gem "psych"
13
+ gem "awesome_print"
14
+ gem "minitest"
data/Gemfile.lock ADDED
@@ -0,0 +1,38 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ awesome_print (1.2.0)
5
+ childprocess (0.3.9)
6
+ ffi (~> 1.0, >= 1.0.11)
7
+ ffi (1.9.0)
8
+ haml (4.0.3)
9
+ tilt
10
+ minitest (5.0.6)
11
+ multi_json (1.8.2)
12
+ psych (2.0.0)
13
+ require_all (1.3.1)
14
+ rubyzip (0.9.9)
15
+ selenium-webdriver (2.35.1)
16
+ childprocess (>= 0.2.5)
17
+ multi_json (~> 1.0)
18
+ rubyzip (< 1.0.0)
19
+ websocket (~> 1.0.4)
20
+ thor (0.18.1)
21
+ tilt (1.4.1)
22
+ watir-webdriver (0.6.4)
23
+ selenium-webdriver (>= 2.18.0)
24
+ websocket (1.0.7)
25
+ xml-simple (1.1.2)
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ awesome_print
32
+ haml
33
+ minitest
34
+ psych
35
+ require_all
36
+ thor
37
+ watir-webdriver
38
+ xml-simple
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Clockwork Active Media Systems
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # WatirCats
2
+
3
+ WatirCats began as a simple fork of Wraith, from the developers at BBC News.
4
+
5
+ Orignally, Wraith used Phantom.js as its browser, but it was too darned slow, so the browsing engine was converted to Watir-Webdriver. There were also several other limitations to Wraith that hampered its use at Clockwork, so it was enhanced to support a number of unique features.
6
+
7
+ Wraith's original comparison command lies at the heart of the comparison functionality of WatirCats.
8
+
9
+ Some of the features:
10
+ - Responsive Screenshots
11
+ - Multiple sources for URLs, but most rely on /sitemap.xml for use
12
+ - Multiple Browsing engines. Chrome, Firefox, FirefoxESR, and support for IE
13
+ - Proxy and custom binary path support for Firefox
14
+
15
+ ## What is it?
16
+
17
+ WatirCats uses Watir-Webdriver to grab screenshots of pages at multiple widths. It also grabs and parses a site's sitemap, assuming the site map is hosted at the site_root/sitemap.xml
18
+
19
+ ## Requirements
20
+
21
+ - ImageMagick
22
+ - Ruby 1.9.3 or greater
23
+ - Firefox
24
+
25
+ ## Installation
26
+
27
+ `gem install WatirCats`
28
+
29
+ or
30
+
31
+ - Checkout this repository
32
+ - `bundle install`
33
+ - `gem build watircats.gemspec`
34
+ - `gem install WatirCats-0.2.0.gem`
35
+
36
+ ## Usage
37
+
38
+ - Compare And Take Screenshots:
39
+ - `watircats compare http://my.example.com http://my-other.example.com`
40
+ - Compare two folders of screenshots:
41
+ - `watircats folders folder_a folder_b`
42
+ - Take screenshots at several widths:
43
+ - `watircats screenshots http://my.example.com --widths 1024 800 320`
44
+
45
+ ## Configuration
46
+
47
+ Configuration can be done at the command line or via a config file. See 'sample_config.yml' for the available parameters.
48
+
49
+ Specify a config file at runtime with `--config_file my_config_file.yml`
50
+
51
+
52
+ If you want to add functionality to this project, pull requests are welcome.
53
+
54
+ * Create a branch based off master and do all of your changes with in it.
55
+ * If it you have to pause to add a 'and' anywhere in the title, it should be two pull requests.
56
+ * Make commits of logical units and describe them properly
57
+ * Check for unnecessary whitespace with git diff --check before committing.
58
+ * If possible, submit tests to your patch / new feature so it can be tested easily.
59
+ * Assure nothing is broken by running all the test
60
+ * Please ensure that it complies with coding standards.
61
+
62
+ **Please raise any issues with this project as a GitHub issue.**
63
+
64
+
65
+ ## License
66
+
67
+ WatirCats is available to everyone under the terms of the MIT open source
68
+ licence. Take a look at the LICENSE file in the code.
69
+
70
+ ## Credits
71
+
72
+ * [Andrew Leaf](http://clockwork.net/people/andrew_leaf/)
73
+ * [Wraith from BBC News](http://github.com/bbc-news/wraith)
74
+
data/bin/watircats ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.push File.expand_path('../../lib/', __FILE__)
3
+
4
+ require 'watircats/cli'
5
+
6
+ WatirCats::CLI.start(ARGV)
@@ -0,0 +1,201 @@
1
+ require 'thor'
2
+ require 'watircats'
3
+ require 'yaml'
4
+
5
+ # CLI for WatirCats. Options and commands for any of the available utilities
6
+ # available through the watircats executable
7
+
8
+ module WatirCats
9
+ class CLI < Thor
10
+
11
+ # Options that are common for comparison operations
12
+ common_compare_options = {
13
+ [:output_dir, '-o'] => "comparison",
14
+ [:screenshot_dir, '-s'] => "screenshots",
15
+ [:working_dir, '-w'] => :string,
16
+ [:images_dir, '-i'] => :string,
17
+ [:reporting_enabled, '-r'] => :boolean,
18
+ [:csv_output] => :boolean,
19
+ [:verbose, '-v'] => :boolean,
20
+ [:strip_zero_differences, '-z'] => :boolean,
21
+ [:config_file, '-c'] => :string,
22
+ [:skip_existing, '-e'] => :boolean,
23
+ }
24
+
25
+ # Options that are common for screenshot operations
26
+ common_screenshot_options = {
27
+ [:browser, '-b'] => "firefox",
28
+ [:widths] => :array,
29
+ [:limit, '-l'] => :numeric,
30
+ [:url_list] => :string,
31
+ [:limit] => :string,
32
+ [:custom_body_class_tests] => :string,
33
+ [:proxy, '-p'] => :string,
34
+ [:limited_path] => :string,
35
+ [:avoided_path] => :string
36
+ }
37
+
38
+ # Description for the next-to-be-defined 'compare' task
39
+ desc 'compare http://SITE_A http://SITE_B', 'Compare Screenshots from two sites'
40
+
41
+ # Add the options for comparison and screenshot operations to the next task
42
+ method_options common_compare_options
43
+ method_options common_screenshot_options
44
+
45
+ def compare(*source_arguments)
46
+ ensure_imagemagick
47
+
48
+ # Configure options
49
+ handle_configuration( options )
50
+
51
+ # Setting an exit status to track for altered screens
52
+ @exit_status = 0
53
+
54
+ # Create an empty array of sources
55
+ sources = []
56
+
57
+ # Populate the sources array with each command line argument
58
+ source_arguments.each { |s| sources << s }
59
+
60
+ # Handle a working directory by calling the private method 'handle_working_dir'
61
+ handle_working_dir
62
+
63
+ # Run the comparison
64
+ WatirCats::Runner.new( :compare, sources )
65
+
66
+ # Handle the reporting functionality
67
+ handle_reporting
68
+
69
+ # Exit based on the exit status of the application
70
+ exit @exit_status
71
+ end
72
+
73
+ desc 'folders FOLDER_A FOLDER_B', 'Compare two folders of screenshots'
74
+
75
+ # Add the options for comparison operations
76
+ method_options common_compare_options
77
+
78
+ def folders(*source_arguments)
79
+ ensure_imagemagick
80
+
81
+ handle_configuration( options )
82
+ # Setting an exit status to track for altered screens
83
+ @exit_status = 0
84
+
85
+ # Create an empty array of sources
86
+ sources = [ ]
87
+
88
+ # Populate the sources array with each command line argument
89
+ source_arguments.each { |s| sources << s }
90
+
91
+ # Handle a working directory
92
+ handle_working_dir
93
+
94
+ # Run the folders command
95
+ WatirCats::Runner.new( :folders, sources )
96
+
97
+ # Handle reporting
98
+ handle_reporting
99
+
100
+ exit @exit_status
101
+ end
102
+
103
+ desc 'screenshots SITE_A [SITE_B SITE_C ...]', 'Take Screenshots of any number of sites'
104
+
105
+ method_options common_compare_options
106
+ method_options common_screenshot_options
107
+
108
+ def screenshots(*source_arguments)
109
+ ensure_imagemagick
110
+
111
+ handle_configuration( options )
112
+ # Setting an exit status to track for altered screens
113
+ @exit_status = 0
114
+
115
+ # Create an empty array of sources
116
+ sources = [ ]
117
+
118
+ # Populate the sources array with each command line argument
119
+ source_arguments.each { |s| sources << s }
120
+
121
+ # Handle a working directory
122
+ handle_working_dir
123
+
124
+ # Run the screenshots command
125
+ WatirCats::Runner.new( :screenshots_only, sources )
126
+
127
+ # Handle Reporting
128
+ handle_reporting
129
+
130
+ exit @exit_status
131
+ end
132
+
133
+ private
134
+
135
+ def handle_working_dir
136
+ # Handle a working directory
137
+ working_dir = WatirCats.config.working_dir
138
+ if working_dir
139
+ unless File.directory? working_dir
140
+ FileUtils.mkdir working_dir
141
+ end
142
+ Dir.chdir working_dir
143
+ end
144
+ end
145
+
146
+ def handle_reporting
147
+ # Handle standard reporting
148
+ reporting = WatirCats.config.reporting_enabled
149
+
150
+ if reporting
151
+ data = WatirCats::Comparer.the_results
152
+ data.each { |e| @exit_status = 1 unless e[:result].match(/0/) }
153
+
154
+ report = WatirCats::Reporter.new( data ).build_html
155
+ File.open("#{WatirCats.config.output_dir}/index.html", 'w') do |f|
156
+ f.write report
157
+ end
158
+ end
159
+
160
+ # Handle custom reporting
161
+ custom_tests = WatirCats.config.custom_body_class_tests
162
+
163
+ if custom_tests
164
+ results = WatirCats::Snapper.custom_test_results
165
+ report = WatirCats::Reporter.build_custom_results( results )
166
+
167
+ File.open("#{WatirCats.config.output_dir}/custom_report.html", 'w') do |f|
168
+ f.write report
169
+ end
170
+ end
171
+
172
+ end
173
+
174
+ def handle_configuration(options)
175
+ # Parse the command line options. If a config file if specified, merge
176
+ # those values into the options hash as long as keys don't collide.
177
+ # Command line options override the config file.
178
+
179
+ cloned_options = options.dup
180
+ if cloned_options[:config_file]
181
+ config = YAML::load_file cloned_options[:config_file]
182
+ config.each do |key,value|
183
+ cloned_options[key.to_sym] = value
184
+ end
185
+ end
186
+ merged_opts = cloned_options.merge(options)
187
+ WatirCats.configure merged_opts
188
+ end
189
+
190
+ def ensure_imagemagick
191
+ # Ensure that Imagemagick's compare is installed
192
+ begin
193
+ `compare --version`
194
+ rescue
195
+ puts "Please ensure ImageMagick is in your system path to use WatirCats. \nPlease visit http://www.imagemagick.org."
196
+ exit
197
+ end
198
+ end
199
+
200
+ end
201
+ end
@@ -0,0 +1,136 @@
1
+ module WatirCats
2
+ class Comparer
3
+
4
+ NO_CHANGE = "Snow"
5
+ ERROR = "Crimson"
6
+ CHANGE = "Khaki"
7
+
8
+
9
+ def initialize(source_a, source_b)
10
+
11
+ @@results = [ ]
12
+ @@strip_zero = WatirCats.config.strip_zero_differences || nil
13
+
14
+ @comparison_dir = WatirCats.config.output_dir.chomp("/")
15
+ # Get the last two directories that were created
16
+
17
+ previous_shots_folder = source_a.chomp("/")
18
+ latest_shots_folder = source_b.chomp("/")
19
+
20
+ # Cleanup the comparison folder
21
+ reset_comparison_folder
22
+
23
+ # Compare the directories
24
+ compare_directories(latest_shots_folder, previous_shots_folder)
25
+
26
+ # Return self
27
+ self
28
+ end
29
+
30
+ def reset_comparison_folder
31
+ if File.directory? @comparison_dir
32
+ dir_contents = Dir.glob("#{@comparison_dir}/*_compared.png")
33
+ if dir_contents.size > 0
34
+ dir_contents.each do |shot|
35
+ FileUtils.rm(shot)
36
+ end
37
+ end
38
+ else
39
+ FileUtils.mkdir_p(@comparison_dir)
40
+ end
41
+ end
42
+
43
+ def compare_directories(latest, previous)
44
+ # Grab the list of screenshots
45
+ old_shots = Dir.glob(previous + "/*.png")
46
+
47
+ old_shots.each do |old_shot|
48
+ new_shot = old_shot.gsub(previous, latest)
49
+
50
+ next unless File.exists? new_shot
51
+ # Set a file prefix for output and info
52
+ base_name = old_shot.split("/").last.split(".").first
53
+ output_file = base_name + "_compared.png"
54
+
55
+ comparison = compare_images(new_shot, old_shot, output_file)
56
+ status = NO_CHANGE
57
+ if comparison.match(/error/)
58
+ status = ERROR
59
+ elsif comparison.match(/^[1-9]/)
60
+ status = CHANGE
61
+ end
62
+ @@results << { :compared_shot => output_file,
63
+ :result => comparison, :status_color => status }
64
+
65
+ # Remove the file if there is no change to be concerned with
66
+ if @@strip_zero == true
67
+ begin
68
+ FileUtils.rm "#{@comparison_dir}/#{output_file}" if status == NO_CHANGE
69
+ rescue Exception => msg
70
+ print msg
71
+ print "\n"
72
+ end
73
+ end
74
+
75
+ end
76
+ # Run the generate thumbs
77
+ generate_thumbs if WatirCats.config.reporting_enabled
78
+ end
79
+
80
+ def generate_thumbs
81
+
82
+ unless results.size < 1
83
+ unless File.directory? "#{@comparison_dir}/thumbs"
84
+ FileUtils.mkdir "#{@comparison_dir}/thumbs"
85
+ end
86
+
87
+ # Generate thumbnails
88
+ `mogrify -format png -path #{@comparison_dir}/thumbs -thumbnail 50x100 #{@comparison_dir}/*.png`
89
+ end
90
+ end
91
+
92
+
93
+ def compare_images(latest_grab, previous_grab, output_file)
94
+ data = `compare -fuzz 20% -metric AE -highlight-color blue #{previous_grab} #{latest_grab} #{@comparison_dir}/#{output_file} 2>&1`.chomp
95
+ # Handle logging
96
+ return data if ( @@strip_zero == true && data.match(/^0/) )
97
+ csv = WatirCats.config.csv
98
+ verbose = WatirCats.config.verbose
99
+ print "#{output_file}" if ( csv || verbose )
100
+ print ",#{data}" if csv
101
+ print "\n" if ( csv || verbose )
102
+ # Return data
103
+ data
104
+ end
105
+
106
+ def results
107
+ sorted = @@results.sort_by { |k| k[:status] }
108
+ if @@strip_zero == true
109
+ return sorted.reject { |capture| true if capture[:result] == "0" }
110
+ else
111
+ return sorted
112
+ end
113
+ end
114
+
115
+
116
+ def self.sanitize_results(data)
117
+ data.each do | hash |
118
+ hash[:result] = 'image mismatch' if hash[:result].match(/compare/)
119
+ end
120
+ end
121
+
122
+ def self.the_results
123
+ sorted = @@results.sort_by { |k| k[:status] }
124
+
125
+ sanitize_results(sorted)
126
+
127
+ if @@strip_zero
128
+ return sorted.reject { |cap| true if cap[:result] == "0" }
129
+ else
130
+ return sorted
131
+ end
132
+
133
+ end
134
+
135
+ end
136
+ end
@@ -0,0 +1,58 @@
1
+ module WatirCats
2
+
3
+ @@config = nil
4
+
5
+ # Create a new Config object to store our settings
6
+ def self.configure( options_hash )
7
+ # Only allows for one time creation of the config
8
+ if @@config.is_a? Config
9
+ update_config( options_hash )
10
+ else
11
+ @@config = Config.new( options_hash )
12
+ end
13
+ # Return the @@config for chaining
14
+ @@config
15
+ end
16
+
17
+ # This allows us to get the config setting from anywhere within WatirCats
18
+ # by using WatirCats.config.setting_name
19
+ def self.config
20
+ # Return the @@config class var to allow chaining for values
21
+ @@config
22
+ end
23
+
24
+ def self.update_config( options_hash )
25
+ # Instantiate a new Config unless @@config already is a Config object
26
+ @@config = Config.new({ }) unless @@config.is_a? Config
27
+ options_hash.each do |key, value|
28
+ @@config.new_key( key, value )
29
+ end
30
+ end
31
+
32
+ # Create a configuration object
33
+ class Config
34
+
35
+ def initialize( options_hash )
36
+ # Iterate through the options hash, setting each key as an instance
37
+ # variable, and creating a getter method with the same name
38
+ options_hash.each do |key, value|
39
+ new_key(key, value)
40
+ end
41
+ end
42
+
43
+ def new_key(key, value)
44
+ # define getter
45
+ instance_eval( "def #{key}; @#{key}; end" ) unless self.respond_to? "#{key}"
46
+ # define setter
47
+ instance_eval( "def #{key}= (v); @#{key} = v; end" ) unless self.respond_to? "#{key}="
48
+ # Set the value on the instance variable, creating if necessary
49
+ instance_variable_set( "@#{key}".to_sym, value )
50
+ end
51
+
52
+ def method_missing( meth, *args, &blk )
53
+ # Return nil if an expected parameter isn't here. No need to die.
54
+ nil
55
+ end
56
+
57
+ end
58
+ end