Source code

Revision control

Copy as Markdown

Other Tools

import collections
import math
import sys
from urllib.parse import urlparse
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.
"""
if session.capabilities.get("setWindowRect"):
# Only restore if needed to workaround a bug for Chrome:
if (
session.capabilities.get("browserName") != "chrome" or
session.window.size != defaults.WINDOW_SIZE
or document_hidden(session)
or is_fullscreen(session)
or is_maximized(session)
):
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 overrides.items():
if isinstance(value, collections.abc.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("""
const {devicePixelRatio} = window;
const {width, height} = document.documentElement.getBoundingClientRect();
return [width * devicePixelRatio, height * devicePixelRatio];
"""))
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):
return session.execute_script("return document.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
return session.execute_script("""
return !!(window.fullScreen || document.webkitIsFullScreen)
""")
def is_maximized(session):
dimensions = session.execute_script("""
return {
availWidth: screen.availWidth,
availHeight: screen.availHeight,
windowWidth: window.outerWidth,
windowHeight: window.outerHeight,
}
""")
return (
# The maximized window can still have a border attached which would
# cause its dimensions to exceed the whole available screen.
dimensions["windowWidth"] >= dimensions["availWidth"] and
dimensions["windowHeight"] >= dimensions["availHeight"] and
# Only return true if the window is not in fullscreen mode
not is_fullscreen(session)
)
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()}
def filter_supported_key_events(all_events, expected):
events = [filter_dict(e, expected[0]) for e in all_events]
if len(events) > 0 and events[0]["code"] is None:
# Remove 'code' entry if browser doesn't support it
expected = [filter_dict(e, {"key": "", "type": ""}) for e in expected]
events = [filter_dict(e, expected[0]) for e in events]
return (events, expected)
def get_origin_from_url(url):
parsed_uri = urlparse(url)
return '{uri.scheme}://{uri.netloc}'.format(uri=parsed_uri)
def wait_for_new_handle(session, handles_before):
def find_new_handle(session):
new_handles = list(set(session.handles) - set(handles_before))
if new_handles and len(new_handles) == 1:
return new_handles[0]
return None
wait = Poll(
session,
timeout=5,
message="No new window has been opened")
return wait.until(find_new_handle)