Update web-platform-tests to revision d011702f368b88b3bae86e7a8fd2ddd22e18b33c

This commit is contained in:
Ms2ger 2016-04-12 09:07:41 +02:00
parent f9608022ca
commit 299ad0f9d0
573 changed files with 38776 additions and 14942 deletions

View file

@ -0,0 +1 @@
webdriver.egg-info/

View file

@ -0,0 +1,48 @@
# WebDriver client for Python
This package provides a WebDriver client compatible with
the [W3C browser automation specification](https://w3c.github.io/webdriver/webdriver-spec.html).
The client is written with determining
implementation compliance to the specification in mind,
so that different remote end drivers
can determine whether they meet the recognised standard.
The client is used for the WebDriver specification tests
in the [Web Platform Tests](https://github.com/w3c/web-platform-tests).
## Installation
To install the package individually
in your virtualenv or system-wide::
% python setup.py install
Or if you want to contribute patches::
% python setup.py develop
If you are writing WebDriver specification tests for
[WPT](https://github.com/w3c/web-platform-tests),
there is no need to install the client manually
as it is picked up as a submodule to
[wpt-tools](https://github.com/w3c/wpt-tools)
that is checked out in `./tools`.
## Usage
```py
import webdriver
session = webdriver.Session("127.0.0.1", "4444")
session.start()
session.url = "https://mozilla.org"
print "The current URL is %s" % session.url
session.end()
```
## Dependencies
This client has the benefit of only using standard library dependencies.
No external PyPI dependencies are needed.

View file

@ -0,0 +1,18 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
from setuptools import setup, find_packages
setup(name="webdriver",
version="1.0",
description="WebDriver client compatible with "
"the W3C browser automation specification.",
author="Mozilla Engineering Productivity",
author_email="tools@lists.mozilla.org",
license="MPL 2.0",
packages=find_packages(),
classifiers=["Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)",
"Operating System :: OS Independent"])

View file

@ -0,0 +1,31 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
from client import Cookies, Element, Find, Session, Timeouts, Window
from error import (
ElementNotSelectableException,
ElementNotVisibleException,
InvalidArgumentException,
InvalidCookieDomainException,
InvalidElementCoordinatesException,
InvalidElementStateException,
InvalidSelectorException,
InvalidSessionIdException,
JavascriptErrorException,
MoveTargetOutOfBoundsException,
NoSuchAlertException,
NoSuchElementException,
NoSuchFrameException,
NoSuchWindowException,
ScriptTimeoutException,
SessionNotCreatedException,
StaleElementReferenceException,
TimeoutException,
UnableToSetCookieException,
UnexpectedAlertOpenException,
UnknownCommandException,
UnknownErrorException,
UnknownMethodException,
UnsupportedOperationException,
WebDriverException)

View file

@ -1,26 +0,0 @@
"""WebDriver alert handling."""
class Alert(object):
"""Class that provides access to the WebDriver alert handling functions."""
def __init__(self, driver):
self._driver = driver
def _execute(self, method, path, name, body=None):
return self._driver.execute(method, path, name, body)
def dismiss(self):
"""Dismiss the alert."""
self._execute('POST', '/dismiss_alert', 'dismiss')
def accept(self):
"""Accept the alert."""
self._execute('POST', '/accept_alert', 'accept')
def get_text(self):
"""Get the text displayed in the alert."""
return self._execute('GET', '/alert_text', 'getText')
def send_keys(self, keys):
"""Type into the text input of the alert if available."""
self._execute('POST', '/alert_text', 'sendKeys', { 'text': keys })

View file

@ -1,30 +0,0 @@
"""Definition of various capability-related constants."""
class Capability:
"""Standard capability names."""
BROWSER_NAME = 'browserName'
BROWSER_VERSION = 'browserVersion'
PAGE_LOADING_STRATEGY = 'pageLoadingStrategy'
PLATFORM_NAME = 'platformName'
PLATFORM_VERSION = 'platformVersion'
SECURE_SSL = 'secureSsl'
TAKES_SCREENSHOT = 'takesScreenshot'
TAKE_ELEMENT_SCREENSHOT = 'takeElementScreenshot'
TOUCH_ENABLED = 'touchEnabled'
class Platform:
"""Standard OS names."""
ANY = 'any'
ANDROID = 'android'
IOS = 'ios'
LINUX = 'linux'
MAC = 'mac'
UNIX = 'unix'
WINDOW = 'windows'
class PageLoadingStrategy:
"""Standard page loading strategies."""
CONSERVATIVE = 'conservative'
NORMAL = 'normal'
EAGER = 'eager'
NONE = 'none'

View file

@ -0,0 +1,409 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import urlparse
import transport
element_key = "element-6066-11e4-a52e-4f735466cecf"
def command(func):
def inner(self, *args, **kwargs):
if hasattr(self, "session"):
session = self.session
else:
session = self
if session.session_id is None:
session.start()
assert session.session_id != None
return func(self, *args, **kwargs)
inner.__name__ = func.__name__
inner.__doc__ = func.__doc__
return inner
class Timeouts(object):
def __init__(self, session):
self.session = session
self._script = 30
self._load = 0
self._implicit_wait = 0
def _set_timeouts(self, name, value):
body = {"type": name,
"ms": value * 1000}
return self.session.send_command("POST", "timeouts", body)
@property
def script(self):
return self._script
@script.setter
def script(self, value):
self._set_timeouts("script", value)
self._script = value
@property
def load(self):
return self._load
@load.setter
def set_load(self, value):
self._set_timeouts("page load", value)
self._script = value
@property
def implicit_wait(self):
return self._implicit_wait
@implicit_wait.setter
def implicit_wait(self, value):
self._set_timeouts("implicit wait", value)
self._implicit_wait = value
class Window(object):
def __init__(self, session):
self.session = session
@property
@command
def size(self):
return self.session.send_command("GET", "window/size")
@size.setter
@command
def size(self, (height, width)):
body = {"width": width,
"height": height}
return self.session.send_command("POST", "window/size", body)
@property
@command
def maximize(self):
return self.session.send_command("POST", "window/maximize")
class Find(object):
def __init__(self, session):
self.session = session
@command
def css(self, selector, all=True):
return self._find_element("css selector", selector, all)
def _find_element(self, strategy, selector, all):
route = "elements" if all else "element"
body = {"using": strategy,
"value": selector}
data = self.session.send_command("POST", route, body, key="value")
if all:
rv = [self.session._element(item) for item in data]
else:
rv = self.session._element(data)
return rv
class Cookies(object):
def __init__(self, session):
self.session = session
def __getitem__(self, name):
self.session.send_command("GET", "cookie/%s" % name, {}, key="value")
def __setitem__(self, name, value):
cookie = {"name": name,
"value": None}
if isinstance(name, (str, unicode)):
cookie["value"] = value
elif hasattr(value, "value"):
cookie["value"] = value.value
self.session.send_command("POST", "cookie/%s" % name, {}, key="value")
class Session(object):
def __init__(self, host, port, url_prefix="", desired_capabilities=None,
required_capabilities=None, timeout=60, extension=None):
self.transport = transport.HTTPWireProtocol(
host, port, url_prefix, timeout=timeout)
self.desired_capabilities = desired_capabilities
self.required_capabilities = required_capabilities
self.session_id = None
self.timeouts = None
self.window = None
self.find = None
self._element_cache = {}
self.extension = None
self.extension_cls = extension
def start(self):
if self.session_id is not None:
return
body = {}
caps = {}
if self.desired_capabilities is not None:
caps["desiredCapabilities"] = self.desired_capabilities
if self.required_capabilities is not None:
caps["requiredCapabilities"] = self.required_capabilities
body["capabilities"] = caps
resp = self.transport.send("POST", "session", body=body)
self.session_id = resp["sessionId"]
self.timeouts = Timeouts(self)
self.window = Window(self)
self.find = Find(self)
if self.extension_cls:
self.extension = self.extension_cls(self)
return resp["value"]
def end(self):
if self.session_id is None:
return
url = "session/%s" % self.session_id
self.transport.send("DELETE", url)
self.session_id = None
self.timeouts = None
self.window = None
self.find = None
self.extension = None
self.transport.disconnect()
def __enter__(self):
resp = self.start()
if resp.error:
raise Exception(resp)
return self
def __exit__(self, *args, **kwargs):
resp = self.end()
if resp.error:
raise Exception(resp)
def send_command(self, method, url, body=None, key=None):
url = urlparse.urljoin("session/%s/" % self.session_id, url)
return self.transport.send(method, url, body, key=key)
@property
@command
def url(self):
return self.send_command("GET", "url", key="value")
@url.setter
@command
def url(self, url):
if urlparse.urlsplit(url).netloc is None:
return self.url(url)
body = {"url": url}
return self.send_command("POST", "url", body)
@command
def back(self):
return self.send_command("POST", "back")
@command
def forward(self):
return self.send_command("POST", "forward")
@command
def refresh(self):
return self.send_command("POST", "refresh")
@property
@command
def title(self):
return self.send_command("GET", "title", key="value")
@property
@command
def window_handle(self):
return self.send_command("GET", "window_handle", key="value")
@window_handle.setter
@command
def window_handle(self, handle):
body = {"handle": handle}
return self.send_command("POST", "window", body=body)
def switch_frame(self, frame):
if frame == "parent":
url = "frame/parent"
body = None
else:
url = "frame"
if isinstance(frame, Element):
body = {"id": frame.json()}
else:
body = {"id": frame}
return self.send_command("POST", url, body)
@command
def close(self):
return self.send_command("DELETE", "window_handle")
@property
@command
def handles(self):
return self.send_command("GET", "window_handles", key="value")
@property
@command
def active_element(self):
data = self.send_command("GET", "element/active", key="value")
if data is not None:
return self._element(data)
def _element(self, data):
elem_id = data[element_key]
assert elem_id
if elem_id in self._element_cache:
return self._element_cache[elem_id]
return Element(self, elem_id)
@command
def cookies(self, name=None):
if name is None:
url = "cookie"
else:
url = "cookie/%s" % name
return self.send_command("GET", url, {}, key="value")
@command
def set_cookie(self, name, value, path=None, domain=None, secure=None, expiry=None):
body = {"name": name,
"value": value}
if path is not None:
body["path"] = path
if domain is not None:
body["domain"] = domain
if secure is not None:
body["secure"] = secure
if expiry is not None:
body["expiry"] = expiry
self.send_command("POST", "cookie", {"cookie": body})
def delete_cookie(self, name=None):
if name is None:
url = "cookie"
else:
url = "cookie/%s" % name
self.send_command("DELETE", url, {}, key="value")
#[...]
@command
def execute_script(self, script, args=None):
if args is None:
args = []
body = {
"script": script,
"args": args
}
return self.send_command("POST", "execute", body, key="value")
@command
def execute_async_script(self, script, args=None):
if args is None:
args = []
body = {
"script": script,
"args": args
}
return self.send_command("POST", "execute_async", body, key="value")
#[...]
@command
def screenshot(self):
return self.send_command("GET", "screenshot", key="value")
class Element(object):
def __init__(self, session, id):
self.session = session
self.id = id
assert id not in self.session._element_cache
self.session._element_cache[self.id] = self
def json(self):
return {element_key: self.id}
@property
def session_id(self):
return self.session.session_id
def url(self, suffix):
return "element/%s/%s" % (self.id, suffix)
@command
def find_element(self, strategy, selector):
body = {"using": strategy,
"value": selector}
elem = self.session.send_command("POST", self.url("element"), body, key="value")
return self.session.element(elem)
@command
def click(self):
self.session.send_command("POST", self.url("click"), {})
@command
def tap(self):
self.session.send_command("POST", self.url("tap"), {})
@command
def clear(self):
self.session.send_command("POST", self.url("clear"), {})
@command
def send_keys(self, keys):
if isinstance(keys, (str, unicode)):
keys = [char for char in keys]
body = {"value": keys}
return self.session.send_command("POST", self.url("value"), body)
@property
@command
def text(self):
return self.session.send_command("GET", self.url("text"))
@property
@command
def name(self):
return self.session.send_command("GET", self.url("name"))
@command
def style(self, property_name):
return self.session.send_command("GET", self.url("css/%s" % property_name))
@property
@command
def rect(self):
return self.session.send_command("GET", self.url("rect"))
@command
def attribute(self, name):
return self.session.send_command("GET", self.url("attribute/%s" % name))

View file

@ -1,111 +0,0 @@
"""Dispatches requests to remote WebDriver endpoint."""
import exceptions
import httplib
import json
import urlparse
import webelement
class CommandExecutor(object):
"""Dispatches requests to remote WebDriver endpoint."""
_HEADERS = {
"User-Agent": "Python WebDriver Local End",
"Content-Type": "application/json;charset=\"UTF-8\"",
"Accept": "application/json",
"Accept-Charset": "utf-8",
"Accept-Encoding": "identity",
"Connection": "close",
}
def __init__(self, url, mode='strict'):
self._parsed_url = urlparse.urlparse(url)
self._conn = httplib.HTTPConnection(self._parsed_url.hostname,
self._parsed_url.port)
self._mode = mode
def execute(self,
method,
path,
session_id,
name,
parameters=None,
object_hook=None):
"""Execute a command against the WebDriver endpoint.
Arguments:
method -- one of GET, POST, DELETE
path -- the path of the url endpoint (needs to include
session/<sessionId> if needed)
session_id -- the sessionId to include in the JSON body
name -- name of the command that is being executed to include in
the JSON body
parameters -- the JSON body to send with the command. Only used if
method is POST
object_hook -- function used by json.loads to properly deserialize
objects in the request
"""
if self._mode == 'strict':
return self._execute_strict(
method, path, session_id, name, parameters, object_hook)
elif self._mode == 'compatibility':
return self._execute_compatibility(
method, path, session_id, name, parameters, object_hook)
else:
raise Exception("Unknown mode: " + self._mode)
def _execute_compatibility(self,
method,
path,
session_id,
name,
parameters,
object_hook):
body = {'sessionId': session_id, 'name': name }
if parameters:
body.update(parameters)
self._conn.request(
method,
self._parsed_url.path + path,
json.dumps(body, default = self._json_encode).encode('utf-8'),
self._HEADERS)
resp = self._conn.getresponse()
data = resp.read().decode('utf-8')
if data:
data = json.loads(data, object_hook = object_hook)
if data['status'] != 0:
raise exceptions.create_webdriver_exception_compatibility(
data['status'], data['value']['message'])
return data
if resp.status < 200 or resp.status > 299:
raise exceptions.create_webdriver_exception_compatibility(
resp.status, resp.reason)
def _execute_strict(self,
method,
path,
session_id,
name,
parameters,
object_hook):
body = {
'sessionId': session_id,
'name': name,
'parameters': parameters }
self._conn.request(
method,
self._parsed_url.path + path,
json.dumps(body, default = self._json_encode).encode('utf-8'),
self._HEADERS)
resp = self._conn.getresponse()
data = json.loads(
resp.read().decode('utf-8'), object_hook = object_hook)
if data['status'] != 'success':
raise exceptions.create_webdriver_exception_strict(
data['status'], data['value'])
return data
def _json_encode(self, obj):
return obj.to_json()

View file

@ -1,199 +0,0 @@
"""Entry point for WebDriver."""
import alert
import command
import searchcontext
import webelement
import base64
class WebDriver(searchcontext.SearchContext):
"""Controls a web browser."""
def __init__(self, host, required, desired, mode='strict'):
args = { 'desiredCapabilities': desired }
if required:
args['requiredCapabilities'] = required
self._executor = command.CommandExecutor(host, mode)
resp = self._executor.execute(
'POST', '/session', None, 'newSession', args)
self.capabilities = resp['value']
self._session_id = resp['sessionId']
self.mode = mode
def execute(self, method, path, name, parameters= None):
"""Execute a command against the current WebDriver session."""
data = self._executor.execute(
method,
'/session/' + self._session_id + path,
self._session_id,
name,
parameters,
self._object_hook)
if data:
return data['value']
def get(self, url):
"""Navigate to url."""
self.execute('POST', '/url', 'get', { 'url': url })
def get_current_url(self):
"""Get the current value of the location bar."""
return self.execute('GET', '/url', 'getCurrentUrl')
def go_back(self):
"""Hit the browser back button."""
self.execute('POST', '/back', 'goBack')
def go_forward(self):
"""Hit the browser forward button."""
self.execute('POST', '/forward', 'goForward')
def refresh(self):
"""Refresh the current page in the browser."""
self.execute('POST', '/refresh', 'refresh')
def quit(self):
"""Shutdown the current WebDriver session."""
self.execute('DELETE', '', 'quit')
def get_window_handle(self):
"""Get the handle for the browser window/tab currently accepting
commands.
"""
return self.execute('GET', '/window_handle', 'getWindowHandle')
def get_window_handles(self):
"""Get handles for all open windows/tabs."""
return self.execute('GET', '/window_handles', 'getWindowHandles')
def close(self):
"""Close the current tab or window.
If this is the last tab or window, then this is the same as
calling quit.
"""
self.execute('DELETE', '/window', 'close')
def maximize_window(self):
"""Maximize the current window."""
return self._window_command('POST', '/maximize', 'maximize')
def get_window_size(self):
"""Get the dimensions of the current window."""
result = self._window_command('GET', '/size', 'getWindowSize')
return {'height': result['height'], 'width': result['width']}
def set_window_size(self, height, width):
"""Set the size of the current window."""
self._window_command(
'POST',
'/size',
'setWindowSize',
{ 'height': height, 'width': width})
def fullscreen_window(self):
"""Make the current window fullscreen."""
pass # implement when end point is defined
def switch_to_window(self, name):
"""Switch to the window with the given handle or name."""
self.execute('POST', '/window', 'switchToWindow', { 'name': name })
def switch_to_frame(self, id):
"""Switch to a frame.
id can be either a WebElement or an integer.
"""
self.execute('POST', '/frame', 'switchToFrame', { 'id': id})
def switch_to_parent_frame(self):
"""Move to the browsing context containing the currently selected frame.
If in the top-level browsing context, this is a no-op.
"""
self.execute('POST', '/frame/parent', 'switchToParentFrame')
def switch_to_alert(self):
"""Return an Alert object to interact with a modal dialog."""
alert_ = alert.Alert(self)
alert_.get_text()
return alert_
def execute_script(self, script, args=[]):
"""Execute a Javascript script in the current browsing context."""
return self.execute(
'POST',
'/execute',
'executeScript',
{ 'script': script, 'args': args })
def execute_script_async(self, script, args=[]):
"""Execute a Javascript script in the current browsing context."""
return self.execute(
'POST',
'/execute_async',
'executeScriptAsync',
{ 'script': script, 'args': args })
def take_screenshot(self, element=None):
"""Take a screenshot.
If element is not provided, the screenshot should be of the
current page, otherwise the screenshot should be of the given element.
"""
if self.mode == 'strict':
pass # implement when endpoint is defined
elif self.mode == 'compatibility':
if element:
pass # element screenshots are unsupported in compatibility
else:
return base64.standard_b64decode(
self.execute('GET', '/screenshot', 'takeScreenshot'))
def add_cookie(self, cookie):
"""Add a cookie to the browser."""
self.execute('POST', '/cookie', 'addCookie', { 'cookie': cookie })
def get_cookie(self, name = None):
"""Get the cookies accessible from the current page."""
if self.mode == 'compatibility':
cookies = self.execute('GET', '/cookie', 'getCookie')
if name:
cookies_ = []
for cookie in cookies:
if cookie['name'] == name:
cookies_.append(cookie)
return cookies_
return cookies
elif self.mode == 'strict':
pass # implement when wire protocol for this has been defined
def set_implicit_timeout(self, ms):
self._set_timeout('implicit', ms)
def set_page_load_timeout(self, ms):
self._set_timeout('page load', ms)
def set_script_timeout(self, ms):
self._set_timeout('script', ms)
def _set_timeout(self, type, ms):
params = { 'type': type, 'ms': ms }
self.execute('POST', '/timeouts', 'timeouts', params)
def _window_command(self, method, path, name, parameters = None):
if self.mode == 'compatibility':
return self.execute(
method, '/window/current' + path, name, parameters)
elif self.mode == 'strict':
pass # implement this when end-points are defined in doc
def _object_hook(self, obj):
if 'ELEMENT' in obj:
return webelement.WebElement(self, obj['ELEMENT'])
return obj

View file

@ -0,0 +1,144 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
import collections
class WebDriverException(Exception):
http_status = None
status_code = None
class ElementNotSelectableException(WebDriverException):
http_status = 400
status_code = "element not selectable"
class ElementNotVisibleException(WebDriverException):
http_status = 400
status_code = "element not visible"
class InvalidArgumentException(WebDriverException):
http_status = 400
status_code = "invalid argument"
class InvalidCookieDomainException(WebDriverException):
http_status = 400
status_code = "invalid cookie domain"
class InvalidElementCoordinatesException(WebDriverException):
http_status = 400
status_code = "invalid element coordinates"
class InvalidElementStateException(WebDriverException):
http_status = 400
status_code = "invalid cookie domain"
class InvalidSelectorException(WebDriverException):
http_status = 400
status_code = "invalid selector"
class InvalidSessionIdException(WebDriverException):
http_status = 404
status_code = "invalid session id"
class JavascriptErrorException(WebDriverException):
http_status = 500
status_code = "javascript error"
class MoveTargetOutOfBoundsException(WebDriverException):
http_status = 500
status_code = "move target out of bounds"
class NoSuchAlertException(WebDriverException):
http_status = 400
status_code = "no such alert"
class NoSuchElementException(WebDriverException):
http_status = 404
status_code = "no such element"
class NoSuchFrameException(WebDriverException):
http_status = 400
status_code = "no such frame"
class NoSuchWindowException(WebDriverException):
http_status = 400
status_code = "no such window"
class ScriptTimeoutException(WebDriverException):
http_status = 408
status_code = "script timeout"
class SessionNotCreatedException(WebDriverException):
http_status = 500
status_code = "session not created"
class StaleElementReferenceException(WebDriverException):
http_status = 400
status_code = "stale element reference"
class TimeoutException(WebDriverException):
http_status = 408
status_code = "timeout"
class UnableToSetCookieException(WebDriverException):
http_status = 500
status_code = "unable to set cookie"
class UnexpectedAlertOpenException(WebDriverException):
http_status = 500
status_code = "unexpected alert open"
class UnknownErrorException(WebDriverException):
http_status = 500
status_code = "unknown error"
class UnknownCommandException(WebDriverException):
http_status = 404
status_code = "unknown command"
class UnknownMethodException(WebDriverException):
http_status = 405
status_code = "unknown method"
class UnsupportedOperationException(WebDriverException):
http_status = 500
status_code = "unsupported operation"
def get(status_code):
"""Gets exception from `status_code`, falling back to
``WebDriverException`` if it is not found.
"""
return _errors.get(status_code, WebDriverException)
_errors = collections.defaultdict()
for item in locals().values():
if type(item) == type and issubclass(item, WebDriverException):
_errors[item.status_code] = item

View file

@ -1,166 +0,0 @@
"""Definition of WebDriverException classes."""
def create_webdriver_exception_strict(status_code, message):
"""Create the appropriate WebDriverException given the status_code."""
if status_code in _exceptions_strict:
return _exceptions_strict[status_code](message)
return UnknownStatusCodeException("[%s] %s" % (status_code, message))
def create_webdriver_exception_compatibility(status_code, message):
"""Create the appropriate WebDriverException given the status_code."""
if status_code in _exceptions_compatibility:
return _exceptions_compatibility[status_code](message)
return UnknownStatusCodeException("[%s] %s" % (status_code, message))
class WebDriverException(Exception):
"""Base class for all WebDriverExceptions."""
class UnableToSetCookieException(WebDriverException):
"""A request to set a cookie's value could not be satisfied."""
class InvalidElementStateException(WebDriverException):
"""An element command could not be completed because the element is
in an invalid state (e.g. attempting to click an element that is no
longer attached to the DOM).
"""
class NoSuchElementException(WebDriverException):
"""An element could not be located on the page using the given
search parameters.
"""
class TimeoutException(WebDriverException):
"""An operation did not complete before its timeout expired."""
class ElementNotSelectableException(InvalidElementStateException):
"""An attempt was made to select an element that cannot be selected."""
class ElementNotVisibleException(InvalidElementStateException):
"""An element command could not be completed because the element is
not visible on the page.
"""
class ImeEngineActivationFailedException(WebDriverException):
"""An IME engine could not be started."""
class ImeNotAvailableException(ImeEngineActivationFailedException):
"""IME was not available."""
class InvalidCookieDomainException(UnableToSetCookieException):
"""An illegal attempt was made to set a cookie under a different
domain than the current page.
"""
class InvalidElementCoordinatesException(WebDriverException):
"""The coordinates provided to an interactions operation are invalid."""
class InvalidSelectorException(NoSuchElementException):
"""Argument was an invalid selector (e.g. XPath/CSS)."""
class JavascriptErrorException(WebDriverException):
"""An error occurred while executing user supplied JavaScript."""
class MoveTargetOutOfBoundsException(InvalidElementStateException):
"""The target for mouse interaction is not in the browser's viewport
and cannot be brought into that viewport.
"""
class NoSuchAlertException(WebDriverException):
"""An attempt was made to operate on a modal dialog when one was not open."""
class NoSuchFrameException(WebDriverException):
"""A request to switch to a frame could not be satisfied because
the frame could not be found."""
class NoSuchWindowException(WebDriverException):
"""A request to switch to a different window could not be satisfied
because the window could not be found.
"""
class ScriptTimeoutException(TimeoutException):
"""A script did not complete before its timeout expired."""
class SessionNotCreatedException(WebDriverException):
"""A new session could not be created."""
class StaleElementReferenceException(InvalidElementStateException):
"""An element command failed because the referenced element is no
longer attached to the DOM.
"""
class UnexpectedAlertOpenException(WebDriverException):
"""A modal dialog was open, blocking this operation."""
class UnknownCommandException(WebDriverException):
"""A command could not be executed because the remote end is not
aware of it.
"""
class UnknownErrorException(WebDriverException):
"""An unknown error occurred in the remote end while processing
the command.
"""
class UnsupportedOperationException(WebDriverException):
"""Indicates that a command that should have executed properly
cannot be supported for some reason.
"""
class UnknownStatusCodeException(WebDriverException):
"""Exception for all other status codes."""
_exceptions_strict = {
"element not selectable": ElementNotSelectableException,
"element not visible": ElementNotVisibleException,
"ime engine activation failed": ImeEngineActivationFailedException,
"ime not available": ImeNotAvailableException,
"invalid cookie domain": InvalidCookieDomainException,
"invalid element coordinates": InvalidElementCoordinatesException,
"invalid element state": InvalidElementStateException,
"invalid selector": InvalidSelectorException,
"javascript error": JavascriptErrorException,
"move target out of bounds": MoveTargetOutOfBoundsException,
"no such alert": NoSuchAlertException,
"no such element": NoSuchElementException,
"no such frame": NoSuchFrameException,
"no such window": NoSuchWindowException,
"script timeout": ScriptTimeoutException,
"session not created": SessionNotCreatedException,
"stale element reference": StaleElementReferenceException,
"success": None,
"timeout": TimeoutException,
"unable to set cookie": UnableToSetCookieException,
"unexpected alert open": UnexpectedAlertOpenException,
"unknown command": UnknownCommandException,
"unknown error": UnknownErrorException,
"unsupported operation": UnsupportedOperationException,
}
_exceptions_compatibility = {
15: ElementNotSelectableException,
11: ElementNotVisibleException,
31: ImeEngineActivationFailedException,
30: ImeNotAvailableException,
24: InvalidCookieDomainException,
29: InvalidElementCoordinatesException,
12: InvalidElementStateException,
19: InvalidSelectorException,
32: InvalidSelectorException,
17: JavascriptErrorException,
34: MoveTargetOutOfBoundsException,
27: NoSuchAlertException,
7: NoSuchElementException,
8: NoSuchFrameException,
23: NoSuchWindowException,
28: ScriptTimeoutException,
6: SessionNotCreatedException,
33: SessionNotCreatedException,
10: StaleElementReferenceException,
0: None, # success
21: TimeoutException,
25: UnableToSetCookieException,
26: UnexpectedAlertOpenException,
9: UnknownCommandException,
13: UnknownErrorException,
# "unsupported operation": UnsupportedOperationException
}

View file

@ -1,68 +0,0 @@
"""Constants for special keys."""
class Keys:
"""Constants for special keys."""
NULL = '\uE000'
CANCEL = '\uE001'
HELP = '\uE002'
BACK_SPACE = '\uE003'
TAB = '\uE004'
CLEAR = '\uE005'
RETURN = '\uE006'
ENTER = '\uE007'
SHIFT = '\uE008'
LEFT_SHIFT = '\uE008'
CONTROL = '\uE009'
LEFT_CONTROL = '\uE009'
ALT = '\uE00A'
LEFT_ALT = '\uE00A'
PAUSE = '\uE00B'
ESCAPE = '\uE00C'
SPACE = '\uE00D'
PAGE_UP = '\uE00E'
PAGE_DOWN = '\uE00F'
END = '\uE010'
HOME = '\uE011'
LEFT = '\uE012'
ARROW_LEFT = '\uE012'
UP = '\uE013'
ARROW_UP = '\uE013'
RIGHT = '\uE014'
ARROW_RIGHT = '\uE014'
DOWN = '\uE015'
ARROW_DOWN = '\uE015'
INSERT = '\uE016'
DELETE = '\uE017'
SEMICOLON = '\uE018'
EQUALS = '\uE019'
NUMPAD0 = '\uE01A'
NUMPAD1 = '\uE01B'
NUMPAD2 = '\uE01C'
NUMPAD3 = '\uE01D'
NUMPAD4 = '\uE01E'
NUMPAD5 = '\uE01F'
NUMPAD6 = '\uE020'
NUMPAD7 = '\uE021'
NUMPAD8 = '\uE022'
NUMPAD9 = '\uE023'
MULTIPLY = '\uE024'
ADD = '\uE025'
SEPARATOR = '\uE026'
SUBTRACT = '\uE027'
DECIMAL = '\uE028'
DIVIDE = '\uE029'
F1 = '\uE031'
F2 = '\uE032'
F3 = '\uE033'
F4 = '\uE034'
F5 = '\uE035'
F6 = '\uE036'
F7 = '\uE037'
F8 = '\uE038'
F9 = '\uE039'
F10 = '\uE03A'
F11 = '\uE03B'
F12 = '\uE03C'
META = '\uE03D'
COMMAND = '\uE03D'
ZENKAKU_HANKAKU = '\uE040'

View file

@ -1,54 +0,0 @@
"""WebDriver element location functionality."""
class SearchContext(object):
"""Abstract class that provides the core element location functionality."""
def find_element_by_css(self, selector):
"""Find the first element matching a css selector."""
return self._find_element('css selector', selector)
def find_elements_by_css(self, selector):
"""Find all elements matching a css selector."""
return self._find_elements('css selector', selector)
def find_element_by_link_text(self, text):
"""Find the first link with the given text."""
return self._find_element('link text', text)
def find_elements_by_link_text(self, text):
"""Find all links with the given text."""
return self._find_elements('link text', text)
def find_element_by_partial_link_text(self, text):
"""Find the first link containing the given text."""
return self._find_element('partial link text', text)
def find_elements_by_partial_link_text(self, text):
"""Find all links containing the given text."""
return self._find_elements('partial link text', text)
def find_element_by_xpath(self, xpath):
"""Find the first element matching the xpath."""
return self._find_element('xpath', xpath)
def find_elements_by_xpath(self, xpath):
"""Find all elements matching the xpath."""
return self._find_elements('xpath', xpath)
def _find_element(self, strategy, value):
return self.execute('POST',
'/element',
'findElement',
self._get_locator(strategy, value))
def _find_elements(self, strategy, value):
return self.execute('POST',
'/elements',
'findElements',
self._get_locator(strategy, value))
def _get_locator(self, strategy, value):
if self.mode == 'strict':
return {'strategy': strategy, 'value': value}
elif self.mode == 'compatibility':
return {'using': strategy, 'value': value}

View file

@ -0,0 +1,22 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
class ServoExtensionCommands(object):
def __init__(self, session):
self.session = session
@command
def get_prefs(self, *prefs):
body = {"prefs": list(prefs)}
return self.session.send_command("POST", "servo/prefs/get", body)
@command
def set_prefs(self, prefs):
body = {"prefs": prefs}
return self.session.send_command("POST", "servo/prefs/set", body)
@command
def reset_prefs(self, *prefs):
body = {"prefs": list(prefs)}
return self.session.send_command("POST", "servo/prefs/reset", body)

View file

@ -0,0 +1,117 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
import errno
import httplib
import json
import socket
import time
import urlparse
import error
HTTP_TIMEOUT = 5
class HTTPWireProtocol(object):
"""Transports messages (commands and responses) over the WebDriver
wire protocol.
"""
def __init__(self, host, port, url_prefix="/", timeout=HTTP_TIMEOUT):
"""Construct interface for communicating with the remote server.
:param url: URL of remote WebDriver server.
:param wait: Duration to wait for remote to appear.
"""
self.host = host
self.port = port
self.path_prefix = url_prefix
self._timeout = timeout
self._connection = None
def connect(self):
wait_for_port(self.host, self.port, self._timeout)
self._connection = httplib.HTTPConnection(
self.host, self.port, timeout=self._timeout)
def disconnect(self):
if self._connection:
self._connection.close()
self._connection = None
def url(self, suffix):
return urlparse.urljoin(self.path_prefix, suffix)
def send(self, method, url, body=None, headers=None, key=None):
"""Send a command to the remote.
:param method: "POST" or "GET".
: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.
"""
if not self._connection:
self.connect()
if body is None and method == "POST":
body = {}
if isinstance(body, dict):
body = json.dumps(body)
if isinstance(body, unicode):
body = body.encode("utf-8")
if headers is None:
headers = {}
url = self.path_prefix + url
self._connection.request(method, url, body, headers)
resp = self._connection.getresponse()
resp_body = resp.read()
try:
data = json.loads(resp_body)
except:
raise IOError("Could not parse response body as JSON: %s" % body)
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
def wait_for_port(host, port, timeout=HTTP_TIMEOUT):
"""Wait for a given host/port to be available."""
starttime = time.time()
poll_interval = 0.1
while time.time() - starttime < timeout:
sock = None
try:
sock = socket.socket()
sock.connect((host, port))
return True
except socket.error as e:
if e[0] != errno.ECONNREFUSED:
raise
finally:
if sock:
sock.close()
time.sleep(poll_interval)
return False

View file

@ -1,87 +0,0 @@
# Copyright 2011 Software Freedom Conservancy.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Waiting functionality."""
import time
from exceptions import NoSuchElementException
from exceptions import TimeoutException
POLL_FREQUENCY = 0.5 # How long to sleep inbetween calls to the method
IGNORED_EXCEPTIONS = [NoSuchElementException] # list of exceptions ignored during calls to the method
class WebDriverWait(object):
def __init__(self, driver, timeout, poll_frequency=POLL_FREQUENCY, ignored_exceptions=None):
"""Constructor, takes a WebDriver instance and timeout in seconds.
:Args:
- driver - Instance of WebDriver (Ie, Firefox, Chrome or Remote)
- timeout - Number of seconds before timing out
- poll_frequency - sleep interval between calls
By default, it is 0.5 second.
- ignored_exceptions - iterable structure of exception classes ignored during calls.
By default, it contains NoSuchElementException only.
Example:
from selenium.webdriver.support.ui import WebDriverWait \n
element = WebDriverWait(driver, 10).until(lambda x: x.find_element_by_id("someId")) \n
is_disappeared = WebDriverWait(driver, 30, 1, (ElementNotVisibleException)).\ \n
until_not(lambda x: x.find_element_by_id("someId").is_displayed())
"""
self._driver = driver
self._timeout = timeout
self._poll = poll_frequency
# avoid the divide by zero
if self._poll == 0:
self._poll = POLL_FREQUENCY
exceptions = IGNORED_EXCEPTIONS
if ignored_exceptions is not None:
try:
exceptions.extend(iter(ignored_exceptions))
except TypeError: # ignored_exceptions is not iterable
exceptions.append(ignored_exceptions)
self._ignored_exceptions = tuple(exceptions)
def until(self, method, message=''):
"""Calls the method provided with the driver as an argument until the \
return value is not False."""
end_time = time.time() + self._timeout
while(True):
try:
value = method(self._driver)
if value:
return value
except self._ignored_exceptions:
pass
time.sleep(self._poll)
if(time.time() > end_time):
break
raise TimeoutException(message)
def until_not(self, method, message=''):
"""Calls the method provided with the driver as an argument until the \
return value is False."""
end_time = time.time() + self._timeout
while(True):
try:
value = method(self._driver)
if not value:
return value
except self._ignored_exceptions:
return True
time.sleep(self._poll)
if(time.time() > end_time):
break
raise TimeoutException(message)

View file

@ -1,56 +0,0 @@
"""Element-level WebDriver operations."""
import searchcontext
class WebElement(searchcontext.SearchContext):
"""Corresponds to a DOM element in the current page."""
def __init__(self, driver, id):
self._driver = driver
self._id = id
# Set value of mode used by SearchContext
self.mode = driver.mode
def execute(self, method, path, name, body=None):
"""Execute a command against this WebElement."""
return self._driver.execute(
method, '/element/%s%s' % (self._id, path), name, body)
def is_displayed(self):
"""Is this element displayed?"""
return self.execute('GET', '/displayed', 'isDisplayed')
def is_selected(self):
"""Is this checkbox, radio button, or option selected?"""
return self.execute('GET', '/selected', 'isSelected')
def get_attribute(self, name):
"""Get the value of an element property or attribute."""
return self.execute('GET', '/attribute/%s' % name, 'getElementAttribute')
@property
def text(self):
"""Get the visible text for this element."""
return self.execute('GET', '/text', 'text')
@property
def tag_name(self):
"""Get the tag name for this element"""
return self.execute('GET', '/name', 'getElementTagName')
def click(self):
"""Click on this element."""
return self.execute('POST', '/click', 'click')
def clear(self):
"""Clear the contents of the this text input."""
self.execute('POST', '/clear', 'clear')
def send_keys(self, keys):
"""Send keys to this text input or body element."""
if isinstance(keys, str):
keys = [keys]
self.execute('POST', '/value', 'sendKeys', {'value': keys})
def to_json(self):
return {'ELEMENT': self.id}