mirror of
https://github.com/servo/servo.git
synced 2025-08-10 16:05:43 +01:00
Update web-platform-tests to revision 0d318188757a9c996e20b82db201fd04de5aa255
This commit is contained in:
parent
b2a5225831
commit
1a81b18b9f
12321 changed files with 544385 additions and 6 deletions
|
@ -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 })
|
|
@ -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'
|
|
@ -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()
|
199
tests/wpt/web-platform-tests/tools/webdriver/webdriver/driver.py
Normal file
199
tests/wpt/web-platform-tests/tools/webdriver/webdriver/driver.py
Normal 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
|
||||
|
|
@ -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
|
||||
}
|
|
@ -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'
|
|
@ -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}
|
|
@ -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)
|
|
@ -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}
|
Loading…
Add table
Add a link
Reference in a new issue