Module: Applitools::Utils::EyesSeleniumUtils

Extended by:
EyesSeleniumUtils
Included in:
EyesSeleniumUtils
Defined in:
lib/applitools/utils/eyes_selenium_utils.rb

Constant Summary collapse

JS_GET_TRANSFORM_VALUE =

JS_GET_TRANSFORM_VALUE = <<-JS.freeze

document.documentElement.style['%{key}']

JS

JS_SET_TRANSFORM_VALUE = <<-JS.freeze

document.documentElement.style['%{key}'] = '%{value}'

JS

<<-JS.freeze
  %{element}.style['%{key}']
JS
JS_SET_TRANSFORM_VALUE =
<<-JS.freeze
  %{element}.style['%{key}'] = '%{value}'
JS
JS_TRANSFORM_KEYS =
['transform', '-webkit-transform', '-ms-transform', '-moz-transform'].freeze
BROWSER_SIZE_CALCULATION_RETRIES =
3
VERIFY_RETRIES =

Number of attemts to set browser size

3
VERIFY_SLEEP_PERIOD =

A time delay (in seconds) before next attempt to set browser size

1
MAX_DIFF =

Maximum different (in pixels) between calculated browser size and real browser size when it tries to achieve target size incrementally

3

Instance Method Summary collapse

Instance Method Details

#android?(_driver) ⇒ Boolean

true if test is running on Android device

Returns:

  • (Boolean)


174
175
176
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 174

def android?(_driver)
  false
end

#current_element_transforms(executor, element) ⇒ Object



291
292
293
294
295
296
297
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 291

def current_element_transforms(executor, element)
  transform_script = JS_TRANSFORM_KEYS.map do |tk|
    "'#{tk}': #{JS_GET_TRANSFORM_VALUE % { element: 'arguments[0]', key: tk }}"
  end.join(', ')
  script = "return { #{transform_script} };"
  executor.execute_script(script, element)
end

#current_frame_content_entire_size(executor) ⇒ Object



247
248
249
250
251
252
253
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 247

def current_frame_content_entire_size(executor)
  return Applitools::MOCK_ENTIRE_SIZE if defined?(Applitools::MOCK_ENTIRE_SIZE)
  dimensions = executor.execute_script(JS_GET_CONTENT_ENTIRE_SIZE)
  Applitools::RectangleSize.new(dimensions.first.to_i, dimensions.last.to_i)
rescue
  raise Applitools::EyesDriverOperationException.new 'Failed to extract entire size!'
end

#current_scroll_position(executor) ⇒ Applitools::Location

Returns Location instance which indicates current scroll position.

Parameters:

  • executor (Applitools::Selenium::Driver)

Returns:



197
198
199
200
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 197

def current_scroll_position(executor)
  position = Applitools::Utils.symbolize_keys executor.execute_script(JS_GET_CURRENT_SCROLL_POSITION).to_hash
  Applitools::Location.new position[:left], position[:top]
end

#current_transforms(executor) ⇒ Object



255
256
257
258
259
260
261
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 255

def current_transforms(executor)
  transform_script = JS_TRANSFORM_KEYS.map do |tk|
    "'#{tk}': #{JS_GET_TRANSFORM_VALUE % { element: 'document.documentElement', key: tk }}"
  end.join(', ')
  script = "return { #{transform_script} };"
  executor.execute_script(script)
end

#device_pixel_ratio(executor) ⇒ Object

Parameters:

  • executor (Applitools::Selenium::Driver)


309
310
311
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 309

def device_pixel_ratio(executor)
  executor.execute_script(JS_GET_DEVICE_PIXEL_RATIO)
end

#element_translate_to(executor, element, location) ⇒ Object



304
305
306
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 304

def element_translate_to(executor, element, location)
  set_element_transforms(executor, element, "translate(#{location.x}px, #{location.y}px)")
end

#entire_page_size(executor) ⇒ Object

Parameters:

  • executor (Applitools::Selenium::Driver)


235
236
237
238
239
240
241
242
243
244
245
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 235

def entire_page_size(executor)
  return Applitools::MOCK_ENTIRE_SIZE if defined?(Applitools::MOCK_ENTIRE_SIZE)
  metrics = page_metrics(executor)
  max_document_element_height = [metrics[:client_height], metrics[:scroll_height]].max
  max_body_height = [metrics[:body_client_height], metrics[:body_scroll_height]].max

  total_width = [metrics[:scroll_width], metrics[:body_scroll_width]].max
  total_height = [max_document_element_height, max_body_height].max

  Applitools::RectangleSize.new(total_width, total_height)
end

#extract_viewport_size(executor) ⇒ Object

Parameters:

  • executor (Applitools::Selenium::Driver)


211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 211

def extract_viewport_size(executor)
  Applitools::EyesLogger.debug 'extract_viewport_size()'

  result = if defined?(Applitools::Appium::Driver) && executor.is_a?(Applitools::Appium::Driver)
             Applitools::RectangleSize.from_any_argument(executor.window_size)
           else
             begin
               width, height = executor.execute_script(JS_GET_VIEWPORT_SIZE)
               Applitools::RectangleSize.from_any_argument width: width, height: height
             rescue => e
               Applitools::EyesLogger.error "Failed extracting viewport size using JavaScript: (#{e.message})"
               Applitools::EyesLogger.info 'Using window size as viewport size.'

               width, height = executor.manage.window.size.to_a
               width, height = height, width if executor.landscape_orientation? && height > width

               Applitools::RectangleSize.new width, height
             end
           end
  Applitools::EyesLogger.debug "Viewport size is #{result}."
  result
end

#hide_scrollbars(executor) ⇒ Object

Parameters:

  • executor (Applitools::Selenium::Driver)


319
320
321
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 319

def hide_scrollbars(executor)
  set_overflow executor, OVERFLOW_HIDDEN
end

#ios?(_driver) ⇒ Boolean

true if test is running on iOS device

Returns:

  • (Boolean)


179
180
181
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 179

def ios?(_driver)
  false
end

#mobile_device?(_driver) ⇒ Boolean

true if test is running on mobile device

Returns:

  • (Boolean)


169
170
171
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 169

def mobile_device?(_driver)
  nil
end

#page_metrics(executor) ⇒ Object

Parameters:

  • executor (Applitools::Selenium::Driver)


314
315
316
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 314

def page_metrics(executor)
  Applitools::Utils.underscore_hash_keys(executor.execute_script(JS_GET_PAGE_METRICS))
end

#platform_version(_driver) ⇒ Object

Parameters:

  • driver (Applitools::Selenium::Driver)


184
185
186
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 184

def platform_version(_driver)
  nil
end

#scroll_to(executor, point) ⇒ Object

scrolls browser to position specified by point.

Parameters:

  • executor (Applitools::Selenium::Driver)
  • point (Applitools::Location)

    position to scroll to. It can be any object, having left and top properties



206
207
208
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 206

def scroll_to(executor, point)
  with_timeout(0.25) { executor.execute_script(JS_SCROLL_TO % { left: point.left, top: point.top }) }
end

#scroll_to_bottom_right(executor) ⇒ Object



429
430
431
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 429

def scroll_to_bottom_right(executor)
  executor.execute_script(JS_SCROLL_TO_BOTTOM_RIGHT)
end

#set_browser_size(executor, required_size) ⇒ Object



400
401
402
403
404
405
406
407
408
409
410
411
412
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 400

def set_browser_size(executor, required_size)
  retries_left = VERIFY_RETRIES
  current_size = Applitools::RectangleSize.new(0, 0)
  while retries_left > 0 && current_size != required_size
    Applitools::EyesLogger.info "Trying to set browser size to #{required_size}"
    executor.manage.window.size = required_size
    sleep VERIFY_SLEEP_PERIOD
    current_size = Applitools::RectangleSize.from_any_argument(executor.manage.window.size)
    Applitools::EyesLogger.info "Current browser size: #{required_size}"
    retries_left -= 1
  end
  current_size == required_size
end

#set_browser_size_by_viewport_size(executor, actual_viewport_size, required_size) ⇒ Object



414
415
416
417
418
419
420
421
422
423
424
425
426
427
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 414

def set_browser_size_by_viewport_size(executor, actual_viewport_size, required_size)
  browser_size = executor.manage.window.size
  if browser_size.width.nil? || browser_size.height.nil?
    raise(
      Applitools::EyesError,
      'driver.manage.window.size returned nil values. ' \
      'Please ensure that you use the latest version of browser and its driver!'
    )
  end
  browser_size = Applitools::RectangleSize.from_any_argument(browser_size)
  Applitools::EyesLogger.info "Current browser size: #{browser_size}"
  required_browser_size = browser_size + required_size - actual_viewport_size
  set_browser_size(executor, required_browser_size)
end

#set_current_transforms(executor, transform) ⇒ Object



263
264
265
266
267
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 263

def set_current_transforms(executor, transform)
  value = {}
  JS_TRANSFORM_KEYS.map { |tk| value[tk] = transform }
  set_transforms(executor, value)
end

#set_element_transforms(executor, element, transform) ⇒ Object



282
283
284
285
286
287
288
289
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 282

def set_element_transforms(executor, element, transform)
  value = {}
  JS_TRANSFORM_KEYS.map { |tk| value[tk] = transform }
  script = value.keys.map do |k|
    JS_SET_TRANSFORM_VALUE % { element: 'arguments[0]', key: k, value: value[k] }
  end.join('; ')
  executor.execute_script(script, element)
end

#set_overflow(executor, overflow) ⇒ Object

Parameters:

  • executor (Applitools::Selenium::Driver)


324
325
326
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 324

def set_overflow(executor, overflow)
  with_timeout(0.1) { executor.execute_script(JS_SET_OVERFLOW % { overflow: overflow }) }
end

#set_transforms(executor, value) ⇒ Object



269
270
271
272
273
274
275
276
277
278
279
280
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 269

def set_transforms(executor, value)
  root_element =
    executor.browser.running_browser_name == :internet_explorer ? 'document.body' : 'document.documentElement'
  script = value.keys.map do |k|
    JS_SET_TRANSFORM_VALUE % {
      element: root_element,
      key: k,
      value: value[k]
    }
  end.join('; ')
  executor.execute_script(script)
end

#set_viewport_size(executor, viewport_size) ⇒ Object

Parameters:



330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 330

def set_viewport_size(executor, viewport_size)
  Applitools::ArgumentGuard.not_nil 'viewport_size', viewport_size
  Applitools::EyesLogger.info "Set viewport size #{viewport_size}"

  required_size = Applitools::RectangleSize.from_any_argument viewport_size
  actual_viewport_size = Applitools::RectangleSize.from_any_argument(extract_viewport_size(executor))

  Applitools::EyesLogger.info "Initial viewport size: #{actual_viewport_size}"

  if actual_viewport_size == required_size
    Applitools::EyesLogger.info 'Required size is already set.'
    return
  end

  # Before resizing the window, set its position to the upper left corner (otherwise, there might not be enough
  # "space" below/next to it and the operation won't be successful).
  begin
    executor.manage.window.position = Selenium::WebDriver::Point.new(0, 0)
  rescue Selenium::WebDriver::Error::UnsupportedOperationError => e
    Applitools::EyesLogger.error e.message << '\n Continue...'
  end

  set_browser_size_by_viewport_size(executor, actual_viewport_size, required_size)

  actual_viewport_size = extract_viewport_size(executor)
  return if actual_viewport_size == required_size

  # Additional attempt. This Solves the "maximized browser" bug
  # (border size for maximized browser sometimes different than
  # non-maximized, so the original browser size calculation is
  # wrong).

  Applitools::EyesLogger.info 'Trying workaround for maximization...'

  set_browser_size_by_viewport_size(executor, actual_viewport_size, required_size)

  actual_viewport_size = extract_viewport_size(executor)
  Applitools::EyesLogger.info "Current viewport size: #{actual_viewport_size}"
  return if actual_viewport_size == required_size

  width_diff = actual_viewport_size.width - required_size.width
  width_step = width_diff > 0 ? -1 : 1
  height_diff = actual_viewport_size.height - required_size.height
  height_step = height_diff > 0 ? -1 : 1

  browser_size = Applitools::RectangleSize.from_any_argument(executor.manage.window.size)

  current_width_change = 0
  current_height_change = 0

  if width_diff.abs <= MAX_DIFF && height_diff <= MAX_DIFF
    Applitools::EyesLogger.info 'Trying  workaround for zoom...'
    while current_width_change.abs <= width_diff && current_height_change.abs <= height_diff

      current_width_change += width_step if actual_viewport_size.width != required_size.width
      current_height_change += height_step if actual_viewport_size.height != required_size.height

      set_browser_size executor,
        browser_size.dup + Applitools::RectangleSize.new(current_width_change, current_height_change)

      actual_viewport_size = Applitools::RectangleSize.from_any_argument extract_viewport_size(executor)
      Applitools::EyesLogger.info "Current viewport size: #{actual_viewport_size}"
      return if actual_viewport_size == required_size
    end
    Applitools::EyesLogger.error 'Zoom workaround failed.'
  end

  raise Applitools::TestFailedError.new "Failed to set viewport size (#{viewport_size})"
end

#translate_to(executor, location) ⇒ Object



299
300
301
302
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 299

def translate_to(executor, location)
  set_current_transforms(executor, "translate(10px, #{-location.y}px)")
  set_current_transforms(executor, "translate(#{-location.x}px, #{-location.y}px)")
end

#user_agent(executor) ⇒ String

Returns User agent string.

Parameters:

  • executor (Applitools::Selenium::Driver)

Returns:

  • (String)

    User agent string



190
191
192
# File 'lib/applitools/utils/eyes_selenium_utils.rb', line 190

def user_agent(executor)
  executor.execute_script(JS_GET_USER_AGENT)
end