capybara-screenshot-diff 1.6.3 → 1.8.3
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/Rakefile +29 -0
- data/capybara-screenshot-diff.gemspec +6 -3
- data/gems.rb +8 -2
- data/lib/capybara/screenshot/diff/browser_helpers.rb +102 -0
- data/lib/capybara/screenshot/diff/cucumber.rb +11 -0
- data/lib/capybara/screenshot/diff/difference.rb +63 -0
- data/lib/capybara/screenshot/diff/drivers/base_driver.rb +42 -0
- data/lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb +193 -252
- data/lib/capybara/screenshot/diff/drivers/utils.rb +18 -0
- data/lib/capybara/screenshot/diff/drivers/vips_driver.rb +61 -102
- data/lib/capybara/screenshot/diff/drivers.rb +16 -0
- data/lib/capybara/screenshot/diff/image_compare.rb +138 -154
- data/lib/capybara/screenshot/diff/os.rb +1 -1
- data/lib/capybara/screenshot/diff/region.rb +86 -0
- data/lib/capybara/screenshot/diff/screenshot_matcher.rb +128 -0
- data/lib/capybara/screenshot/diff/screenshoter.rb +136 -0
- data/lib/capybara/screenshot/diff/stabilization.rb +0 -208
- data/lib/capybara/screenshot/diff/stable_screenshoter.rb +106 -0
- data/lib/capybara/screenshot/diff/test_methods.rb +57 -63
- data/lib/capybara/screenshot/diff/vcs.rb +48 -21
- data/lib/capybara/screenshot/diff/version.rb +1 -1
- data/lib/capybara/screenshot/diff.rb +15 -19
- data/sig/capybara/screenshot/diff/diff.rbs +28 -0
- data/sig/capybara/screenshot/diff/difference.rbs +33 -0
- data/sig/capybara/screenshot/diff/drivers/base_driver.rbs +63 -0
- data/sig/capybara/screenshot/diff/drivers/browser_helpers.rbs +36 -0
- data/sig/capybara/screenshot/diff/drivers/chunky_png_driver.rbs +89 -0
- data/sig/capybara/screenshot/diff/drivers/utils.rbs +13 -0
- data/sig/capybara/screenshot/diff/drivers/vips_driver.rbs +25 -0
- data/sig/capybara/screenshot/diff/image_compare.rbs +93 -0
- data/sig/capybara/screenshot/diff/os.rbs +11 -0
- data/sig/capybara/screenshot/diff/region.rbs +43 -0
- data/sig/capybara/screenshot/diff/screenshot_matcher.rbs +60 -0
- data/sig/capybara/screenshot/diff/screenshoter.rbs +48 -0
- data/sig/capybara/screenshot/diff/stable_screenshoter.rbs +29 -0
- data/sig/capybara/screenshot/diff/test_methods.rbs +39 -0
- data/sig/capybara/screenshot/diff/vcs.rbs +17 -0
- metadata +30 -25
- data/.gitattributes +0 -4
- data/.github/workflows/lint.yml +0 -25
- data/.github/workflows/test.yml +0 -120
- data/.gitignore +0 -12
- data/.standard.yml +0 -12
- data/CONTRIBUTING.md +0 -22
- data/Dockerfile +0 -60
- data/README.md +0 -555
- data/bin/bundle +0 -114
- data/bin/console +0 -15
- data/bin/install-vips +0 -11
- data/bin/rake +0 -27
- data/bin/setup +0 -8
- data/bin/standardrb +0 -29
- data/gemfiles/rails52.gemfile +0 -6
- data/gemfiles/rails60_gems.rb +0 -8
- data/gemfiles/rails61_gems.rb +0 -7
- data/gemfiles/rails70_gems.rb +0 -7
- data/tmp/.keep +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e7e3bdfacb7c2fad912c72ade765c9ec6a50f306048a374d8056fc02c27d643
|
4
|
+
data.tar.gz: c1527905de61a1d801c545729d68b811ba91db5902c1ff209b4dc212fa252971
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c9c7868fe6d13263db039cf2a7fbb85234abee8f3bc05dd51fc5cc78579a96c1de3f2275782f5c806e9b154472ad51a991cfad1847a54d4811460597a3a4b8fe
|
7
|
+
data.tar.gz: 209f71e33b2b4bdead447293c0e286de6b6e1d945f4e12889e1b4f94675bb8bc035956f19a9897ceeedf278999598bb095991ecd34f2eaffa219d088ea19d577
|
data/Rakefile
CHANGED
@@ -16,3 +16,32 @@ Rake::TestTask.new("test:integration") do |t|
|
|
16
16
|
t.libs << "lib"
|
17
17
|
t.test_files = FileList["test/integration/**/*_test.rb"]
|
18
18
|
end
|
19
|
+
|
20
|
+
Rake::TestTask.new("test:signatures") do |t|
|
21
|
+
ENV["RBS_TEST_DOUBLE_SUITE"] ||= "minitest"
|
22
|
+
ENV["RBS_TEST_TARGET"] ||= "Capybara::Screenshot::Diff::*"
|
23
|
+
ENV["RBS_TEST_OPT"] ||= "-rset -rpathname -Isig"
|
24
|
+
|
25
|
+
t.libs << "test"
|
26
|
+
t.ruby_opts << "-r rbs/test/setup"
|
27
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
28
|
+
end
|
29
|
+
|
30
|
+
task "clobber" do
|
31
|
+
puts "Cleanup tmp/*.png"
|
32
|
+
FileUtils.rm_rf(Dir["./tmp/*"])
|
33
|
+
end
|
34
|
+
|
35
|
+
task "test:benchmark" do
|
36
|
+
require_relative "./scripts/benchmark/find_region_benchmark"
|
37
|
+
benchmark = Capybara::Screenshot::Diff::Drivers::FindRegionBenchmark.new
|
38
|
+
|
39
|
+
puts "For Medium Screen Size: 800x600"
|
40
|
+
benchmark.for_medium_size_screens
|
41
|
+
|
42
|
+
puts ""
|
43
|
+
puts "*" * 100
|
44
|
+
|
45
|
+
puts "For Small Screen Size: 80x60"
|
46
|
+
benchmark.for_small_images
|
47
|
+
end
|
@@ -12,15 +12,18 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.summary = "Track your GUI changes with diff assertions"
|
13
13
|
spec.description = "Save screen shots and track changes with graphical diff"
|
14
14
|
spec.homepage = "https://github.com/donv/capybara-screenshot-diff"
|
15
|
-
spec.required_ruby_version = ">=
|
15
|
+
spec.required_ruby_version = ">= 3.0.0"
|
16
16
|
spec.license = "MIT"
|
17
17
|
spec.metadata["allowed_push_host"] = "https://rubygems.org/"
|
18
|
-
spec.files = `git ls-files -z`.split("\x0").reject
|
18
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
19
|
+
f.match(%r{(^(\.|tmp|bin|test|spec|features|gemfiles|scripts)/)|(^(\.|Dockerfile|CONTRIBUTING|README))})
|
20
|
+
end
|
21
|
+
|
19
22
|
spec.bindir = "exe"
|
20
23
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
24
|
spec.require_paths = ["lib"]
|
22
25
|
|
23
|
-
spec.add_runtime_dependency "actionpack", ">=
|
26
|
+
spec.add_runtime_dependency "actionpack", ">= 6.1", "< 8"
|
24
27
|
spec.add_runtime_dependency "capybara", ">= 2", "< 4"
|
25
28
|
spec.add_runtime_dependency "chunky_png", "~> 1.3"
|
26
29
|
end
|
data/gems.rb
CHANGED
@@ -8,7 +8,7 @@ gemspec path: __dir__
|
|
8
8
|
gem "rake"
|
9
9
|
|
10
10
|
# Image processing libraries
|
11
|
-
gem "oily_png", platform: :ruby
|
11
|
+
gem "oily_png", platform: :ruby, git: "https://github.com/donv/oily_png", branch: "patch-2"
|
12
12
|
gem "ruby-vips", require: false
|
13
13
|
|
14
14
|
# Test
|
@@ -18,12 +18,18 @@ gem "simplecov", require: false
|
|
18
18
|
|
19
19
|
# Capybara Server
|
20
20
|
gem "puma", require: false
|
21
|
+
gem "rackup", require: false
|
21
22
|
|
22
23
|
# Capybara Drivers
|
23
24
|
gem "cuprite", require: false
|
24
25
|
gem "selenium-webdriver", require: false
|
25
|
-
gem "webdrivers", require: false
|
26
|
+
gem "webdrivers", "~> 5.0", require: false
|
27
|
+
|
28
|
+
# Test Frameworks
|
29
|
+
# gem "cucumber", require: false
|
30
|
+
# gem "cucumber-rails", require: false
|
26
31
|
|
27
32
|
group :tools do
|
28
33
|
gem "standard", require: false
|
34
|
+
gem "rbs", require: false, platform: :ruby
|
29
35
|
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "region"
|
4
|
+
|
5
|
+
module Capybara
|
6
|
+
module Screenshot
|
7
|
+
module BrowserHelpers
|
8
|
+
def self.resize_to(window_size)
|
9
|
+
if session.driver.respond_to?(:resize)
|
10
|
+
session.driver.resize(*window_size)
|
11
|
+
elsif BrowserHelpers.selenium?
|
12
|
+
session.driver.browser.manage.window.resize_to(*window_size)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.selenium?
|
17
|
+
current_capybara_driver_class <= Capybara::Selenium::Driver
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.window_size_is_wrong?(expected_window_size = nil)
|
21
|
+
selenium? && expected_window_size &&
|
22
|
+
session.driver.browser.manage.window.size != ::Selenium::WebDriver::Dimension.new(*expected_window_size)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.bounds_for_css(*css_selectors)
|
26
|
+
css_selectors.reduce([]) do |regions, selector|
|
27
|
+
regions.concat(all_visible_regions_for(selector))
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
IMAGE_WAIT_SCRIPT = <<~JS
|
32
|
+
function pending_image() {
|
33
|
+
var images = document.images;
|
34
|
+
for (var i = 0; i < images.length; i++) {
|
35
|
+
if (!images[i].complete) {
|
36
|
+
return images[i].src;
|
37
|
+
}
|
38
|
+
}
|
39
|
+
return false;
|
40
|
+
}(window)
|
41
|
+
JS
|
42
|
+
|
43
|
+
HIDE_CARET_SCRIPT = <<~JS
|
44
|
+
if (!document.getElementById('csdHideCaretStyle')) {
|
45
|
+
let style = document.createElement('style');
|
46
|
+
style.setAttribute('id', 'csdHideCaretStyle');
|
47
|
+
document.head.appendChild(style);
|
48
|
+
let styleSheet = style.sheet;
|
49
|
+
styleSheet.insertRule("* { caret-color: transparent !important; }", 0);
|
50
|
+
}
|
51
|
+
JS
|
52
|
+
|
53
|
+
def self.hide_caret
|
54
|
+
session.execute_script(HIDE_CARET_SCRIPT)
|
55
|
+
end
|
56
|
+
|
57
|
+
FIND_ACTIVE_ELEMENT_SCRIPT = <<~JS
|
58
|
+
function activeElement(){
|
59
|
+
const ae = document.activeElement;
|
60
|
+
if (ae.nodeName === "INPUT" || ae.nodeName === "TEXTAREA") {
|
61
|
+
ae.blur();
|
62
|
+
return ae;
|
63
|
+
}
|
64
|
+
return null;
|
65
|
+
}(window);
|
66
|
+
JS
|
67
|
+
|
68
|
+
def self.blur_from_focused_element
|
69
|
+
session.evaluate_script(FIND_ACTIVE_ELEMENT_SCRIPT)
|
70
|
+
end
|
71
|
+
|
72
|
+
GET_BOUNDING_CLIENT_RECT_SCRIPT = <<~JS
|
73
|
+
[
|
74
|
+
this.getBoundingClientRect().left,
|
75
|
+
this.getBoundingClientRect().top,
|
76
|
+
this.getBoundingClientRect().right,
|
77
|
+
this.getBoundingClientRect().bottom
|
78
|
+
]
|
79
|
+
JS
|
80
|
+
|
81
|
+
def self.all_visible_regions_for(selector)
|
82
|
+
BrowserHelpers.session.all(selector, visible: true).map(&method(:region_for))
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.region_for(element)
|
86
|
+
element.evaluate_script(GET_BOUNDING_CLIENT_RECT_SCRIPT).map { |point| point.negative? ? 0 : point.to_i }
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.session
|
90
|
+
Capybara.current_session
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.pending_image_to_load
|
94
|
+
BrowserHelpers.session.evaluate_script(IMAGE_WAIT_SCRIPT)
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.current_capybara_driver_class
|
98
|
+
session.driver.class
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "capybara/screenshot/diff"
|
4
|
+
require "capybara/screenshot/diff/test_methods"
|
5
|
+
|
6
|
+
World(Capybara::Screenshot::Diff::TestMethods)
|
7
|
+
|
8
|
+
Before do
|
9
|
+
Capybara::Screenshot::Diff.delayed = false
|
10
|
+
Capybara::Screenshot::BrowserHelpers.resize_to(Capybara::Screenshot.window_size) if Capybara::Screenshot.window_size
|
11
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
module Capybara
|
6
|
+
module Screenshot
|
7
|
+
module Diff
|
8
|
+
class Difference < Struct.new(:region, :meta, :comparison)
|
9
|
+
def different?
|
10
|
+
!(blank? || tolerable?)
|
11
|
+
end
|
12
|
+
|
13
|
+
def base_image
|
14
|
+
comparison.base_image
|
15
|
+
end
|
16
|
+
|
17
|
+
def options
|
18
|
+
comparison.options
|
19
|
+
end
|
20
|
+
|
21
|
+
def tolerance
|
22
|
+
options[:tolerance]
|
23
|
+
end
|
24
|
+
|
25
|
+
def skip_area
|
26
|
+
options[:skip_area]
|
27
|
+
end
|
28
|
+
|
29
|
+
def area_size_limit
|
30
|
+
options[:area_size_limit]
|
31
|
+
end
|
32
|
+
|
33
|
+
def blank?
|
34
|
+
region.nil? || region_area_size.zero?
|
35
|
+
end
|
36
|
+
|
37
|
+
def region_area_size
|
38
|
+
region&.size || 0
|
39
|
+
end
|
40
|
+
|
41
|
+
def ratio
|
42
|
+
meta[:difference_level]
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_h
|
46
|
+
{area_size: region_area_size, region: coordinates}.merge!(meta)
|
47
|
+
end
|
48
|
+
|
49
|
+
def coordinates
|
50
|
+
region&.to_edge_coordinates
|
51
|
+
end
|
52
|
+
|
53
|
+
def inspect
|
54
|
+
to_h.to_json
|
55
|
+
end
|
56
|
+
|
57
|
+
def tolerable?
|
58
|
+
!!((area_size_limit && area_size_limit >= region_area_size) || (tolerance && tolerance >= ratio))
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "chunky_png"
|
4
|
+
require "capybara/screenshot/diff/difference"
|
5
|
+
|
6
|
+
module Capybara
|
7
|
+
module Screenshot
|
8
|
+
module Diff
|
9
|
+
# Compare two images and determine if they are equal, different, or within some comparison
|
10
|
+
# range considering color values and difference area size.
|
11
|
+
module Drivers
|
12
|
+
class BaseDriver
|
13
|
+
PNG_EXTENSION = ".png"
|
14
|
+
|
15
|
+
def same_dimension?(comparison)
|
16
|
+
dimension(comparison.base_image) == dimension(comparison.new_image)
|
17
|
+
end
|
18
|
+
|
19
|
+
def height_for(image)
|
20
|
+
image.height
|
21
|
+
end
|
22
|
+
|
23
|
+
def width_for(image)
|
24
|
+
image.width
|
25
|
+
end
|
26
|
+
|
27
|
+
def image_area_size(image)
|
28
|
+
width_for(image) * height_for(image)
|
29
|
+
end
|
30
|
+
|
31
|
+
def dimension(image)
|
32
|
+
[width_for(image), height_for(image)]
|
33
|
+
end
|
34
|
+
|
35
|
+
def inscribed?(dimensions, i)
|
36
|
+
width_for(i) < dimensions[0] || height_for(i) < dimensions[1]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|