dotdiff 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ee81e4a430c00cb04ad15b616dc3b4e2ab24a338
4
+ data.tar.gz: 769f09a70a309d0ab64bf02b1891bb64974778a6
5
+ SHA512:
6
+ metadata.gz: fa3f58f8dfc35765d45e3c95724cd3d3e92cdb529da542a534c85b9291308aee325c590f0b3f56d8016b974cfb0474768ac2ff7e3ee66ae495cef3f850ecaff4
7
+ data.tar.gz: 61de0f39159498cd6c3d3b828d91fb86f4c3333b3395c558beb2d72707255a3158851867fe84efd38c78bf1d820fa8dfbdc5d6389b8cf305b2d11e01fce14aa5
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dotdiff.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Jon Normington
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, 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,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,94 @@
1
+ # Dotdiff
2
+
3
+ Dotdiff is a very basic wrapper around [perceptual-diff](http://pdiff.sourceforge.net/) which works with both Capybara and RSpec to capture and compare the images with a simple rspec matcher. Which can also hide certain elements via executing javascript for elements which can change with different display suchas username or user specific details.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'dotdiff'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install dotdiff
20
+
21
+ ## Usage
22
+
23
+ First ensure to install perceptualdiff binary which is available via apt-get and brew or via http://pdiff.sourceforge.net/
24
+
25
+ In your spec/spec_helper
26
+ ```
27
+ require 'dotdiff'
28
+ ```
29
+
30
+ If you want the rspec_matcher require the following as well
31
+ ```
32
+ require 'dotdiff/rspec_matcher'
33
+ ```
34
+
35
+ In an initializer you can configure certain options example shown below within Dotdiff
36
+
37
+ ```ruby
38
+ DotDiff.configure do |config|
39
+ config.perceptual_diff_bin = `which perceptualdiff`.strip
40
+ config.image_store_path = File.expand_path('../../spec/fixtures/images', __FILE__)
41
+ config.js_elements_to_hide = [
42
+ "document.getElementsByClassName('drop-menu-toggle')[0]",
43
+ "document.getElementsById('username-title')",
44
+ ]
45
+ config.failure_image_path = '/home/user/spec_image_failures'
46
+
47
+ end
48
+ ```
49
+
50
+ Basic usage in your spec is just the line below;
51
+
52
+ ```ruby
53
+ expect(page).to match_image('GooglePage', subdir: 'Google')
54
+ ```
55
+
56
+ It does the following;
57
+
58
+ It builds the base_image_file location with DotDiff.image_store_path + subdir + filename + .png
59
+
60
+ It then checks if that file exists;
61
+ - If it doesn't exist it or `resave_base_image` is passed;
62
+ - it hides any elements defined in `js_elements_to_hide`
63
+ - uses `Capybara::Session#save_screenshot` to create a screenshot
64
+ - it then un-hides any elements defined as above
65
+ - returns that compare was successfull
66
+
67
+ Also if resave_base_image is passed and DotDiff.overwrite_on_resave is false it creates an r2 version so that you can compare with the original or if the file is deleted it will just write the same file.
68
+
69
+ - If the `base_image_file` exists and resave_base_image is false;
70
+ - it hides any elements defined in `js_elements_to_hide`
71
+ - uses `Capybara::Session#save_screenshot` to create a screenshot in a tmpdir to compare against the base_image
72
+ - runs the command and observes the result
73
+ - it then un-hides any elements defined as above
74
+ - if failure_image_path is defined it moves the new captured image to that path named as the original file
75
+ - returns both the result and stdout failure message
76
+
77
+ A failure message might look like the following `expected to match image but failed with: FAIL: Images are 120 pixels visibly different`
78
+
79
+
80
+ ## Contributing
81
+
82
+ Bug reports and pull requests are welcome on GitHub at https://github.com/jnormington/dotdiff.
83
+
84
+
85
+ ## License
86
+
87
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
88
+
89
+ ## Whats left to do
90
+
91
+ Its not fully completed yet but is usable in its current state.
92
+ - Improve the message output to extract just the fail line
93
+ - Add an integration spec
94
+ - Other things as it crops up
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "dotdiff"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/dotdiff.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dotdiff/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "dotdiff"
8
+ spec.version = DotDiff::VERSION
9
+ spec.authors = ["Jon Normington"]
10
+ spec.email = ["jnormington@users.noreply.github.com"]
11
+
12
+ spec.summary = "Preceptual diff wrapper for capybara and rspec image regression specs"
13
+ spec.description = [spec.summary, "which is great for graphs and charts where checking"\
14
+ "the DOM is either impossible to not worth it."].join(' ')
15
+ spec.homepage = "https://github.com/jnormington/dotdiff"
16
+ spec.license = "MIT"
17
+
18
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.11"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "rspec", "~> 3.0"
26
+ end
data/lib/dotdiff.rb ADDED
@@ -0,0 +1,27 @@
1
+ require 'dotdiff/version'
2
+
3
+ require 'shellwords'
4
+ require 'tmpdir'
5
+
6
+ require 'dotdiff/command_wrapper'
7
+ require 'dotdiff/image'
8
+ require 'dotdiff/element_handler'
9
+
10
+ module DotDiff
11
+ class << self
12
+ attr_accessor :perceptual_diff_bin, :resave_base_image, :failure_image_path,
13
+ :image_store_path, :overwrite_on_resave, :js_elements_to_hide
14
+
15
+ def configure
16
+ yield self
17
+ end
18
+
19
+ def resave_base_image
20
+ @resave_base_image ||= false
21
+ end
22
+
23
+ def js_elements_to_hide
24
+ @js_elements_to_hide ||= []
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,39 @@
1
+ require 'shellwords'
2
+
3
+ module DotDiff
4
+ class CommandWrapper
5
+ attr_reader :message
6
+
7
+ def run(base_image, new_image)
8
+ output = `#{command(base_image, new_image)}`
9
+
10
+ @ran_checks = true
11
+
12
+ if output.include?('PASS:')
13
+ @failed = false
14
+ else
15
+ @failed = true
16
+ @message = output.split("\n").join(' ')
17
+ end
18
+ end
19
+
20
+ def passed?
21
+ !failed?
22
+ end
23
+
24
+ def failed?
25
+ @ran_checks && @failed
26
+ end
27
+
28
+ def ran_checks
29
+ @ran_checks
30
+ end
31
+
32
+ private
33
+
34
+ def command(base_image, new_image)
35
+ "#{DotDiff.perceptual_diff_bin} #{Shellwords.escape(base_image)} "\
36
+ "#{Shellwords.escape(new_image)} -verbose"
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,26 @@
1
+ module DotDiff
2
+ class ElementHandler
3
+ attr_accessor :driver
4
+
5
+ def initialize(driver, elements = DotDiff.js_elements_to_hide)
6
+ @driver = driver
7
+ @elements = elements
8
+ end
9
+
10
+ def hide
11
+ elements.each do |elem|
12
+ driver.execute_script("#{elem}.style.visibility = 'hidden'")
13
+ end
14
+ end
15
+
16
+ def show
17
+ elements.each do |elem|
18
+ driver.execute_script("#{elem}.style.visibility = ''")
19
+ end
20
+ end
21
+
22
+ def elements
23
+ @elements ||= []
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,80 @@
1
+ require 'fileutils'
2
+
3
+ module DotDiff
4
+ class Image
5
+ attr_accessor :driver, :resave_base_image, :subdir, :file_name
6
+
7
+ def initialize(opts = {})
8
+ Hash(opts).each do |key, value|
9
+ if self.respond_to?("#{key}=")
10
+ self.send("#{key}=", value)
11
+ end
12
+ end
13
+ end
14
+
15
+ def compare
16
+ outcome = []
17
+
18
+ if !File.exists?(base_image_file) || resave_base_image
19
+ path = capture_and_resave_base_image
20
+ outcome = [true, path]
21
+ else
22
+ compare_to_image = capture_from_browser
23
+ result = CommandWrapper.new
24
+
25
+ element_handler.hide
26
+ result.run(base_image_file, compare_to_image)
27
+ element_handler.show
28
+
29
+ if result.failed? && DotDiff.failure_image_path
30
+ FileUtils.mkdir_p(File.join(DotDiff.failure_image_path, subdir.to_s))
31
+ file_name = File.basename(compare_to_image)
32
+
33
+ FileUtils.mv(compare_to_image,
34
+ File.join(DotDiff.failure_image_path, subdir.to_s, file_name), force: true)
35
+ end
36
+
37
+ outcome = [result.passed?, result.message]
38
+ end
39
+
40
+ outcome
41
+ end
42
+
43
+ def resave_base_image
44
+ @resave_base_image.nil? ? DotDiff.resave_base_image : @resave_base_image
45
+ end
46
+
47
+ def base_image_file
48
+ @file_name = "#{file_name}.png" unless file_name.include?('.png')
49
+
50
+ File.join(DotDiff.image_store_path, subdir.to_s, file_name)
51
+ end
52
+
53
+ private
54
+
55
+ def element_handler
56
+ @elemnt_handler ||= ElementHandler.new(driver)
57
+ end
58
+
59
+ def capture_from_browser
60
+ tmp_screenshot_file = File.join(Dir.tmpdir, File.basename(base_image_file))
61
+
62
+ element_handler.hide
63
+ driver.save_screenshot(tmp_screenshot_file)
64
+ element_handler.show
65
+
66
+ tmp_screenshot_file
67
+ end
68
+
69
+ def capture_and_resave_base_image
70
+ tmp_image = capture_from_browser
71
+ FileUtils.mkdir_p(File.join(DotDiff.image_store_path, subdir))
72
+
73
+ if !File.exists?(base_image_file) || DotDiff.overwrite_on_resave
74
+ FileUtils.mv(tmp_image, base_image_file, force: true)
75
+ else
76
+ FileUtils.mv(tmp_image, "#{base_image_file}.r2", force: true)
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,15 @@
1
+ require 'rspec/expectations'
2
+
3
+ RSpec::Matchers.define :match_image do |filename, opts = {}|
4
+ match do |page|
5
+ image = DotDiff::Image.new(Hash(opts).merge!(file_name: filename, driver: page))
6
+
7
+ result, @message = image.compare
8
+ result == true
9
+ end
10
+
11
+
12
+ failure_message do |actual|
13
+ "expected to match image but failed with: #{@message}"
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module DotDiff
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dotdiff
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jon Normington
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-03-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description: Preceptual diff wrapper for capybara and rspec image regression specs
56
+ which is great for graphs and charts where checkingthe DOM is either impossible
57
+ to not worth it.
58
+ email:
59
+ - jnormington@users.noreply.github.com
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - .gitignore
65
+ - .rspec
66
+ - Gemfile
67
+ - LICENSE
68
+ - README.md
69
+ - Rakefile
70
+ - bin/console
71
+ - bin/setup
72
+ - dotdiff.gemspec
73
+ - lib/dotdiff.rb
74
+ - lib/dotdiff/command_wrapper.rb
75
+ - lib/dotdiff/element_handler.rb
76
+ - lib/dotdiff/image.rb
77
+ - lib/dotdiff/rspec_matcher.rb
78
+ - lib/dotdiff/version.rb
79
+ homepage: https://github.com/jnormington/dotdiff
80
+ licenses:
81
+ - MIT
82
+ metadata: {}
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 2.0.14
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: Preceptual diff wrapper for capybara and rspec image regression specs
103
+ test_files: []