Update web-platform-tests to revision 58eb04cecbbec2e18531ab440225e38944a9c444

This commit is contained in:
Josh Matthews 2017-04-17 12:06:02 +10:00 committed by Anthony Ramine
parent 25e8bf69e6
commit 665817d2a6
35333 changed files with 1818077 additions and 16036 deletions

View file

@ -2,3 +2,4 @@
@lukeis
@AutomatedTester
@shs96c
@mjzffr

View file

@ -0,0 +1,34 @@
import pytest
@pytest.fixture
def key_chain(session):
return session.actions.sequence("key", "keyboard_id")
@pytest.fixture
def mouse_chain(session):
return session.actions.sequence(
"pointer",
"pointer_id",
{"pointerType": "mouse"})
@pytest.fixture(autouse=True)
def release_actions(session, request):
# release all actions after each test
# equivalent to a teardown_function, but with access to session fixture
request.addfinalizer(session.actions.release)
@pytest.fixture
def key_reporter(session, test_actions_page, request):
"""Represents focused input element from `test_keys_page` fixture."""
input_el = session.find.css("#keys", all=False)
input_el.click()
return input_el
@pytest.fixture
def test_actions_page(session, url):
session.url = url("/webdriver/actions/support/test_actions_wdspec.html")

View file

@ -1,72 +1,9 @@
# META: timeout=long
import pytest
from support.keys import Keys
def get_events(session):
"""Return list of key events recorded in the test_keys_page fixture."""
events = session.execute_script("return allEvents.events;") or []
# `key` values in `allEvents` may be escaped (see `escapeSurrogateHalf` in
# test_keys_wdspec.html), so this converts them back into unicode literals.
for e in events:
# example: turn "U+d83d" (6 chars) into u"\ud83d" (1 char)
if e["key"].startswith(u"U+"):
key = e["key"]
hex_suffix = key[key.index("+") + 1:]
e["key"] = unichr(int(hex_suffix, 16))
return events
def get_keys(input_el):
"""Get printable characters entered into `input_el`.
:param input_el: HTML input element.
"""
rv = input_el.property("value")
if rv is None:
return ""
else:
return rv
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()}
@pytest.fixture
def key_reporter(session, test_keys_page, request):
"""Represents focused input element from `test_keys_page` fixture."""
input_el = session.find.css("#keys", all=False)
input_el.click()
return input_el
@pytest.fixture
def test_keys_page(session, server):
session.url = server.where_is("test_keys_wdspec.html")
@pytest.fixture
def key_chain(session):
return session.actions.sequence("key", "keyboard_id")
@pytest.fixture(autouse=True)
def release_actions(session, request):
# release all actions after each test
# equivalent to a teardown_function, but with access to session fixture
request.addfinalizer(session.actions.release)
def test_no_actions_send_no_events(session, key_reporter, key_chain):
key_chain.perform()
assert len(get_keys(key_reporter)) == 0
assert len(get_events(session)) == 0
from support.refine import get_keys, filter_dict, get_events
def test_lone_keyup_sends_no_events(session, key_reporter, key_chain):
@ -220,24 +157,6 @@ def test_sequence_of_keydown_printable_keys_sends_events(session,
assert get_keys(key_reporter) == "ab"
def test_release_char_sequence_sends_keyup_events_in_reverse(session,
key_reporter,
key_chain):
key_chain \
.key_down("a") \
.key_down("b") \
.perform()
# reset so we only see the release events
session.execute_script("resetEvents();")
session.actions.release()
expected = [
{"code": "KeyB", "key": "b", "type": "keyup"},
{"code": "KeyA", "key": "a", "type": "keyup"},
]
events = [filter_dict(e, expected[0]) for e in get_events(session)]
assert events == expected
def test_sequence_of_keydown_character_keys(session, key_reporter, key_chain):
key_chain.send_keys("ef").perform()
expected = [
@ -251,9 +170,3 @@ def test_sequence_of_keydown_character_keys(session, key_reporter, key_chain):
events = [filter_dict(e, expected[0]) for e in get_events(session)]
assert events == expected
assert get_keys(key_reporter) == "ef"
def test_release_no_actions_sends_no_events(session, key_reporter, key_chain):
session.actions.release()
assert len(get_keys(key_reporter)) == 0
assert len(get_events(session)) == 0

View file

@ -0,0 +1,31 @@
from support.refine import get_events, filter_dict
def test_click_at_coordinates(session, test_actions_page, mouse_chain):
div_point = {
"x": 82,
"y": 187,
}
button = 0
mouse_chain \
.pointer_move(div_point["x"], div_point["y"], duration=1000) \
.pointer_down(button) \
.pointer_up(button) \
.perform()
events = get_events(session)
assert len(events) == 4
for e in events:
if e["type"] != "mousemove":
assert e["pageX"] == div_point["x"]
assert e["pageY"] == div_point["y"]
assert e["target"] == "outer"
if e["type"] != "mousedown":
assert e["buttons"] == 0
assert e["button"] == button
expected = [
{"type": "mousedown", "buttons": 1},
{"type": "mouseup", "buttons": 0},
{"type": "click", "buttons": 0},
]
filtered_events = [filter_dict(e, expected[0]) for e in events]
assert expected == filtered_events[1:]

View file

@ -0,0 +1,31 @@
from support.refine import get_keys, filter_dict, get_events
def test_no_actions_send_no_events(session, key_reporter, key_chain):
key_chain.perform()
assert len(get_keys(key_reporter)) == 0
assert len(get_events(session)) == 0
def test_release_char_sequence_sends_keyup_events_in_reverse(session,
key_reporter,
key_chain):
key_chain \
.key_down("a") \
.key_down("b") \
.perform()
# reset so we only see the release events
session.execute_script("resetEvents();")
session.actions.release()
expected = [
{"code": "KeyB", "key": "b", "type": "keyup"},
{"code": "KeyA", "key": "a", "type": "keyup"},
]
events = [filter_dict(e, expected[0]) for e in get_events(session)]
assert events == expected
def test_release_no_actions_sends_no_events(session, key_reporter):
session.actions.release()
assert len(get_keys(key_reporter)) == 0
assert len(get_events(session)) == 0

View file

@ -0,0 +1,33 @@
def get_events(session):
"""Return list of key events recorded in the test_keys_page fixture."""
events = session.execute_script("return allEvents.events;") or []
# `key` values in `allEvents` may be escaped (see `escapeSurrogateHalf` in
# test_keys_wdspec.html), so this converts them back into unicode literals.
for e in events:
# example: turn "U+d83d" (6 chars) into u"\ud83d" (1 char)
if "key" in e and e["key"].startswith(u"U+"):
key = e["key"]
hex_suffix = key[key.index("+") + 1:]
e["key"] = unichr(int(hex_suffix, 16))
return events
def get_keys(input_el):
"""Get printable characters entered into `input_el`.
:param input_el: HTML input element.
"""
rv = input_el.property("value")
if rv is None:
return ""
else:
return rv
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()}

View file

@ -0,0 +1,131 @@
<!doctype html>
<meta charset=utf-8>
<head>
<title>Test Actions</title>
<style>
div { padding:0px; margin: 0px; }
#resultContainer { width: 600px; height: 60px; }
#outer { width: 100px; height: 50px; background-color: #ccc; }
#trackPointer {
width: 5px;
height: 5px;
border: solid 1px red;
position: fixed; }
</style>
<script>
var allEvents = {events: []};
function displayMessage(message) {
document.getElementById("events").innerHTML = "<p>" + message + "</p>";
}
function appendMessage(message) {
document.getElementById("events").innerHTML += "<p>" + message + "</p>";
}
/**
* Escape |key| if it's in a surrogate-half character range.
*
* Example: given "\ud83d" return "U+d83d".
*
* Otherwise JSON.stringify will convert it to U+FFFD (REPLACEMENT CHARACTER)
* when returning a value from executeScript, for example.
*/
function escapeSurrogateHalf(key) {
if (typeof key !== "undefined" && key.length === 1) {
var charCode = key.charCodeAt(0);
var highSurrogate = charCode >= 0xD800 && charCode <= 0xDBFF;
var surrogate = highSurrogate || (charCode >= 0xDC00 && charCode <= 0xDFFF);
if (surrogate) {
key = "U+" + charCode.toString(16);
}
}
return key;
}
function recordKeyboardEvent(event) {
var key = escapeSurrogateHalf(event.key);
allEvents.events.push({
"code": event.code,
"key": key,
"which": event.which,
"location": event.location,
"ctrl": event.ctrlKey,
"meta": event.metaKey,
"shift": event.shiftKey,
"repeat": event.repeat,
"type": event.type
});
appendMessage(`${event.type}(` +
`code: ${event.code}, ` +
`key: ${key}, ` +
`which: ${event.which})`);
}
function recordPointerEvent(event) {
allEvents.events.push({
"type": event.type,
"button": event.button,
"buttons": event.buttons,
"pageX": event.pageX,
"pageY": event.pageY,
"target": event.target.id
});
appendMessage(`${event.type}(` +
`button: ${event.button}, ` +
`pageX: ${event.pageX}, ` +
`pageY: ${event.pageY}, ` +
`button: ${event.button}, ` +
`buttons: ${event.buttons}, ` +
`target id: ${event.target.id})`);
}
function recordFirstPointerMove(event) {
recordPointerEvent(event);
window.removeEventListener("mousemove", recordFirstPointerMove);
}
function resetEvents() {
allEvents.events.length = 0;
displayMessage("");
}
document.addEventListener("DOMContentLoaded", () => {
var keyReporter = document.getElementById("keys");
["keyup", "keypress", "keydown"].forEach((e) => {
keyReporter.addEventListener(e, recordKeyboardEvent);
});
var outer = document.getElementById("outer");
["click", "dblclick", "mousedown",
"mouseup", "contextmenu"].forEach((e) => {
outer.addEventListener(e, recordPointerEvent);
});
window.addEventListener("mousemove", recordFirstPointerMove);
//visual cue for mousemove
var pointer = document.getElementById("trackPointer");
window.addEventListener("mousemove", (e) => {
setTimeout(() => {
let offset = 15;
pointer.style.top = e.pageY + offset + "px";
pointer.style.left = e.pageX + offset + "px";
}, 30);
});
});
</script>
</head>
<body>
<div id="trackPointer"></div>
<div>
<h2>KeyReporter</h2>
<input type="text" id="keys" size="80">
</div>
<div>
<h2>ClickReporter</h2>
<div id="outer">
</div>
</div>
<div id="resultContainer">
<h2>Events</h2>
<div id="events"></div>
</div>
</body>
</html>

View file

@ -1,41 +1,12 @@
import json
import os
import pytest
import webdriver
from support.fixtures import (
create_frame, create_session, create_window, http, server_config, session,
url)
from util import cleanup
from util.http_request import HTTPRequest
default_host = "http://127.0.0.1"
default_port = "4444"
@pytest.fixture(scope="session")
def _session(request):
host = os.environ.get("WD_HOST", default_host)
port = int(os.environ.get("WD_PORT", default_port))
capabilities = json.loads(os.environ.get("WD_CAPABILITIES", "{}"))
session = webdriver.Session(host, port, desired_capabilities=capabilities)
def destroy():
if session.session_id is not None:
session.end()
request.addfinalizer(destroy)
return session
@pytest.fixture(scope="function")
def session(_session, request):
# finalisers are popped off a stack,
# making their ordering reverse
request.addfinalizer(lambda: cleanup.switch_to_top_level_browsing_context(_session))
request.addfinalizer(lambda: cleanup.restore_windows(_session))
request.addfinalizer(lambda: cleanup.dismiss_user_prompts(_session))
return _session
@pytest.fixture(scope="function")
def http(session):
return HTTPRequest(session.transport.host, session.transport.port)
pytest.fixture()(create_frame)
pytest.fixture()(create_session)
pytest.fixture()(create_window)
pytest.fixture()(http)
pytest.fixture()(server_config)
pytest.fixture(scope="function")(session)
pytest.fixture()(url)

View file

@ -25,10 +25,11 @@ def test_window_size_types(http, session):
with http.get("/session/%s/window/size" % session.session_id) as resp:
assert resp.status == 200
body = json.load(resp)
assert "width" in body
assert "height" in body
assert isinstance(body["width"], int)
assert isinstance(body["height"], int)
assert "value" in body
assert "width" in body["value"]
assert "height" in body["value"]
assert isinstance(body["value"]["width"], int)
assert isinstance(body["value"]["height"], int)
size = session.window.size
assert isinstance(size, tuple)
@ -83,10 +84,11 @@ def test_window_position_types(http, session):
with http.get("/session/%s/window/position" % session.session_id) as resp:
assert resp.status == 200
body = json.load(resp)
assert "x" in body
assert "y" in body
assert isinstance(body["x"], int)
assert isinstance(body["y"], int)
assert "value" in body
assert "x" in body["value"]
assert "y" in body["value"]
assert isinstance(body["value"]["x"], int)
assert isinstance(body["value"]["y"], int)
pos = session.window.position
assert isinstance(pos, tuple)

View file

@ -1,14 +1,9 @@
import json
import pytest
import types
import urllib
import webdriver
def inline(doc):
return "data:text/html;charset=utf-8,%s" % urllib.quote(doc)
from support.inline import inline
from support.asserts import assert_error, assert_success
alert_doc = inline("<script>window.alert()</script>")
frame_doc = inline("<p>frame")
@ -16,89 +11,83 @@ one_frame_doc = inline("<iframe src='%s'></iframe>" % frame_doc)
two_frames_doc = inline("<iframe src='%s'></iframe>" % one_frame_doc)
@pytest.fixture
def new_window(session):
"""Open new window and return the window handle."""
windows_before = session.window_handles
name = session.execute_script("window.open()")
assert len(session.window_handles) == len(windows_before) + 1
new_windows = session.window_handles - windows_before
return new_windows.pop()
# TODO(ato): 7.1 Get
def test_get_current_url_no_browsing_context(session, new_window):
def test_get_current_url_no_browsing_context(session, create_window):
# 7.2 step 1
session.window_handle = new_window
session.window_handle = create_window()
session.close()
with pytest.raises(webdriver.NoSuchWindowException):
session.url = "about:blank"
result = session.transport.send("GET", "session/%s/url" % session.session_id)
assert_error(result, "no such window")
def test_get_current_url_alert_prompt(session):
# 7.2 step 2
session.url = alert_doc
with pytest.raises(webdriver.UnexpectedAlertOpenException):
session.url = "about:blank"
result = session.transport.send("GET", "session/%s/url" % session.session_id)
assert_error(result, "unexpected alert open")
def test_get_current_url_matches_location(session):
# 7.2 step 3
url = session.execute_script("return window.location.href")
assert session.url == url
def test_get_current_url_payload(http, session):
def test_get_current_url_payload(session):
# 7.2 step 4-5
session.start()
with http.get("/session/%s/url" % session.session_id) as resp:
assert resp.status == 200
body = json.load(resp)
assert "value" in body
assert isinstance(body["value"], types.StringTypes)
result = session.transport.send("GET", "session/%s/url" % session.session_id)
assert result.status == 200
assert isinstance(result.body["value"], basestring)
def test_get_current_url_special_pages(session):
session.url = "about:blank"
assert session.url == "about:blank"
result = session.transport.send("GET", "session/%s/url" % session.session_id)
"""
Disabled due to https://bugzilla.mozilla.org/show_bug.cgi?id=1332122
assert_success(result, "about:blank")
# TODO(ato): This test requires modification to pass on Windows
def test_get_current_url_file_protocol(session):
# tests that the browsing context remains the same
# when navigated privileged documents
session.url = "file:///"
assert session.url == "file:///"
"""
result = session.transport.send("GET", "session/%s/url" % session.session_id)
assert_success(result, "file:///")
# TODO(ato): Test for http:// and https:// protocols.
# We need to expose a fixture for accessing
# documents served by wptserve in order to test this.
def test_set_malformed_url(session):
result = session.transport.send("POST",
"session/%s/url" % session.session_id,
{"url": "foo"})
def test_get_current_url_malformed_url(session):
session.url = "foo"
assert session.url
assert_error(result, "invalid argument")
def test_get_current_url_after_modified_location(session):
session.execute_script("window.location.href = 'about:blank'")
assert session.url == "about:blank"
session.execute_script("window.location.href = 'about:blank#wd_test_modification'")
result = session.transport.send("GET", "session/%s/url" % session.session_id)
def test_get_current_url_nested_browsing_context(session):
session.url = one_frame_doc
top_level_url = session.url
frame = session.find.css("iframe", all=False)
session.switch_frame(frame)
assert session.url == top_level_url
assert_success(result, "about:blank#wd_test_modification")
def test_get_current_url_nested_browsing_context(session, create_frame):
session.url = "about:blank#wd_from_within_frame"
session.switch_frame(create_frame())
result = session.transport.send("GET", "session/%s/url" % session.session_id)
assert_success(result, "about:blank#wd_from_within_frame")
def test_get_current_url_nested_browsing_contexts(session):
session.url = two_frames_doc
@ -108,6 +97,6 @@ def test_get_current_url_nested_browsing_contexts(session):
session.switch_frame(outer_frame)
inner_frame = session.find.css("iframe", all=False)
session.switch_frame(frame)
session.switch_frame(inner_frame)
assert session.url == top_level_url

View file

@ -0,0 +1 @@
from merge_dictionaries import merge_dictionaries

View file

@ -0,0 +1,77 @@
# WebDriver specification ID: dfn-error-response-data
errors = {
"element click intercepted": 400,
"element not selectable": 400,
"element not interactable": 400,
"insecure certificate": 400,
"invalid argument": 400,
"invalid cookie domain": 400,
"invalid coordinates": 400,
"invalid element state": 400,
"invalid selector": 400,
"invalid session id": 404,
"javascript error": 500,
"move target out of bounds": 500,
"no such alert": 400,
"no such cookie": 404,
"no such element": 404,
"no such frame": 400,
"no such window": 400,
"script timeout": 408,
"session not created": 500,
"stale element reference": 400,
"timeout": 408,
"unable to set cookie": 500,
"unable to capture screen": 500,
"unexpected alert open": 500,
"unknown command": 404,
"unknown error": 500,
"unknown method": 405,
"unsupported operation": 500,
}
# WebDriver specification ID: dfn-send-an-error
#
# > When required to send an error, with error code, a remote end must run the
# > following steps:
# >
# > 1. Let http status and name be the error response data for error code.
# > 2. Let message be an implementation-defined string containing a
# > human-readable description of the reason for the error.
# > 3. Let stacktrace be an implementation-defined string containing a stack
# > trace report of the active stack frames at the time when the error
# > occurred.
# > 4. Let data be a new JSON Object initialised with the following properties:
# >
# > error
# > name
# > message
# > message
# > stacktrace
# > stacktrace
# >
# > 5. Send a response with status and data as arguments.
def assert_error(response, error_code):
"""Verify that the provided wdclient.Response instance described a valid
error response as defined by `dfn-send-an-error` and the provided error
code.
:param response: wdclient.Response instance
:param error_code: string value of the expected "error code"
"""
assert response.status == errors[error_code]
assert "value" in response.body
assert response.body["value"]["error"] == error_code
assert isinstance(response.body["value"]["message"], basestring)
assert isinstance(response.body["value"]["stacktrace"], basestring)
def assert_success(response, value):
"""Verify that the provided wdclient.Response instance described a valid
error response as defined by `dfn-send-an-error` and the provided error
code.
:param response: wdclient.Response instance
:param value: expected value of the response body
"""
assert response.status == 200
assert response.body["value"] == value

View file

@ -0,0 +1,144 @@
import json
import os
import urlparse
import webdriver
from support.http_request import HTTPRequest
from support import merge_dictionaries
default_host = "http://127.0.0.1"
default_port = "4444"
def _ensure_valid_window(session):
"""If current window is not open anymore, ensure to have a valid one selected."""
try:
session.window_handle
except webdriver.NoSuchWindowException:
session.window_handle = session.handles[0]
def _dismiss_user_prompts(session):
"""Dismisses 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
def _restore_windows(session):
"""Closes superfluous windows opened by the test without ending
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.window_handles) > 1:
session.close()
session.window_handle = current_window
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 create_frame(session):
"""Create an `iframe` element in the current browsing context and insert it
into the document. Return an element reference."""
def create_frame():
append = """
var frame = document.createElement('iframe');
document.body.appendChild(frame);
return frame;
"""
response = session.execute_script(append)
return create_frame
def create_window(session):
"""Open new window and return the window handle."""
def create_window():
windows_before = session.handles
name = session.execute_script("window.open()")
assert len(session.handles) == len(windows_before) + 1
new_windows = list(set(session.handles) - set(windows_before))
return new_windows.pop()
return create_window
def http(session):
return HTTPRequest(session.transport.host, session.transport.port)
def server_config():
return json.loads(os.environ.get("WD_SERVER_CONFIG"))
def create_session(request):
"""Provide a factory function that produces wdclient `Session` instances.
If the `WD_CAPABILITIES` environment variable is set, it will be parsed as
JSON and the resulting object will be included in the WebDriver "Create
Session" command. Additional capabilities may be specified as an optional
argument to this function, but the operation will fail if any values
conflict with those specified via the environment. If the session is still
active at the completion of the test, it will be destroyed
automatically."""
def create_session(test_capabilities=None):
host = os.environ.get("WD_HOST", default_host)
port = int(os.environ.get("WD_PORT", default_port))
if test_capabilities is None:
test_capabilities = {}
env_capabilities = json.loads(os.environ.get("WD_CAPABILITIES", "{}"))
capabilities = merge_dictionaries(env_capabilities, test_capabilities)
session = webdriver.Session(host, port, capabilities=capabilities)
def destroy():
if session.session_id is not None:
session.end()
# finalisers are popped off a stack, making their ordering reverse
request.addfinalizer(destroy)
request.addfinalizer(lambda: _switch_to_top_level_browsing_context(session))
request.addfinalizer(lambda: _restore_windows(session))
request.addfinalizer(lambda: _dismiss_user_prompts(session))
request.addfinalizer(lambda: _ensure_valid_window(session))
return session
return create_session
# Create a wdclient `Session` object for each Pytest "session". If the
# `WD_CAPABILITIES` environment variable is set, it will be parsed as JSON and
# the resulting object will be included in the WebDriver "Create Session"
# command. If the session is still active at the completion of the test, it
# will be destroyed automatically.
def session(create_session):
return create_session()
def url(server_config):
def inner(path, query="", fragment=""):
rv = urlparse.urlunsplit(("http",
"%s:%s" % (server_config["host"],
server_config["ports"]["http"][0]),
path,
query,
fragment))
return rv
return inner

View file

@ -0,0 +1,19 @@
import urllib
def inline(doc, doctype="html", mime="text/html;charset=utf-8"):
if doctype == "html":
mime = "text/html;charset=utf-8"
elif doctype == "xhtml":
mime = "application/xhtml+xml"
doc = r"""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>XHTML might be the future</title>
</head>
<body>
{}
</body>
</html>""".format(doc)
return "data:{},{}".format(mime, urllib.quote(doc))

View file

@ -0,0 +1,49 @@
def iteritems(d):
"""Create a key-value iterator for the given dict in both Python 2.x and
Python 3.x environments"""
if hasattr(d, "iteritems"):
return d.iteritems()
return d.items()
def merge_dictionaries(first, second):
"""Given two dictionaries, create a third that defines all specified
key/value pairs. This merge_dictionaries is performed "deeply" on any nested
dictionaries. If a value is defined for the same key by both dictionaries,
an exception will be raised."""
result = dict(first)
for key, value in iteritems(second):
if key in result and result[key] != value:
if isinstance(result[key], dict) and isinstance(value, dict):
result[key] = merge_dictionaries(result[key], value)
elif result[key] != value:
raise TypeError("merge_dictionaries: refusing to overwrite " +
"attribute: `%s`" % key)
else:
result[key] = value
return result
if __name__ == "__main__":
assert merge_dictionaries({}, {}) == {}
assert merge_dictionaries({}, {"a": 23}) == {"a": 23}
assert merge_dictionaries({"a": 23}, {"b": 45}) == {"a": 23, "b": 45}
e = None
try:
merge_dictionaries({"a": 23}, {"a": 45})
except Exception as _e:
e = _e
assert isinstance(e, TypeError)
assert merge_dictionaries({"a": 23}, {"a": 23}) == {"a": 23}
assert merge_dictionaries({"a": {"b": 23}}, {"a": {"c": 45}}) == {"a": {"b": 23, "c": 45}}
assert merge_dictionaries({"a": {"b": 23}}, {"a": {"b": 23}}) == {"a": {"b": 23}}
e = None
try:
merge_dictionaries({"a": {"b": 23}}, {"a": {"b": 45}})
except Exception as _e:
e = _e
assert isinstance(e, TypeError)

View file

@ -1,43 +0,0 @@
import webdriver
def dismiss_user_prompts(session):
"""Dismisses 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
def restore_windows(session):
"""Closes superfluous windows opened by the test without ending
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.window_handles) > 1:
session.close()
session.window_handle = current_window
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)