blob: 13607e30481876a7777edfad57f48fcafbf8e40f [file] [log] [blame]
from __future__ import print_function
import collections
import math
import sys
from six import iteritems
import webdriver
from tests.support import defaults
from tests.support.sync import Poll
def ignore_exceptions(f):
def inner(*args, **kwargs):
try:
return f(*args, **kwargs)
except webdriver.error.WebDriverException as e:
print("Ignored exception %s" % e, file=sys.stderr)
inner.__name__ = f.__name__
return inner
def cleanup_session(session):
"""Clean-up the current session for a clean state."""
@ignore_exceptions
def _dismiss_user_prompts(session):
"""Dismiss any open user prompts in windows."""
current_window = session.window_handle
for window in _windows(session):
session.window_handle = window
try:
session.alert.dismiss()
except webdriver.NoSuchAlertException:
pass
session.window_handle = current_window
@ignore_exceptions
def _ensure_valid_window(session):
"""If current window was closed, ensure to have a valid one selected."""
try:
session.window_handle
except webdriver.NoSuchWindowException:
session.window_handle = session.handles[0]
@ignore_exceptions
def _restore_timeouts(session):
"""Restore modified timeouts to their default values."""
session.timeouts.implicit = defaults.IMPLICIT_WAIT_TIMEOUT
session.timeouts.page_load = defaults.PAGE_LOAD_TIMEOUT
session.timeouts.script = defaults.SCRIPT_TIMEOUT
@ignore_exceptions
def _restore_window_state(session):
"""Reset window to an acceptable size.
This also includes bringing it out of maximized, minimized,
or fullscreened state.
"""
session.window.size = defaults.WINDOW_SIZE
@ignore_exceptions
def _restore_windows(session):
"""Close superfluous windows opened by the test.
It will not end the session implicitly by closing the last window.
"""
current_window = session.window_handle
for window in _windows(session, exclude=[current_window]):
session.window_handle = window
if len(session.handles) > 1:
session.window.close()
session.window_handle = current_window
_restore_timeouts(session)
_ensure_valid_window(session)
_dismiss_user_prompts(session)
_restore_windows(session)
_restore_window_state(session)
_switch_to_top_level_browsing_context(session)
@ignore_exceptions
def _switch_to_top_level_browsing_context(session):
"""If the current browsing context selected by WebDriver is a
`<frame>` or an `<iframe>`, switch it back to the top-level
browsing context.
"""
session.switch_frame(None)
def _windows(session, exclude=None):
"""Set of window handles, filtered by an `exclude` list if
provided.
"""
if exclude is None:
exclude = []
wins = [w for w in session.handles if w not in exclude]
return set(wins)
def clear_all_cookies(session):
"""Removes all cookies associated with the current active document"""
session.transport.send("DELETE", "session/%s/cookie" % session.session_id)
def deep_update(source, overrides):
"""
Update a nested dictionary or similar mapping.
Modify ``source`` in place.
"""
for key, value in iteritems(overrides):
if isinstance(value, collections.Mapping) and value:
returned = deep_update(source.get(key, {}), value)
source[key] = returned
else:
source[key] = overrides[key]
return source
def document_dimensions(session):
return tuple(session.execute_script("""
let rect = document.documentElement.getBoundingClientRect();
return [rect.width, rect.height];
"""))
def center_point(element):
"""Calculates the in-view center point of a web element."""
inner_width, inner_height = element.session.execute_script(
"return [window.innerWidth, window.innerHeight]")
rect = element.rect
# calculate the intersection of the rect that is inside the viewport
visible = {
"left": max(0, min(rect["x"], rect["x"] + rect["width"])),
"right": min(inner_width, max(rect["x"], rect["x"] + rect["width"])),
"top": max(0, min(rect["y"], rect["y"] + rect["height"])),
"bottom": min(inner_height, max(rect["y"], rect["y"] + rect["height"])),
}
# arrive at the centre point of the visible rectangle
x = (visible["left"] + visible["right"]) / 2.0
y = (visible["top"] + visible["bottom"]) / 2.0
# convert to CSS pixels, as centre point can be float
return (math.floor(x), math.floor(y))
def document_hidden(session):
"""Polls for the document to become hidden."""
def hidden(session):
return session.execute_script("return document.hidden")
return Poll(session, timeout=3, raises=None).until(hidden)
def document_location(session):
"""
Unlike ``webdriver.Session#url``, which always returns
the top-level browsing context's URL, this returns
the current browsing context's active document's URL.
"""
return session.execute_script("return document.location.href")
def element_rect(session, element):
return session.execute_script("""
let element = arguments[0];
let rect = element.getBoundingClientRect();
return {
x: rect.left + window.pageXOffset,
y: rect.top + window.pageYOffset,
width: rect.width,
height: rect.height,
};
""", args=(element,))
def is_element_in_viewport(session, element):
"""Check if element is outside of the viewport"""
return session.execute_script("""
let el = arguments[0];
let rect = el.getBoundingClientRect();
let viewport = {
height: window.innerHeight || document.documentElement.clientHeight,
width: window.innerWidth || document.documentElement.clientWidth,
};
return !(rect.right < 0 || rect.bottom < 0 ||
rect.left > viewport.width || rect.top > viewport.height)
""", args=(element,))
def is_fullscreen(session):
# At the time of writing, WebKit does not conform to the
# Fullscreen API specification.
#
# Remove the prefixed fallback when
# https://bugs.webkit.org/show_bug.cgi?id=158125 is fixed.
return session.execute_script("""
return !!(window.fullScreen || document.webkitIsFullScreen)
""")
def document_dimensions(session):
return tuple(session.execute_script("""
let {devicePixelRatio} = window;
let {width, height} = document.documentElement.getBoundingClientRect();
return [width * devicePixelRatio, height * devicePixelRatio];
"""))
def screen_size(session):
"""Returns the available width/height size of the screen."""
return tuple(session.execute_script("""
return [
screen.availWidth,
screen.availHeight,
];
"""))
def available_screen_size(session):
"""
Returns the effective available screen width/height size,
excluding any fixed window manager elements.
"""
return tuple(session.execute_script("""
return [
screen.availWidth - screen.availLeft,
screen.availHeight - screen.availTop,
];
"""))
def filter_dict(source, d):
"""Filter `source` dict to only contain same keys as `d` dict.
:param source: dictionary to filter.
:param d: dictionary whose keys determine the filtering.
"""
return {k: source[k] for k in d.keys()}