mirror of
https://github.com/servo/servo.git
synced 2025-08-15 10:25:32 +01:00
Update web-platform-tests and CSS tests.
- Update CSS tests to revision e05bfd5e30ed662c2f8a353577003f8eed230180. - Update web-platform-tests to revision a052787dd5c069a340031011196b73affbd68cd9.
This commit is contained in:
parent
fb4f421c8b
commit
296fa2512b
21852 changed files with 2080936 additions and 892894 deletions
|
@ -1 +1,2 @@
|
|||
webdriver.egg-info/
|
||||
*.pyc
|
||||
|
|
|
@ -70,6 +70,101 @@ class Timeouts(object):
|
|||
self._implicit_wait = value
|
||||
|
||||
|
||||
class ActionSequence(object):
|
||||
"""API for creating and performing action sequences.
|
||||
|
||||
Each action method adds one or more actions to a queue. When perform()
|
||||
is called, the queued actions fire in order.
|
||||
|
||||
May be chained together as in::
|
||||
|
||||
ActionSequence(session, "key", id) \
|
||||
.key_down("a") \
|
||||
.key_up("a") \
|
||||
.perform()
|
||||
"""
|
||||
def __init__(self, session, action_type, input_id):
|
||||
"""Represents a sequence of actions of one type for one input source.
|
||||
|
||||
:param session: WebDriver session.
|
||||
:param action_type: Action type; may be "none", "key", or "pointer".
|
||||
:param input_id: ID of input source.
|
||||
"""
|
||||
self.session = session
|
||||
# TODO take advantage of remote end generating uuid
|
||||
self._id = input_id
|
||||
self._type = action_type
|
||||
self._actions = []
|
||||
|
||||
@property
|
||||
def dict(self):
|
||||
return {
|
||||
"type": self._type,
|
||||
"id": self._id,
|
||||
"actions": self._actions,
|
||||
}
|
||||
|
||||
@command
|
||||
def perform(self):
|
||||
"""Perform all queued actions."""
|
||||
self.session.actions.perform([self.dict])
|
||||
|
||||
def _key_action(self, subtype, value):
|
||||
self._actions.append({"type": subtype, "value": value})
|
||||
|
||||
def key_up(self, value):
|
||||
"""Queue a keyUp action for `value`.
|
||||
|
||||
:param value: Character to perform key action with.
|
||||
"""
|
||||
self._key_action("keyUp", value)
|
||||
return self
|
||||
|
||||
def key_down(self, value):
|
||||
"""Queue a keyDown action for `value`.
|
||||
|
||||
:param value: Character to perform key action with.
|
||||
"""
|
||||
self._key_action("keyDown", value)
|
||||
return self
|
||||
|
||||
def send_keys(self, keys):
|
||||
"""Queue a keyDown and keyUp action for each character in `keys`.
|
||||
|
||||
:param keys: String of keys to perform key actions with.
|
||||
"""
|
||||
for c in keys:
|
||||
self.key_down(c)
|
||||
self.key_up(c)
|
||||
return self
|
||||
|
||||
|
||||
class Actions(object):
|
||||
def __init__(self, session):
|
||||
self.session = session
|
||||
|
||||
@command
|
||||
def perform(self, actions=None):
|
||||
"""Performs actions by tick from each action sequence in `actions`.
|
||||
|
||||
:param actions: List of input source action sequences. A single action
|
||||
sequence may be created with the help of
|
||||
``ActionSequence.dict``.
|
||||
"""
|
||||
body = {"actions": [] if actions is None else actions}
|
||||
return self.session.send_command("POST", "actions", body)
|
||||
|
||||
@command
|
||||
def release(self):
|
||||
return self.session.send_command("DELETE", "actions")
|
||||
|
||||
def sequence(self, *args, **kwargs):
|
||||
"""Return an empty ActionSequence of the designated type.
|
||||
|
||||
See ActionSequence for parameter list.
|
||||
"""
|
||||
return ActionSequence(self.session, *args, **kwargs)
|
||||
|
||||
class Window(object):
|
||||
def __init__(self, session):
|
||||
self.session = session
|
||||
|
@ -190,6 +285,7 @@ class Session(object):
|
|||
self.window = Window(self)
|
||||
self.find = Find(self)
|
||||
self.alert = UserPrompt(self)
|
||||
self.actions = Actions(self)
|
||||
|
||||
def __enter__(self):
|
||||
self.start()
|
||||
|
@ -215,13 +311,13 @@ class Session(object):
|
|||
#body["capabilities"] = caps
|
||||
body = caps
|
||||
|
||||
resp = self.transport.send("POST", "session", body=body)
|
||||
self.session_id = resp["sessionId"]
|
||||
response = self.transport.send("POST", "session", body=body)
|
||||
self.session_id = response.body["value"]["sessionId"]
|
||||
|
||||
if self.extension_cls:
|
||||
self.extension = self.extension_cls(self)
|
||||
|
||||
return resp["value"]
|
||||
return response.body["value"]
|
||||
|
||||
def end(self):
|
||||
if self.session_id is None:
|
||||
|
@ -236,11 +332,48 @@ class Session(object):
|
|||
self.find = None
|
||||
self.extension = None
|
||||
|
||||
def send_raw_command(self, method, url, body=None, headers=None):
|
||||
"""Send a command to the remote end.
|
||||
|
||||
:param method: HTTP method to use in request
|
||||
:param url: "command part" of the requests URL path
|
||||
:param body: body of the HTTP request
|
||||
:param headers: Additional headers to include in the HTTP request
|
||||
|
||||
:return: an instance of wdclient.Response describing the HTTP response
|
||||
received from the remote end
|
||||
"""
|
||||
url = urlparse.urljoin("session/%s/" % self.session_id, url)
|
||||
return self.transport.send(method, url, body, headers)
|
||||
|
||||
def send_command(self, method, url, body=None, key=None):
|
||||
"""Send a command to the remote end and validate its success.
|
||||
|
||||
:param method: HTTP method to use in request
|
||||
:param url: "command part" of the requests URL path
|
||||
:param body: body of the HTTP request
|
||||
:param key: (deprecated) when specified, this string value will be used
|
||||
to de-reference the HTTP response body following JSON parsing
|
||||
|
||||
:return: None if the HTTP response body was empty, otherwise the
|
||||
result of parsing the HTTP response body as JSON
|
||||
"""
|
||||
|
||||
if self.session_id is None:
|
||||
raise error.SessionNotCreatedException()
|
||||
url = urlparse.urljoin("session/%s/" % self.session_id, url)
|
||||
return self.transport.send(method, url, body, key=key)
|
||||
|
||||
response = self.send_raw_command(method, url, body)
|
||||
|
||||
if response.status != 200:
|
||||
cls = error.get(response.body["value"].get("error"))
|
||||
raise cls(response.body["value"].get("message"))
|
||||
|
||||
if key is not None:
|
||||
response.body = response.body[key]
|
||||
if not response.body:
|
||||
response.body = None
|
||||
|
||||
return response.body
|
||||
|
||||
@property
|
||||
@command
|
||||
|
@ -275,7 +408,7 @@ class Session(object):
|
|||
@property
|
||||
@command
|
||||
def window_handle(self):
|
||||
return self.send_command("GET", "window_handle", key="value")
|
||||
return self.send_command("GET", "window", key="value")
|
||||
|
||||
@window_handle.setter
|
||||
@command
|
||||
|
@ -298,12 +431,12 @@ class Session(object):
|
|||
|
||||
@command
|
||||
def close(self):
|
||||
return self.send_command("DELETE", "window_handle")
|
||||
return self.send_command("DELETE", "window")
|
||||
|
||||
@property
|
||||
@command
|
||||
def handles(self):
|
||||
return self.send_command("GET", "window_handles", key="value")
|
||||
return self.send_command("GET", "window/handles", key="value")
|
||||
|
||||
@property
|
||||
@command
|
||||
|
@ -428,22 +561,26 @@ class Element(object):
|
|||
@property
|
||||
@command
|
||||
def text(self):
|
||||
return self.session.send_command("GET", self.url("text"))
|
||||
return self.session.send_command("GET", self.url("text"), key="value")
|
||||
|
||||
@property
|
||||
@command
|
||||
def name(self):
|
||||
return self.session.send_command("GET", self.url("name"))
|
||||
return self.session.send_command("GET", self.url("name"), key="value")
|
||||
|
||||
@command
|
||||
def style(self, property_name):
|
||||
return self.session.send_command("GET", self.url("css/%s" % property_name))
|
||||
return self.session.send_command("GET", self.url("css/%s" % property_name), key="value")
|
||||
|
||||
@property
|
||||
@command
|
||||
def rect(self):
|
||||
return self.session.send_command("GET", self.url("rect"))
|
||||
|
||||
@command
|
||||
def property(self, name):
|
||||
return self.session.send_command("GET", self.url("property/%s" % name), key="value")
|
||||
|
||||
@command
|
||||
def attribute(self, name):
|
||||
return self.session.send_command("GET", self.url("attribute/%s" % name))
|
||||
return self.session.send_command("GET", self.url("attribute/%s" % name), key="value")
|
||||
|
|
|
@ -21,6 +21,11 @@ class ElementNotVisibleException(WebDriverException):
|
|||
status_code = "element not visible"
|
||||
|
||||
|
||||
class InsecureCertificateException(WebDriverException):
|
||||
http_status = 400
|
||||
status_code = "insecure certificate"
|
||||
|
||||
|
||||
class InvalidArgumentException(WebDriverException):
|
||||
http_status = 400
|
||||
status_code = "invalid argument"
|
||||
|
|
|
@ -6,11 +6,46 @@ import httplib
|
|||
import json
|
||||
import urlparse
|
||||
|
||||
import error
|
||||
|
||||
|
||||
HTTP_TIMEOUT = 5
|
||||
|
||||
class Response(object):
|
||||
"""Describes an HTTP response received from a remote en"Describes an HTTP
|
||||
response received from a remote end whose body has been read and parsed as
|
||||
appropriate."""
|
||||
def __init__(self, status, body):
|
||||
self.status = status
|
||||
self.body = body
|
||||
|
||||
def __repr__(self):
|
||||
return "wdclient.Response(status=%d, body=%s)" % (self.status, self.body)
|
||||
|
||||
@staticmethod
|
||||
def from_http_response(http_response):
|
||||
status = http_response.status
|
||||
body = http_response.read()
|
||||
|
||||
# SpecID: dfn-send-a-response
|
||||
#
|
||||
# > 3. Set the response's header with name and value with the following
|
||||
# > values:
|
||||
# >
|
||||
# > "Content-Type"
|
||||
# > "application/json; charset=utf-8"
|
||||
# > "cache-control"
|
||||
# > "no-cache"
|
||||
assert http_response.getheader("Content-Type") == "application/json; charset=utf-8"
|
||||
assert http_response.getheader("Cache-Control") == "no-cache"
|
||||
|
||||
if body:
|
||||
body = json.loads(body)
|
||||
|
||||
# SpecID: dfn-send-a-response
|
||||
#
|
||||
# > 4. If data is not null, let response's body be a JSON Object
|
||||
# with a key `value` set to the JSON Serialization of data.
|
||||
assert "value" in body
|
||||
|
||||
return Response(status, body)
|
||||
|
||||
class HTTPWireProtocol(object):
|
||||
"""Transports messages (commands and responses) over the WebDriver
|
||||
|
@ -33,15 +68,16 @@ class HTTPWireProtocol(object):
|
|||
def url(self, suffix):
|
||||
return urlparse.urljoin(self.path_prefix, suffix)
|
||||
|
||||
def send(self, method, url, body=None, headers=None, key=None):
|
||||
def send(self, method, url, body=None, headers=None):
|
||||
"""Send a command to the remote.
|
||||
|
||||
:param method: "POST" or "GET".
|
||||
:param url: "command part" of the requests URL path
|
||||
:param body: Body of the request. Defaults to an empty dictionary
|
||||
if ``method`` is "POST".
|
||||
:param headers: Additional headers to include in the request.
|
||||
:param key: Extract this key from the dictionary returned from
|
||||
the remote.
|
||||
:return: an instance of wdclient.Response describing the HTTP response
|
||||
received from the remote end.
|
||||
"""
|
||||
|
||||
if body is None and method == "POST":
|
||||
|
@ -62,22 +98,9 @@ class HTTPWireProtocol(object):
|
|||
self.host, self.port, strict=True, timeout=self._timeout)
|
||||
conn.request(method, url, body, headers)
|
||||
|
||||
resp = conn.getresponse()
|
||||
resp_body = resp.read()
|
||||
conn.close()
|
||||
|
||||
try:
|
||||
data = json.loads(resp_body)
|
||||
except:
|
||||
raise IOError("Could not parse response body as JSON: '%s'" % resp_body)
|
||||
response = Response.from_http_response(conn.getresponse())
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
if resp.status != 200:
|
||||
cls = error.get(data.get("error"))
|
||||
raise cls(data.get("message"))
|
||||
|
||||
if key is not None:
|
||||
data = data[key]
|
||||
if not data:
|
||||
data = None
|
||||
|
||||
return data
|
||||
return response
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue