capybara-screenshot-diff 1.6.3 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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(
|