-
Notifications
You must be signed in to change notification settings - Fork 567
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add appium prefix in create session and fix find_elements for W3C #196
Changes from 2 commits
a8160a8
eb2278e
2ffa61a
a3eaebb
3bbeb5b
d77735f
05e44b9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,7 +26,57 @@ | |
from selenium.webdriver.common.by import By | ||
from selenium.webdriver.remote.webelement import WebElement | ||
from selenium.webdriver.support.ui import WebDriverWait | ||
from selenium.common.exceptions import TimeoutException | ||
from selenium.common.exceptions import TimeoutException, InvalidArgumentException | ||
|
||
from selenium.webdriver.remote.command import Command as RemoteCommand | ||
import copy | ||
|
||
# From remote/webdriver.py | ||
_W3C_CAPABILITY_NAMES = frozenset([ | ||
'acceptInsecureCerts', | ||
'browserName', | ||
'browserVersion', | ||
'platformName', | ||
'pageLoadStrategy', | ||
'proxy', | ||
'setWindowRect', | ||
'timeouts', | ||
'unhandledPromptBehavior', | ||
]) | ||
|
||
# From remote/webdriver.py | ||
_OSS_W3C_CONVERSION = { | ||
'acceptSslCerts': 'acceptInsecureCerts', | ||
'version': 'browserVersion', | ||
'platform': 'platformName' | ||
} | ||
|
||
# override | ||
def _make_w3c_caps(caps): | ||
appium_prefix = 'appium:' | ||
|
||
caps = copy.deepcopy(caps) | ||
profile = caps.get('firefox_profile') | ||
always_match = {} | ||
if caps.get('proxy') and caps['proxy'].get('proxyType'): | ||
caps['proxy']['proxyType'] = caps['proxy']['proxyType'].lower() | ||
for k, v in caps.items(): | ||
if v and k in _OSS_W3C_CONVERSION: | ||
always_match[_OSS_W3C_CONVERSION[k]] = v.lower() if k == 'platform' else v | ||
if k in _W3C_CAPABILITY_NAMES or ':' in k: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we have a constant for ':' ? |
||
always_match[k] = v | ||
else: | ||
if not k.startswith(appium_prefix): | ||
always_match[appium_prefix + k] = v | ||
if profile: | ||
moz_opts = always_match.get('moz:firefoxOptions', {}) | ||
# If it's already present, assume the caller did that intentionally. | ||
if 'profile' not in moz_opts: | ||
# Don't mutate the original capabilities. | ||
new_opts = copy.deepcopy(moz_opts) | ||
new_opts['profile'] = profile | ||
always_match['moz:firefoxOptions'] = new_opts | ||
return {"firstMatch": [{}], "alwaysMatch": always_match} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PEP recommends to use single quotes by default for string constants |
||
|
||
|
||
class WebDriver(webdriver.Remote): | ||
|
@@ -48,6 +98,43 @@ def __init__(self, command_executor='http://127.0.0.1:4444/wd/hub', | |
By.ANDROID_UIAUTOMATOR = MobileBy.ANDROID_UIAUTOMATOR | ||
By.ACCESSIBILITY_ID = MobileBy.ACCESSIBILITY_ID | ||
|
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. one line space is enough between class methods |
||
def start_session(self, capabilities, browser_profile=None): | ||
""" | ||
Creates a new session with the desired capabilities. | ||
|
||
:Args: | ||
- browser_name - The name of the browser to request. | ||
- version - Which browser version to request. | ||
- platform - Which platform to request the browser on. | ||
- javascript_enabled - Whether the new session should support JavaScript. | ||
- browser_profile - A selenium.webdriver.firefox.firefox_profile.FirefoxProfile object. Only used if Firefox is requested. | ||
""" | ||
if not isinstance(capabilities, dict): | ||
raise InvalidArgumentException("Capabilities must be a dictionary") | ||
if browser_profile: | ||
if "moz:firefoxOptions" in capabilities: | ||
capabilities["moz:firefoxOptions"]["profile"] = browser_profile.encoded | ||
else: | ||
capabilities.update({'firefox_profile': browser_profile.encoded}) | ||
w3c_caps = _make_w3c_caps(capabilities) | ||
parameters = {"capabilities": w3c_caps, | ||
"desiredCapabilities": capabilities} | ||
response = self.execute(RemoteCommand.NEW_SESSION, parameters) | ||
if 'sessionId' not in response: | ||
response = response['value'] | ||
self.session_id = response['sessionId'] | ||
self.capabilities = response.get('value') | ||
|
||
# if capabilities is none we are probably speaking to | ||
# a W3C endpoint | ||
if self.capabilities is None: | ||
self.capabilities = response.get('capabilities') | ||
|
||
# Double check to see if we have a W3C Compliant browser | ||
self.w3c = response.get('status') is None | ||
|
||
|
||
@property | ||
def contexts(self): | ||
""" | ||
|
@@ -78,6 +165,61 @@ def context(self): | |
""" | ||
return self.current_context | ||
|
||
def find_element(self, by=By.ID, value=None): | ||
""" | ||
Override for Appium | ||
'Private' method used by the find_element_by_* methods. | ||
|
||
:Usage: | ||
Use the corresponding find_element_by_* instead of this. | ||
|
||
:rtype: WebElement | ||
""" | ||
# if self.w3c: | ||
# if by == By.ID: | ||
# by = By.CSS_SELECTOR | ||
# value = '[id="%s"]' % value | ||
# elif by == By.TAG_NAME: | ||
# by = By.CSS_SELECTOR | ||
# elif by == By.CLASS_NAME: | ||
# by = By.CSS_SELECTOR | ||
# value = ".%s" % value | ||
# elif by == By.NAME: | ||
# by = By.CSS_SELECTOR | ||
# value = '[name="%s"]' % value | ||
return self.execute(RemoteCommand.FIND_ELEMENT, { | ||
'using': by, | ||
'value': value})['value'] | ||
|
||
def find_elements(self, by=By.ID, value=None): | ||
""" | ||
Override for Appium | ||
'Private' method used by the find_elements_by_* methods. | ||
|
||
:Usage: | ||
Use the corresponding find_elements_by_* instead of this. | ||
|
||
:rtype: list of WebElement | ||
""" | ||
# if self.w3c: | ||
# if by == By.ID: | ||
# by = By.CSS_SELECTOR | ||
# value = '[id="%s"]' % value | ||
# elif by == By.TAG_NAME: | ||
# by = By.CSS_SELECTOR | ||
# elif by == By.CLASS_NAME: | ||
# by = By.CSS_SELECTOR | ||
# value = ".%s" % value | ||
# elif by == By.NAME: | ||
# by = By.CSS_SELECTOR | ||
# value = '[name="%s"]' % value | ||
|
||
# Return empty list if driver returns null | ||
# See https://github.com/SeleniumHQ/selenium/issues/4555 | ||
return self.execute(RemoteCommand.FIND_ELEMENTS, { | ||
'using': by, | ||
'value': value})['value'] or [] | ||
|
||
def find_element_by_ios_uiautomation(self, uia_string): | ||
"""Finds an element by uiautomation in iOS. | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-> iteritems
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With Python 3.x,
items()
looks enough as an iterator anditeritems
is deprecated.