eyes_core 3.0.4
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 +7 -0
- data/ext/eyes_core/extconf.rb +3 -0
- data/ext/eyes_core/eyes_core.c +80 -0
- data/ext/eyes_core/eyes_core.h +24 -0
- data/lib/applitools/capybara.rb +8 -0
- data/lib/applitools/chunky_png/resampling.rb +148 -0
- data/lib/applitools/chunky_png_patch.rb +8 -0
- data/lib/applitools/connectivity/proxy.rb +3 -0
- data/lib/applitools/connectivity/server_connector.rb +118 -0
- data/lib/applitools/core/app_environment.rb +29 -0
- data/lib/applitools/core/app_output.rb +17 -0
- data/lib/applitools/core/app_output_with_screenshot.rb +22 -0
- data/lib/applitools/core/argument_guard.rb +35 -0
- data/lib/applitools/core/batch_info.rb +18 -0
- data/lib/applitools/core/eyes_base.rb +463 -0
- data/lib/applitools/core/eyes_screenshot.rb +35 -0
- data/lib/applitools/core/fixed_cut_provider.rb +61 -0
- data/lib/applitools/core/fixed_scale_provider.rb +14 -0
- data/lib/applitools/core/helpers.rb +18 -0
- data/lib/applitools/core/location.rb +84 -0
- data/lib/applitools/core/match_result.rb +16 -0
- data/lib/applitools/core/match_results.rb +9 -0
- data/lib/applitools/core/match_window_data.rb +34 -0
- data/lib/applitools/core/match_window_task.rb +86 -0
- data/lib/applitools/core/mouse_trigger.rb +39 -0
- data/lib/applitools/core/rectangle_size.rb +46 -0
- data/lib/applitools/core/region.rb +180 -0
- data/lib/applitools/core/screenshot.rb +49 -0
- data/lib/applitools/core/session.rb +15 -0
- data/lib/applitools/core/session_start_info.rb +33 -0
- data/lib/applitools/core/test_results.rb +55 -0
- data/lib/applitools/core/text_trigger.rb +24 -0
- data/lib/applitools/core/trigger.rb +8 -0
- data/lib/applitools/extensions.rb +18 -0
- data/lib/applitools/eyes_logger.rb +45 -0
- data/lib/applitools/images/eyes.rb +204 -0
- data/lib/applitools/images/eyes_images_screenshot.rb +102 -0
- data/lib/applitools/method_tracer.rb +23 -0
- data/lib/applitools/sauce.rb +2 -0
- data/lib/applitools/utils/eyes_selenium_utils.rb +348 -0
- data/lib/applitools/utils/image_delta_compressor.rb +146 -0
- data/lib/applitools/utils/image_utils.rb +146 -0
- data/lib/applitools/utils/utils.rb +68 -0
- data/lib/applitools/version.rb +3 -0
- data/lib/eyes_core.rb +70 -0
- metadata +273 -0
@@ -0,0 +1,102 @@
|
|
1
|
+
module Applitools::Images
|
2
|
+
# @!visibility private
|
3
|
+
class EyesImagesScreenshot < ::Applitools::EyesScreenshot
|
4
|
+
SCREENSHOT_AS_IS = Applitools::EyesScreenshot::COORDINATE_TYPES[:screenshot_as_is].freeze
|
5
|
+
CONTEXT_RELATIVE = Applitools::EyesScreenshot::COORDINATE_TYPES[:context_relative].freeze
|
6
|
+
|
7
|
+
def initialize(image, options = {})
|
8
|
+
super image
|
9
|
+
return if (location = options[:location]).nil?
|
10
|
+
Applitools::ArgumentGuard.is_a? location, 'options[:location]', Applitools::Location
|
11
|
+
@bounds = Applitools::Region.new location.x, location.y, image.width, image.height
|
12
|
+
end
|
13
|
+
|
14
|
+
def convert_location(location, from, to)
|
15
|
+
Applitools::ArgumentGuard.not_nil location, 'location'
|
16
|
+
Applitools::ArgumentGuard.not_nil from, 'from'
|
17
|
+
Applitools::ArgumentGuard.not_nil to, 'to'
|
18
|
+
|
19
|
+
Applitools::ArgumentGuard.is_a? location, 'location', Applitools::Location
|
20
|
+
|
21
|
+
result = Applitools::Location.new location.x, location.y
|
22
|
+
return result if from == to
|
23
|
+
|
24
|
+
case from
|
25
|
+
when SCREENSHOT_AS_IS
|
26
|
+
raise "Coordinate type conversation error: #{from} -> #{to}" unless to == CONTEXT_RELATIVE
|
27
|
+
result.offset bounds
|
28
|
+
return result
|
29
|
+
when CONTEXT_RELATIVE
|
30
|
+
raise "Coordinate type conversation error: #{from} -> #{to}" unless to == SCREENSHOT_AS_IS
|
31
|
+
result.offset(Applitools::Location.new(-bounds.x, -bounds.y))
|
32
|
+
return result
|
33
|
+
else
|
34
|
+
raise "Coordinate type conversation error: #{from} -> #{to}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def convert_region_location(region, from, to)
|
39
|
+
Applitools::ArgumentGuard.not_nil region, 'region'
|
40
|
+
return Core::Region.new(0, 0, 0, 0) if region.empty?
|
41
|
+
|
42
|
+
Applitools::ArgumentGuard.not_nil from, 'from'
|
43
|
+
Applitools::ArgumentGuard.not_nil to, 'to'
|
44
|
+
|
45
|
+
updated_location = convert_location region.location, from, to
|
46
|
+
|
47
|
+
Applitools::Region.new updated_location.x, updated_location.y, region.width, region.height
|
48
|
+
end
|
49
|
+
|
50
|
+
def intersected_region(region, from, to = CONTEXT_RELATIVE)
|
51
|
+
Applitools::ArgumentGuard.not_nil region, 'region'
|
52
|
+
Applitools::ArgumentGuard.not_nil from, 'coordinates Type (from)'
|
53
|
+
|
54
|
+
return Applitools::Region.new(0, 0, 0, 0) if region.empty?
|
55
|
+
|
56
|
+
intersected_region = convert_region_location region, from, to
|
57
|
+
intersected_region.intersect bounds
|
58
|
+
return intersected_region if intersected_region.empty?
|
59
|
+
|
60
|
+
intersected_region.location = convert_location intersected_region.location, to, from
|
61
|
+
intersected_region
|
62
|
+
end
|
63
|
+
|
64
|
+
def location_in_screenshot(location, coordinates_type)
|
65
|
+
Applitools::ArgumentGuard.not_nil location, 'location'
|
66
|
+
Applitools::ArgumentGuard.not_nil coordinates_type, 'coordinates_type'
|
67
|
+
location = convert_location(location, coordinates_type, CONTEXT_RELATIVE)
|
68
|
+
|
69
|
+
unless bounds.contains? location.left, location.top
|
70
|
+
raise Applitools::OutOfBoundsException.new "Location #{location} is not available in screenshot!"
|
71
|
+
end
|
72
|
+
|
73
|
+
convert_location location, CONTEXT_RELATIVE, SCREENSHOT_AS_IS
|
74
|
+
end
|
75
|
+
|
76
|
+
def sub_screenshot(region, coordinates_type, throw_if_clipped)
|
77
|
+
Applitools::ArgumentGuard.not_nil region, 'region'
|
78
|
+
Applitools::ArgumentGuard.not_nil coordinates_type, 'coordinates_type'
|
79
|
+
|
80
|
+
sub_screen_region = intersected_region region, coordinates_type, SCREENSHOT_AS_IS
|
81
|
+
|
82
|
+
if sub_screen_region.empty? || (throw_if_clipped && !region.size_equals?(sub_screen_region))
|
83
|
+
Applitools::OutOfBoundsException.new "Region #{sub_screen_region} (#{coordinates_type}) is out of " \
|
84
|
+
" screenshot bounds #{bounds}"
|
85
|
+
end
|
86
|
+
|
87
|
+
sub_screenshot_image = Applitools::Screenshot.new image.crop(sub_screen_region.left, sub_screen_region.top,
|
88
|
+
sub_screen_region.width, sub_screen_region.height).to_datastream.to_blob
|
89
|
+
|
90
|
+
relative_sub_screenshot_region = convert_region_location(sub_screen_region, SCREENSHOT_AS_IS, CONTEXT_RELATIVE)
|
91
|
+
|
92
|
+
Applitools::Images::EyesImagesScreenshot.new sub_screenshot_image,
|
93
|
+
location: relative_sub_screenshot_region.location
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def bounds
|
99
|
+
@bounds ||= Applitools::Region.new(0, 0, image.width, image.height)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# @!visibility private
|
2
|
+
module Applitools::MethodTracer
|
3
|
+
def self.included(base)
|
4
|
+
instance_methods = base.instance_methods(false) + base.private_instance_methods(false)
|
5
|
+
class_methods = base.methods(false)
|
6
|
+
|
7
|
+
base.class_eval do
|
8
|
+
def self.trace_method(base, method_name, instance = true)
|
9
|
+
original_method = instance ? instance_method(method_name) : method(method_name)
|
10
|
+
|
11
|
+
send(instance ? :define_method : :define_singleton_method, method_name) do |*args, &block|
|
12
|
+
Applitools::EyesLogger.debug "-> #{base}##{method_name}"
|
13
|
+
return_value = (instance ? original_method.bind(self) : original_method).call(*args, &block)
|
14
|
+
Applitools::EyesLogger.debug "<- #{base}##{method_name}"
|
15
|
+
return_value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
instance_methods.each { |method_name| trace_method(base, method_name) }
|
20
|
+
class_methods.each { |method_name| trace_method(base, method_name, false) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,348 @@
|
|
1
|
+
module Applitools::Utils
|
2
|
+
module EyesSeleniumUtils
|
3
|
+
extend self
|
4
|
+
|
5
|
+
# @!visibility private
|
6
|
+
JS_GET_VIEWPORT_SIZE = <<-JS.freeze
|
7
|
+
return (function() {
|
8
|
+
var height = undefined;
|
9
|
+
var width = undefined;
|
10
|
+
if (window.innerHeight) {height = window.innerHeight;}
|
11
|
+
else if (document.documentElement && document.documentElement.clientHeight)
|
12
|
+
{height = document.documentElement.clientHeight;}
|
13
|
+
else { var b = document.getElementsByTagName('body')[0];
|
14
|
+
if (b.clientHeight) {height = b.clientHeight;}
|
15
|
+
};
|
16
|
+
|
17
|
+
if (window.innerWidth) {width = window.innerWidth;}
|
18
|
+
else if (document.documentElement && document.documentElement.clientWidth)
|
19
|
+
{width = document.documentElement.clientWidth;}
|
20
|
+
else { var b = document.getElementsByTagName('body')[0];
|
21
|
+
if (b.clientWidth) {width = b.clientWidth;}
|
22
|
+
};
|
23
|
+
return [width, height];
|
24
|
+
}());
|
25
|
+
JS
|
26
|
+
|
27
|
+
# @!visibility private
|
28
|
+
JS_GET_USER_AGENT = <<-JS.freeze
|
29
|
+
return navigator.userAgent;
|
30
|
+
JS
|
31
|
+
|
32
|
+
# @!visibility private
|
33
|
+
JS_GET_DEVICE_PIXEL_RATIO = <<-JS.freeze
|
34
|
+
return window.devicePixelRatio;
|
35
|
+
JS
|
36
|
+
|
37
|
+
# @!visibility private
|
38
|
+
JS_GET_PAGE_METRICS = <<-JS.freeze
|
39
|
+
return {
|
40
|
+
scrollWidth: document.documentElement.scrollWidth,
|
41
|
+
bodyScrollWidth: document.body.scrollWidth,
|
42
|
+
clientHeight: document.documentElement.clientHeight,
|
43
|
+
bodyClientHeight: document.body.clientHeight,
|
44
|
+
scrollHeight: document.documentElement.scrollHeight,
|
45
|
+
bodyScrollHeight: document.body.scrollHeight
|
46
|
+
};
|
47
|
+
JS
|
48
|
+
|
49
|
+
# @!visibility private
|
50
|
+
JS_GET_CONTENT_ENTIRE_SIZE = <<-JS.freeze
|
51
|
+
var scrollWidth = document.documentElement.scrollWidth;
|
52
|
+
var bodyScrollWidth = document.body.scrollWidth;
|
53
|
+
var totalWidth = Math.max(scrollWidth, bodyScrollWidth);
|
54
|
+
var clientHeight = document.documentElement.clientHeight;
|
55
|
+
var bodyClientHeight = document.body.clientHeight;
|
56
|
+
var scrollHeight = document.documentElement.scrollHeight;
|
57
|
+
var bodyScrollHeight = document.body.scrollHeight;
|
58
|
+
var maxDocElementHeight = Math.max(clientHeight, scrollHeight);
|
59
|
+
var maxBodyHeight = Math.max(bodyClientHeight, bodyScrollHeight);
|
60
|
+
var totalHeight = Math.max(maxDocElementHeight, maxBodyHeight);
|
61
|
+
return [totalWidth, totalHeight];
|
62
|
+
JS
|
63
|
+
|
64
|
+
# @!visibility private
|
65
|
+
JS_GET_CURRENT_SCROLL_POSITION = <<-JS.freeze
|
66
|
+
return (function() {
|
67
|
+
var doc = document.documentElement;
|
68
|
+
var x = (window.scrollX || window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0);
|
69
|
+
var y = (window.scrollY || window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);
|
70
|
+
|
71
|
+
return {left: parseInt(x, 10) || 0, top: parseInt(y, 10) || 0};
|
72
|
+
}());
|
73
|
+
JS
|
74
|
+
|
75
|
+
# @!visibility private
|
76
|
+
JS_SCROLL_TO = <<-JS.freeze
|
77
|
+
window.scrollTo(%{left}, %{top});
|
78
|
+
JS
|
79
|
+
|
80
|
+
# @!visibility private
|
81
|
+
JS_GET_CURRENT_TRANSFORM = <<-JS.freeze
|
82
|
+
return document.body.style.transform;
|
83
|
+
JS
|
84
|
+
|
85
|
+
# @!visibility private
|
86
|
+
JS_SET_TRANSFORM = <<-JS.freeze
|
87
|
+
return (function() {
|
88
|
+
var originalTransform = document.body.style.transform;
|
89
|
+
document.body.style.transform = '%{transform}';
|
90
|
+
return originalTransform;
|
91
|
+
}());
|
92
|
+
JS
|
93
|
+
|
94
|
+
# @!visibility private
|
95
|
+
JS_SET_OVERFLOW = <<-JS.freeze
|
96
|
+
return (function() {
|
97
|
+
var origOF = document.documentElement.style.overflow;
|
98
|
+
document.documentElement.style.overflow = '%{overflow}';
|
99
|
+
return origOF;
|
100
|
+
}());
|
101
|
+
JS
|
102
|
+
|
103
|
+
JS_GET_TRANSFORM_VALUE = <<-JS.freeze
|
104
|
+
document.documentElement.style['%{key}']
|
105
|
+
JS
|
106
|
+
|
107
|
+
JS_SET_TRANSFORM_VALUE = <<-JS.freeze
|
108
|
+
document.documentElement.style['%{key}'] = '%{value}'
|
109
|
+
JS
|
110
|
+
|
111
|
+
JS_TRANSFORM_KEYS = ['transform', '-webkit-transform'].freeze
|
112
|
+
|
113
|
+
# @!visibility private
|
114
|
+
OVERFLOW_HIDDEN = 'hidden'.freeze
|
115
|
+
|
116
|
+
BROWSER_SIZE_CALCULATION_RETRIES = 3
|
117
|
+
|
118
|
+
# Number of attemts to set browser size
|
119
|
+
VERIFY_RETRIES = 3
|
120
|
+
|
121
|
+
# A time delay (in seconds) before next attempt to set browser size
|
122
|
+
VERIFY_SLEEP_PERIOD = 1
|
123
|
+
|
124
|
+
# Maximum different (in pixels) between calculated browser size and real browser size when it tries to achieve
|
125
|
+
# target size incrementally
|
126
|
+
MAX_DIFF = 3
|
127
|
+
|
128
|
+
# true if test is running on mobile device
|
129
|
+
def mobile_device?
|
130
|
+
return $driver if $driver && $driver.is_a?(Appium::Driver)
|
131
|
+
nil
|
132
|
+
end
|
133
|
+
|
134
|
+
# true if test is running on Android device
|
135
|
+
def android?(driver)
|
136
|
+
driver.respond_to?(:appium_device) && driver.appium_device == :android
|
137
|
+
end
|
138
|
+
|
139
|
+
# true if test is running on iOS device
|
140
|
+
def ios?(driver)
|
141
|
+
driver.respond_to?(:appium_device) && driver.appium_device == :ios
|
142
|
+
end
|
143
|
+
|
144
|
+
# @param [Applitools::Selenium::Driver] driver
|
145
|
+
def platform_version(driver)
|
146
|
+
driver.respond_to?(:caps) && driver.caps[:platformVersion]
|
147
|
+
end
|
148
|
+
|
149
|
+
# @param [Applitools::Selenium::Driver] executor
|
150
|
+
# @return [Applitools::Location] {Applitools::Location} instance which indicates current scroll
|
151
|
+
# position
|
152
|
+
def current_scroll_position(executor)
|
153
|
+
position = Applitools::Utils.symbolize_keys executor.execute_script(JS_GET_CURRENT_SCROLL_POSITION).to_hash
|
154
|
+
Applitools::Location.new position[:left], position[:top]
|
155
|
+
end
|
156
|
+
|
157
|
+
# scrolls browser to position specified by point.
|
158
|
+
# @param [Applitools::Selenium::Driver] executor
|
159
|
+
# @param [Applitools::Location] point position to scroll to. It can be any object,
|
160
|
+
# having left and top properties
|
161
|
+
def scroll_to(executor, point)
|
162
|
+
with_timeout(0.25) { executor.execute_script(JS_SCROLL_TO % { left: point.left, top: point.top }) }
|
163
|
+
end
|
164
|
+
|
165
|
+
# @param [Applitools::Selenium::Driver] executor
|
166
|
+
def extract_viewport_size(executor)
|
167
|
+
Applitools::EyesLogger.debug 'extract_viewport_size()'
|
168
|
+
|
169
|
+
begin
|
170
|
+
width, height = executor.execute_script(JS_GET_VIEWPORT_SIZE)
|
171
|
+
result = Applitools::RectangleSize.from_any_argument width: width, height: height
|
172
|
+
Applitools::EyesLogger.debug "Viewport size is #{result}."
|
173
|
+
return result
|
174
|
+
rescue => e
|
175
|
+
Applitools::EyesLogger.error "Failed extracting viewport size using JavaScript: (#{e.message})"
|
176
|
+
end
|
177
|
+
|
178
|
+
Applitools::EyesLogger.info 'Using window size as viewport size.'
|
179
|
+
|
180
|
+
width, height = executor.manage.window.size.to_a
|
181
|
+
width, height = height, width if executor.landscape_orientation? && height > width
|
182
|
+
|
183
|
+
result = Applitools::RectangleSize.new width, height
|
184
|
+
Applitools::EyesLogger.debug "Viewport size is #{result}."
|
185
|
+
result
|
186
|
+
end
|
187
|
+
|
188
|
+
# @param [Applitools::Selenium::Driver] executor
|
189
|
+
def entire_page_size(executor)
|
190
|
+
metrics = page_metrics(executor)
|
191
|
+
max_document_element_height = [metrics[:client_height], metrics[:scroll_height]].max
|
192
|
+
max_body_height = [metrics[:body_client_height], metrics[:body_scroll_height]].max
|
193
|
+
|
194
|
+
total_width = [metrics[:scroll_width], metrics[:body_scroll_width]].max
|
195
|
+
total_height = [max_document_element_height, max_body_height].max
|
196
|
+
|
197
|
+
Applitools::RectangleSize.new(total_width, total_height)
|
198
|
+
end
|
199
|
+
|
200
|
+
def current_frame_content_entire_size(executor)
|
201
|
+
dimensions = executor.execute_script(JS_GET_CONTENT_ENTIRE_SIZE)
|
202
|
+
Applitools::RectangleSize.new(dimensions.first.to_i, dimensions.last.to_i)
|
203
|
+
rescue
|
204
|
+
raise Applitools::EyesDriverOperationException.new 'Failed to extract entire size!'
|
205
|
+
end
|
206
|
+
|
207
|
+
def current_transforms(executor)
|
208
|
+
script =
|
209
|
+
"return { #{JS_TRANSFORM_KEYS.map { |tk| "'#{tk}': #{JS_GET_TRANSFORM_VALUE % { key: tk }}" }.join(', ')} };"
|
210
|
+
executor.execute_script(script)
|
211
|
+
end
|
212
|
+
|
213
|
+
def set_current_transforms(executor, transform)
|
214
|
+
value = {}
|
215
|
+
JS_TRANSFORM_KEYS.map { |tk| value[tk] = transform }
|
216
|
+
set_transforms(executor, value)
|
217
|
+
end
|
218
|
+
|
219
|
+
def set_transforms(executor, value)
|
220
|
+
script = value.keys.map { |k| JS_SET_TRANSFORM_VALUE % { key: k, value: value[k] } }.join('; ')
|
221
|
+
executor.execute_script(script)
|
222
|
+
end
|
223
|
+
|
224
|
+
def translate_to(executor, location)
|
225
|
+
set_current_transforms(executor, "translate(-#{location.x}px, -#{location.y}px)")
|
226
|
+
end
|
227
|
+
|
228
|
+
# @param [Applitools::Selenium::Driver] executor
|
229
|
+
def device_pixel_ratio(executor)
|
230
|
+
executor.execute_script(JS_GET_DEVICE_PIXEL_RATIO)
|
231
|
+
end
|
232
|
+
|
233
|
+
# @param [Applitools::Selenium::Driver] executor
|
234
|
+
def page_metrics(executor)
|
235
|
+
Applitools::Utils.underscore_hash_keys(executor.execute_script(JS_GET_PAGE_METRICS))
|
236
|
+
end
|
237
|
+
|
238
|
+
# @param [Applitools::Selenium::Driver] executor
|
239
|
+
def hide_scrollbars(executor)
|
240
|
+
set_overflow executor, OVERFLOW_HIDDEN
|
241
|
+
end
|
242
|
+
|
243
|
+
# @param [Applitools::Selenium::Driver] executor
|
244
|
+
def set_overflow(executor, overflow)
|
245
|
+
with_timeout(0.1) { executor.execute_script(JS_SET_OVERFLOW % { overflow: overflow }) }
|
246
|
+
end
|
247
|
+
|
248
|
+
# @param [Applitools::Selenium::Driver] executor
|
249
|
+
# @param [Applitools::RectangleSize] viewport_size
|
250
|
+
def set_viewport_size(executor, viewport_size)
|
251
|
+
Applitools::ArgumentGuard.not_nil 'viewport_size', viewport_size
|
252
|
+
Applitools::EyesLogger.info "Set viewport size #{viewport_size}"
|
253
|
+
|
254
|
+
required_size = Applitools::RectangleSize.from_any_argument viewport_size
|
255
|
+
actual_viewport_size = Applitools::RectangleSize.from_any_argument(extract_viewport_size(executor))
|
256
|
+
|
257
|
+
Applitools::EyesLogger.info "Initial viewport size: #{actual_viewport_size}"
|
258
|
+
|
259
|
+
if actual_viewport_size == required_size
|
260
|
+
Applitools::EyesLogger.info 'Required size is already set.'
|
261
|
+
return
|
262
|
+
end
|
263
|
+
|
264
|
+
# Before resizing the window, set its position to the upper left corner (otherwise, there might not be enough
|
265
|
+
# "space" below/next to it and the operation won't be successful).
|
266
|
+
begin
|
267
|
+
executor.manage.window.position = Selenium::WebDriver::Point.new(0, 0)
|
268
|
+
rescue Selenium::WebDriver::Error::UnsupportedOperationError => e
|
269
|
+
Applitools::EyesLogger.error e.message << '\n Continue...'
|
270
|
+
end
|
271
|
+
|
272
|
+
set_browser_size_by_viewport_size(executor, actual_viewport_size, required_size)
|
273
|
+
|
274
|
+
actual_viewport_size = extract_viewport_size(executor)
|
275
|
+
return if actual_viewport_size == required_size
|
276
|
+
|
277
|
+
# Additional attempt. This Solves the "maximized browser" bug
|
278
|
+
# (border size for maximized browser sometimes different than
|
279
|
+
# non-maximized, so the original browser size calculation is
|
280
|
+
# wrong).
|
281
|
+
|
282
|
+
Applitools::EyesLogger.info 'Trying workaround for maximization...'
|
283
|
+
|
284
|
+
set_browser_size_by_viewport_size(executor, actual_viewport_size, required_size)
|
285
|
+
|
286
|
+
actual_viewport_size = extract_viewport_size(executor)
|
287
|
+
Applitools::EyesLogger.info "Current viewport size: #{actual_viewport_size}"
|
288
|
+
return if actual_viewport_size == required_size
|
289
|
+
|
290
|
+
width_diff = actual_viewport_size.width - required_size.width
|
291
|
+
width_step = width_diff > 0 ? -1 : 1
|
292
|
+
height_diff = actual_viewport_size.height - required_size.height
|
293
|
+
height_step = height_diff > 0 ? -1 : 1
|
294
|
+
|
295
|
+
browser_size = Applitools::RectangleSize.from_any_argument(executor.manage.window.size)
|
296
|
+
|
297
|
+
current_width_change = 0
|
298
|
+
current_height_change = 0
|
299
|
+
|
300
|
+
if width_diff.abs <= MAX_DIFF && height_diff <= MAX_DIFF
|
301
|
+
Applitools::EyesLogger.info 'Trying workaround for zoom...'
|
302
|
+
while current_width_change.abs <= width_diff && current_height_change.abs <= height_diff
|
303
|
+
|
304
|
+
current_width_change += width_step if actual_viewport_size.width != required_size.width
|
305
|
+
current_height_change += height_step if actual_viewport_size.height != required_size.height
|
306
|
+
|
307
|
+
set_browser_size executor,
|
308
|
+
browser_size.dup + Applitools::RectangleSize.new(current_width_change, current_height_change)
|
309
|
+
|
310
|
+
actual_viewport_size = Applitools::RectangleSize.from_any_argument extract_viewport_size(executor)
|
311
|
+
Applitools::EyesLogger.info "Current viewport size: #{actual_viewport_size}"
|
312
|
+
return if actual_viewport_size == required_size
|
313
|
+
end
|
314
|
+
Applitools::EyesLogger.error 'Zoom workaround failed.'
|
315
|
+
end
|
316
|
+
|
317
|
+
raise Applitools::TestFailedError.new 'Failed to set viewport size'
|
318
|
+
end
|
319
|
+
|
320
|
+
def set_browser_size(executor, required_size)
|
321
|
+
retries_left = VERIFY_RETRIES
|
322
|
+
current_size = Applitools::RectangleSize.new(0, 0)
|
323
|
+
while retries_left > 0 && current_size != required_size
|
324
|
+
Applitools::EyesLogger.info "Trying to set browser size to #{required_size}"
|
325
|
+
executor.manage.window.size = required_size
|
326
|
+
sleep VERIFY_SLEEP_PERIOD
|
327
|
+
current_size = Applitools::RectangleSize.from_any_argument(executor.manage.window.size)
|
328
|
+
Applitools::EyesLogger.info "Current browser size: #{required_size}"
|
329
|
+
retries_left -= 1
|
330
|
+
end
|
331
|
+
current_size == required_size
|
332
|
+
end
|
333
|
+
|
334
|
+
def set_browser_size_by_viewport_size(executor, actual_viewport_size, required_size)
|
335
|
+
browser_size = Applitools::RectangleSize.from_any_argument(executor.manage.window.size)
|
336
|
+
Applitools::EyesLogger.info "Current browser size: #{browser_size}"
|
337
|
+
required_browser_size = browser_size + required_size - actual_viewport_size
|
338
|
+
set_browser_size(executor, required_browser_size)
|
339
|
+
end
|
340
|
+
|
341
|
+
private
|
342
|
+
|
343
|
+
def with_timeout(timeout, &_block)
|
344
|
+
raise 'You have to pass block to method with_timeout' unless block_given?
|
345
|
+
yield.tap { sleep timeout }
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|