capybara-screenshot-diff 1.6.3 → 1.7.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/.github/dependabot.yml +8 -0
- data/.github/workflows/lint.yml +1 -1
- data/.github/workflows/test.yml +36 -18
- data/.gitignore +2 -0
- data/CONTRIBUTING.md +3 -1
- data/Dockerfile +2 -3
- data/README.md +39 -27
- data/bin/install-vips +1 -1
- data/capybara-screenshot-diff.gemspec +2 -2
- data/lib/capybara/screenshot/diff/browser_helpers.rb +101 -0
- data/lib/capybara/screenshot/diff/drivers/chunky_png_driver.rb +30 -17
- data/lib/capybara/screenshot/diff/drivers/vips_driver.rb +26 -17
- data/lib/capybara/screenshot/diff/image_compare.rb +85 -72
- data/lib/capybara/screenshot/diff/region.rb +86 -0
- data/lib/capybara/screenshot/diff/stabilization.rb +14 -38
- data/lib/capybara/screenshot/diff/test_methods.rb +68 -35
- data/lib/capybara/screenshot/diff/vcs.rb +6 -5
- data/lib/capybara/screenshot/diff/version.rb +1 -1
- metadata +8 -6
- data/gemfiles/rails52.gemfile +0 -6
@@ -29,6 +29,10 @@ module Capybara
|
|
29
29
|
reset
|
30
30
|
end
|
31
31
|
|
32
|
+
def skip_area=(new_skip_area)
|
33
|
+
# noop
|
34
|
+
end
|
35
|
+
|
32
36
|
# Resets the calculated data about the comparison with regard to the "new_image".
|
33
37
|
# Data about the original image is kept.
|
34
38
|
def reset
|
@@ -53,12 +57,6 @@ module Capybara
|
|
53
57
|
[region, diff_mask]
|
54
58
|
end
|
55
59
|
|
56
|
-
def size(region)
|
57
|
-
return 0 unless region
|
58
|
-
|
59
|
-
(region[2] - region[0]) * (region[3] - region[1])
|
60
|
-
end
|
61
|
-
|
62
60
|
def adds_error_details_to(_log)
|
63
61
|
end
|
64
62
|
|
@@ -68,8 +66,16 @@ module Capybara
|
|
68
66
|
dimension(i) == dimensions || i.width < dimensions[0] || i.height < dimensions[1]
|
69
67
|
end
|
70
68
|
|
71
|
-
def crop(
|
72
|
-
i.crop(*
|
69
|
+
def crop(region, i)
|
70
|
+
result = i.crop(*region.to_top_left_corner_coordinates)
|
71
|
+
|
72
|
+
# FIXME: Vips is caching operations, and if we ware going to read the same file, he will use cached version for this
|
73
|
+
# so after we cropped files and stored in the same file, the next load will recover old version instead of cropped
|
74
|
+
# Workaround to make vips works with cropped versions
|
75
|
+
Vips.cache_set_max(0)
|
76
|
+
Vips.vips_cache_set_max(1000)
|
77
|
+
|
78
|
+
result
|
73
79
|
end
|
74
80
|
|
75
81
|
def filter_image_with_median(image, median_filter_window_size)
|
@@ -77,7 +83,7 @@ module Capybara
|
|
77
83
|
end
|
78
84
|
|
79
85
|
def add_black_box(memo, region)
|
80
|
-
memo.draw_rect([0, 0, 0, 0], *region, fill: true)
|
86
|
+
memo.draw_rect([0, 0, 0, 0], *region.to_top_left_corner_coordinates, fill: true)
|
81
87
|
end
|
82
88
|
|
83
89
|
def chunky_png_comparator
|
@@ -131,10 +137,10 @@ module Capybara
|
|
131
137
|
result
|
132
138
|
end
|
133
139
|
|
134
|
-
def dimension_changed?(
|
135
|
-
return false if dimension(
|
140
|
+
def dimension_changed?(old_image, new_image)
|
141
|
+
return false if dimension(old_image) == dimension(new_image)
|
136
142
|
|
137
|
-
change_msg = [
|
143
|
+
change_msg = [old_image, new_image].map { |i| "#{i.width}x#{i.height}" }.join(" => ")
|
138
144
|
warn "Image size has changed for #{@new_file_name}: #{change_msg}"
|
139
145
|
|
140
146
|
true
|
@@ -144,16 +150,16 @@ module Capybara
|
|
144
150
|
[image.width, image.height]
|
145
151
|
end
|
146
152
|
|
147
|
-
def draw_rectangles(images,
|
153
|
+
def draw_rectangles(images, region, rgba)
|
148
154
|
images.map do |image|
|
149
|
-
image.draw_rect(rgba, left - 1, top - 1,
|
155
|
+
image.draw_rect(rgba, region.left - 1, region.top - 1, region.width + 2, region.height + 2)
|
150
156
|
end
|
151
157
|
end
|
152
158
|
|
153
159
|
class VipsUtil
|
154
160
|
def self.difference(old_image, new_image, color_distance: 0)
|
155
161
|
diff_mask = difference_mask(color_distance, new_image, old_image)
|
156
|
-
difference_region_by(diff_mask)
|
162
|
+
difference_region_by(diff_mask).to_edge_coordinates
|
157
163
|
end
|
158
164
|
|
159
165
|
def self.difference_area(old_image, new_image, color_distance: 0)
|
@@ -171,14 +177,17 @@ module Capybara
|
|
171
177
|
end
|
172
178
|
|
173
179
|
def self.difference_region_by(diff_mask)
|
174
|
-
columns, rows = diff_mask.project
|
180
|
+
columns, rows = diff_mask.bandor.project
|
175
181
|
|
176
182
|
left = columns.profile[1].min
|
177
183
|
right = columns.width - columns.flip("horizontal").profile[1].min
|
184
|
+
|
178
185
|
top = rows.profile[0].min
|
179
186
|
bottom = rows.height - rows.flip("vertical").profile[0].min
|
180
187
|
|
181
|
-
|
188
|
+
return nil if right < left || bottom < top
|
189
|
+
|
190
|
+
Region.from_edge_coordinates(left, top, right, bottom)
|
182
191
|
end
|
183
192
|
end
|
184
193
|
end
|
@@ -12,9 +12,8 @@ module Capybara
|
|
12
12
|
|
13
13
|
attr_reader :driver, :driver_options
|
14
14
|
|
15
|
-
attr_reader :annotated_new_file_name, :annotated_old_file_name, :
|
16
|
-
|
17
|
-
:skip_area
|
15
|
+
attr_reader :annotated_new_file_name, :annotated_old_file_name, :new_file_name, :old_file_name, :skip_area
|
16
|
+
attr_accessor :shift_distance_limit, :area_size_limit, :color_distance_limit
|
18
17
|
|
19
18
|
def initialize(new_file_name, old_file_name = nil, options = {})
|
20
19
|
options = old_file_name if old_file_name.is_a?(Hash)
|
@@ -40,21 +39,23 @@ module Capybara
|
|
40
39
|
super(@driver)
|
41
40
|
end
|
42
41
|
|
42
|
+
def skip_area=(new_skip_area)
|
43
|
+
@skip_area = new_skip_area
|
44
|
+
driver.skip_area = @skip_area
|
45
|
+
end
|
46
|
+
|
43
47
|
# Compare the two image files and return `true` or `false` as quickly as possible.
|
44
|
-
# Return
|
48
|
+
# Return falsely if the old file does not exist or the image dimensions do not match.
|
45
49
|
def quick_equal?
|
46
50
|
return false unless old_file_exists?
|
47
51
|
return true if new_file_size == old_file_size
|
48
52
|
|
49
|
-
# old_bytes, new_bytes = load_image_files(@old_file_name, @new_file_name)
|
50
|
-
# return true if old_bytes == new_bytes
|
51
|
-
|
52
53
|
images = driver.load_images(@old_file_name, @new_file_name)
|
53
54
|
old_image, new_image = preprocess_images(images, driver)
|
54
55
|
|
55
56
|
return false if driver.dimension_changed?(old_image, new_image)
|
56
57
|
|
57
|
-
|
58
|
+
self.difference_region, meta = driver.find_difference_region(
|
58
59
|
new_image,
|
59
60
|
old_image,
|
60
61
|
@color_distance_limit,
|
@@ -63,14 +64,9 @@ module Capybara
|
|
63
64
|
fast_fail: true
|
64
65
|
)
|
65
66
|
|
66
|
-
|
67
|
-
|
68
|
-
return true if
|
69
|
-
|
70
|
-
return true if @area_size_limit && driver.size(region) <= @area_size_limit
|
71
|
-
|
72
|
-
return true if @tolerance && @tolerance >= driver.difference_level(meta, old_image, region)
|
73
|
-
|
67
|
+
return true if difference_region_area_size.zero? || difference_region_empty?(new_image, difference_region)
|
68
|
+
return true if @area_size_limit && difference_region_area_size <= @area_size_limit
|
69
|
+
return true if @tolerance && @tolerance >= driver.difference_level(meta, old_image, difference_region)
|
74
70
|
# TODO: Remove this or find similar solution for vips
|
75
71
|
return true if @shift_distance_limit && driver.shift_distance_equal?
|
76
72
|
|
@@ -79,41 +75,38 @@ module Capybara
|
|
79
75
|
|
80
76
|
# Compare the two images referenced by this object, and return `true` if they are different,
|
81
77
|
# and `false` if they are the same.
|
82
|
-
# Return `nil` if the old file does not exist or if the image dimensions do not match.
|
83
78
|
def different?
|
84
|
-
return
|
79
|
+
return false unless old_file_exists?
|
85
80
|
|
86
81
|
images = driver.load_images(@old_file_name, @new_file_name)
|
87
|
-
|
88
82
|
old_image, new_image = preprocess_images(images, driver)
|
89
83
|
|
90
84
|
if driver.dimension_changed?(old_image, new_image)
|
91
|
-
|
92
|
-
|
93
|
-
|
85
|
+
self.difference_region = Region.from_edge_coordinates(
|
86
|
+
0,
|
87
|
+
0,
|
88
|
+
[driver.width_for(old_image), driver.width_for(new_image)].min,
|
89
|
+
[driver.height_for(old_image), driver.height_for(new_image)].min
|
90
|
+
)
|
94
91
|
|
95
|
-
return
|
92
|
+
return different(*images)
|
96
93
|
end
|
97
94
|
|
98
|
-
|
95
|
+
self.difference_region, meta = driver.find_difference_region(
|
99
96
|
new_image,
|
100
97
|
old_image,
|
101
98
|
@color_distance_limit,
|
102
99
|
@shift_distance_limit,
|
103
100
|
@area_size_limit
|
104
101
|
)
|
105
|
-
self.difference_region = region
|
106
|
-
|
107
|
-
return not_different if difference_region_empty?(old_image, region)
|
108
|
-
return not_different if @area_size_limit && driver.size(region) <= @area_size_limit
|
109
|
-
return not_different if @tolerance && @tolerance > driver.difference_level(meta, old_image, region)
|
110
102
|
|
103
|
+
return not_different if difference_region_area_size.zero? || difference_region_empty?(old_image, difference_region)
|
104
|
+
return not_different if @area_size_limit && difference_region_area_size <= @area_size_limit
|
105
|
+
return not_different if @tolerance && @tolerance > driver.difference_level(meta, old_image, difference_region)
|
111
106
|
# TODO: Remove this or find similar solution for vips
|
112
107
|
return not_different if @shift_distance_limit && !driver.shift_distance_different?
|
113
108
|
|
114
|
-
|
115
|
-
|
116
|
-
true
|
109
|
+
different(*images)
|
117
110
|
end
|
118
111
|
|
119
112
|
def clean_tmp_files
|
@@ -123,17 +116,6 @@ module Capybara
|
|
123
116
|
File.delete(@annotated_new_file_name) if File.exist?(@annotated_new_file_name)
|
124
117
|
end
|
125
118
|
|
126
|
-
DIFF_COLOR = [255, 0, 0, 255].freeze
|
127
|
-
SKIP_COLOR = [255, 192, 0, 255].freeze
|
128
|
-
|
129
|
-
def annotate_and_save(images, region = difference_region)
|
130
|
-
annotated_images = driver.draw_rectangles(images, region, DIFF_COLOR)
|
131
|
-
@skip_area.to_a.flatten.each_slice(4) do |region|
|
132
|
-
annotated_images = driver.draw_rectangles(annotated_images, region, SKIP_COLOR)
|
133
|
-
end
|
134
|
-
save(*annotated_images, @annotated_old_file_name, @annotated_new_file_name)
|
135
|
-
end
|
136
|
-
|
137
119
|
def save(old_img, new_img, annotated_old_file_name, annotated_new_file_name)
|
138
120
|
driver.save_image_to(old_img, annotated_old_file_name)
|
139
121
|
driver.save_image_to(new_img, annotated_new_file_name)
|
@@ -148,25 +130,43 @@ module Capybara
|
|
148
130
|
driver.reset
|
149
131
|
end
|
150
132
|
|
133
|
+
NEW_LINE = "\n"
|
134
|
+
|
151
135
|
def error_message
|
152
136
|
result = {
|
153
|
-
area_size:
|
154
|
-
region:
|
137
|
+
area_size: difference_region_area_size,
|
138
|
+
region: difference_coordinates
|
155
139
|
}
|
156
140
|
|
157
141
|
driver.adds_error_details_to(result)
|
158
142
|
|
159
|
-
[
|
143
|
+
[
|
144
|
+
"(#{result.to_json})",
|
145
|
+
new_file_name,
|
146
|
+
annotated_old_file_name,
|
147
|
+
annotated_new_file_name
|
148
|
+
].join(NEW_LINE)
|
160
149
|
end
|
161
150
|
|
162
|
-
def
|
163
|
-
|
151
|
+
def difference_coordinates
|
152
|
+
difference_region&.to_edge_coordinates
|
153
|
+
end
|
154
|
+
|
155
|
+
def difference_region_area_size
|
156
|
+
return 0 unless difference_region
|
164
157
|
|
165
|
-
|
158
|
+
difference_region.size
|
166
159
|
end
|
167
160
|
|
168
161
|
private
|
169
162
|
|
163
|
+
attr_accessor :difference_region
|
164
|
+
|
165
|
+
def different(old_image, new_image)
|
166
|
+
annotate_and_save([old_image, new_image], difference_region)
|
167
|
+
true
|
168
|
+
end
|
169
|
+
|
170
170
|
def find_driver_class_for(driver)
|
171
171
|
driver = AVAILABLE_DRIVERS.first if driver == :auto
|
172
172
|
|
@@ -183,23 +183,6 @@ module Capybara
|
|
183
183
|
end
|
184
184
|
end
|
185
185
|
|
186
|
-
def old_file_size
|
187
|
-
@old_file_size ||= old_file_exists? && File.size(@old_file_name)
|
188
|
-
end
|
189
|
-
|
190
|
-
def new_file_size
|
191
|
-
File.size(@new_file_name)
|
192
|
-
end
|
193
|
-
|
194
|
-
def not_different
|
195
|
-
clean_tmp_files
|
196
|
-
false
|
197
|
-
end
|
198
|
-
|
199
|
-
def load_images(old_file_name, new_file_name, driver = self)
|
200
|
-
[driver.from_file(old_file_name), driver.from_file(new_file_name)]
|
201
|
-
end
|
202
|
-
|
203
186
|
def preprocess_images(images, driver = self)
|
204
187
|
old_img = preprocess_image(images.first, driver)
|
205
188
|
new_img = preprocess_image(images.last, driver)
|
@@ -225,19 +208,49 @@ module Capybara
|
|
225
208
|
result
|
226
209
|
end
|
227
210
|
|
228
|
-
def
|
229
|
-
@
|
211
|
+
def old_file_size
|
212
|
+
@old_file_size ||= old_file_exists? && File.size(@old_file_name)
|
213
|
+
end
|
214
|
+
|
215
|
+
def new_file_size
|
216
|
+
File.size(@new_file_name)
|
217
|
+
end
|
218
|
+
|
219
|
+
def not_different
|
220
|
+
clean_tmp_files
|
221
|
+
false
|
230
222
|
end
|
231
223
|
|
232
224
|
def difference_region_empty?(new_image, region)
|
233
225
|
region.nil? ||
|
234
226
|
(
|
235
|
-
region
|
236
|
-
region
|
237
|
-
region
|
238
|
-
region
|
227
|
+
region.height == height_for(new_image) &&
|
228
|
+
region.width == width_for(new_image) &&
|
229
|
+
region.x.zero? &&
|
230
|
+
region.y.zero?
|
239
231
|
)
|
240
232
|
end
|
233
|
+
|
234
|
+
def annotate_and_save(images, region)
|
235
|
+
annotated_images = annotate_difference(images, region)
|
236
|
+
annotated_images = annotate_skip_areas(annotated_images, @skip_area) if @skip_area
|
237
|
+
|
238
|
+
save(*annotated_images, @annotated_old_file_name, @annotated_new_file_name)
|
239
|
+
end
|
240
|
+
|
241
|
+
DIFF_COLOR = [255, 0, 0, 255].freeze
|
242
|
+
|
243
|
+
def annotate_difference(images, region)
|
244
|
+
driver.draw_rectangles(images, region, DIFF_COLOR)
|
245
|
+
end
|
246
|
+
|
247
|
+
SKIP_COLOR = [255, 192, 0, 255].freeze
|
248
|
+
|
249
|
+
def annotate_skip_areas(annotated_images, skip_areas)
|
250
|
+
skip_areas.reduce(annotated_images) do |annotated_images, region|
|
251
|
+
driver.draw_rectangles(annotated_images, region, SKIP_COLOR)
|
252
|
+
end
|
253
|
+
end
|
241
254
|
end
|
242
255
|
end
|
243
256
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Region
|
4
|
+
attr_accessor :x, :y, :width, :height
|
5
|
+
|
6
|
+
def initialize(x, y, width, height)
|
7
|
+
@x, @y, @width, @height = x, y, width, height
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.from_top_left_corner_coordinates(x, y, width, height)
|
11
|
+
return nil unless x && y && width && height
|
12
|
+
return nil if width < 0 || height < 0
|
13
|
+
|
14
|
+
Region.new(x, y, width, height)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.from_edge_coordinates(left, top, right, bottom)
|
18
|
+
return nil unless left && top && right && bottom
|
19
|
+
return nil if right < left || bottom < top
|
20
|
+
|
21
|
+
Region.new(left, top, right - left, bottom - top)
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_edge_coordinates
|
25
|
+
[left, top, right, bottom]
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_top_left_corner_coordinates
|
29
|
+
[x, y, width, height]
|
30
|
+
end
|
31
|
+
|
32
|
+
def top
|
33
|
+
y
|
34
|
+
end
|
35
|
+
|
36
|
+
def bottom
|
37
|
+
y + height
|
38
|
+
end
|
39
|
+
|
40
|
+
def left
|
41
|
+
x
|
42
|
+
end
|
43
|
+
|
44
|
+
def right
|
45
|
+
x + width
|
46
|
+
end
|
47
|
+
|
48
|
+
def size
|
49
|
+
return 0 if width < 0 || height < 0
|
50
|
+
|
51
|
+
result = width * height
|
52
|
+
result.zero? ? 1 : result
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_a
|
56
|
+
[@x, @y, @width, @height]
|
57
|
+
end
|
58
|
+
|
59
|
+
def find_intersect_with(region)
|
60
|
+
return nil unless intersect?(region)
|
61
|
+
|
62
|
+
new_left = [x, region.x].max
|
63
|
+
new_top = [y, region.y].max
|
64
|
+
|
65
|
+
Region.new(new_left, new_top, [right, region.right].min - new_left, [bottom, region.bottom].min - new_top)
|
66
|
+
end
|
67
|
+
|
68
|
+
def intersect?(region)
|
69
|
+
left <= region.right && right >= region.left && top <= region.bottom && bottom >= region.top
|
70
|
+
end
|
71
|
+
|
72
|
+
def move_by(right_by, down_by)
|
73
|
+
Region.new(x + right_by, y + down_by, width, height)
|
74
|
+
end
|
75
|
+
|
76
|
+
def find_relative_intersect(region)
|
77
|
+
intersect = find_intersect_with(region)
|
78
|
+
return nil unless intersect
|
79
|
+
|
80
|
+
intersect.move_by(-x, -y)
|
81
|
+
end
|
82
|
+
|
83
|
+
def cover?(x, y)
|
84
|
+
left <= x && x <= right && top <= y && y <= bottom
|
85
|
+
end
|
86
|
+
end
|
@@ -8,28 +8,6 @@ module Capybara
|
|
8
8
|
module Stabilization
|
9
9
|
include Os
|
10
10
|
|
11
|
-
IMAGE_WAIT_SCRIPT = <<-JS.strip_heredoc.freeze
|
12
|
-
function pending_image() {
|
13
|
-
var images = document.images;
|
14
|
-
for (var i = 0; i < images.length; i++) {
|
15
|
-
if (!images[i].complete) {
|
16
|
-
return images[i].src;
|
17
|
-
}
|
18
|
-
}
|
19
|
-
return false;
|
20
|
-
}()
|
21
|
-
JS
|
22
|
-
|
23
|
-
HIDE_CARET_SCRIPT = <<~JS
|
24
|
-
if (!document.getElementById('csdHideCaretStyle')) {
|
25
|
-
let style = document.createElement('style');
|
26
|
-
style.setAttribute('id', 'csdHideCaretStyle');
|
27
|
-
document.head.appendChild(style);
|
28
|
-
let styleSheet = style.sheet;
|
29
|
-
styleSheet.insertRule("* { caret-color: transparent !important; }", 0);
|
30
|
-
}
|
31
|
-
JS
|
32
|
-
|
33
11
|
def take_stable_screenshot(comparison, stability_time_limit:, wait:, crop:)
|
34
12
|
previous_file_name = comparison.old_file_name
|
35
13
|
screenshot_started_at = last_image_change_at = Time.now
|
@@ -41,6 +19,7 @@ module Capybara
|
|
41
19
|
clean_stabilization_images(comparison.new_file_name)
|
42
20
|
break
|
43
21
|
end
|
22
|
+
|
44
23
|
comparison.reset
|
45
24
|
|
46
25
|
if previous_file_name
|
@@ -78,7 +57,7 @@ module Capybara
|
|
78
57
|
end
|
79
58
|
|
80
59
|
def notice_how_to_avoid_this
|
81
|
-
unless @_csd_retina_warned
|
60
|
+
unless defined?(@_csd_retina_warned)
|
82
61
|
warn "Halving retina screenshot. " \
|
83
62
|
'You should add "force-device-scale-factor=1" to your Chrome chromeOptions args.'
|
84
63
|
@_csd_retina_warned = true
|
@@ -90,7 +69,7 @@ module Capybara
|
|
90
69
|
def build_snapshot_version_file_name(comparison, iteration, screenshot_started_at, stabilization_comparison)
|
91
70
|
"#{comparison.new_file_name.chomp(".png")}" \
|
92
71
|
"_x#{format("%02i", iteration)}_#{(Time.now - screenshot_started_at).round(1)}s" \
|
93
|
-
"_#{stabilization_comparison.
|
72
|
+
"_#{stabilization_comparison.difference_coordinates&.to_s&.gsub(", ", "_") || :initial}.png" \
|
94
73
|
"#{ImageCompare::TMP_FILE_SUFFIX}"
|
95
74
|
end
|
96
75
|
|
@@ -123,18 +102,15 @@ module Capybara
|
|
123
102
|
|
124
103
|
def prepare_page_for_screenshot(timeout:)
|
125
104
|
assert_images_loaded(timeout: timeout)
|
105
|
+
|
126
106
|
if Capybara::Screenshot.blur_active_element
|
127
|
-
|
128
|
-
ae = document.activeElement;
|
129
|
-
if (ae.nodeName === "INPUT" || ae.nodeName === "TEXTAREA") {
|
130
|
-
ae.blur();
|
131
|
-
return ae;
|
132
|
-
}
|
133
|
-
return null;
|
134
|
-
JS
|
135
|
-
blurred_input = page.driver.send :unwrap_script_result, active_element
|
107
|
+
blurred_input = blur_from_focused_element
|
136
108
|
end
|
137
|
-
|
109
|
+
|
110
|
+
if Capybara::Screenshot.hide_caret
|
111
|
+
hide_caret
|
112
|
+
end
|
113
|
+
|
138
114
|
blurred_input
|
139
115
|
end
|
140
116
|
|
@@ -148,9 +124,9 @@ module Capybara
|
|
148
124
|
# ODOT
|
149
125
|
|
150
126
|
if crop
|
151
|
-
|
152
|
-
|
153
|
-
driver.save_image_to(
|
127
|
+
image = driver.from_file(comparison.new_file_name)
|
128
|
+
cropped_image = driver.crop(crop, image)
|
129
|
+
driver.save_image_to(cropped_image, comparison.new_file_name)
|
154
130
|
end
|
155
131
|
end
|
156
132
|
|
@@ -191,7 +167,7 @@ module Capybara
|
|
191
167
|
|
192
168
|
start = Time.now
|
193
169
|
loop do
|
194
|
-
pending_image =
|
170
|
+
pending_image = pending_image_to_load
|
195
171
|
break unless pending_image
|
196
172
|
|
197
173
|
assert(
|