Update web-platform-tests to revision 0d318188757a9c996e20b82db201fd04de5aa255

This commit is contained in:
James Graham 2015-03-27 09:15:38 +00:00
parent b2a5225831
commit 1a81b18b9f
12321 changed files with 544385 additions and 6 deletions

View file

@ -0,0 +1,26 @@
"""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

@ -0,0 +1,30 @@
"""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,111 @@
"""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

@ -0,0 +1,199 @@
"""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,166 @@
"""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

@ -0,0 +1,68 @@
"""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

@ -0,0 +1,54 @@
"""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,87 @@
# 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

@ -0,0 +1,56 @@
"""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}