Skip to content
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

Merged
merged 7 commits into from
Jan 23, 2018
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 143 additions & 1 deletion appium/webdriver/webdriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> iteritems

Copy link
Member Author

@KazuCocoa KazuCocoa Jan 4, 2018

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 and iteritems is deprecated.

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:
Copy link
Contributor

Choose a reason for hiding this comment

The 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}
Copy link
Contributor

Choose a reason for hiding this comment

The 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):
Expand All @@ -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


Copy link
Contributor

Choose a reason for hiding this comment

The 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):
"""
Expand Down Expand Up @@ -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.

Expand Down