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

added webview and automatic context selection #365

Closed
Show file tree
Hide file tree
Changes from all 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
52 changes: 0 additions & 52 deletions toolium/pageelements/page_element.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ class PageElement(CommonObject):
or toolium.pageelements.PageElement
or (selenium.webdriver.common.by.By or appium.webdriver.common.mobileby.MobileBy, str)
"""
native_context = "NATIVE_APP"
webview_context_prefix = "WEBVIEW"

def __init__(self, by, value, parent=None, order=None, wait=False, shadowroot=None, webview=False,
webview_context_selection_callback=None, webview_csc_args=None):
Expand Down Expand Up @@ -119,56 +117,6 @@ def _find_web_element(self):
self._web_element = base.find_elements(*self.locator)[self.order] if self.order \
else base.find_element(*self.locator)

def _android_automatic_context_selection(self):
"""Change context selection depending if the element is a webview for android devices"""
# we choose the appPackage webview context, and select the first window returned by mobile: getContexts
if self.webview:
context = None
window_handle = None
if self.webview_context_selection_callback:
context, window_handle = self.webview_context_selection_callback(*self.webview_csc_args)
else:
app_web_context = "{}_{}".format(PageElement.webview_context_prefix,
self.driver.capabilities['appPackage'])
if app_web_context in self.driver.contexts:
context = app_web_context
if self.driver.context != context:
self.driver.switch_to.context(context)
window_handle = self.driver.window_handles[0]
else:
raise KeyError("WEBVIEW context not found")

if context:
if self.driver.context != context:
self.driver.switch_to.context(context)
if self.driver.current_window_handle != window_handle:
self.driver.switch_to.window(window_handle)
else:
raise KeyError("WEBVIEW context not found")
else:
if self.driver.context != PageElement.native_context:
self.driver.switch_to.context(PageElement.native_context)

def _ios_automatic_context_selection(self):
"""Change context selection depending if the element is a webview for ios devices"""
# we choose the last webview context returned by mobile: getContexts for the bundleid
if self.webview:
if self.webview_context_selection_callback:
context_id = self.webview_context_selection_callback(*self.webview_csc_args)
else:
contexts = self.driver.execute_script('mobile: getContexts')
context_id = next(
(item['id'] for item in reversed(contexts) if
'bundleId' in item and item['bundleId'] == self.driver.capabilities['bundleId']),
None)
if context_id:
if self.driver.context != context_id:
self.driver.switch_to.context(context_id)
else:
raise KeyError("WEBVIEW context not found")
else:
if self.driver.context != PageElement.native_context:
self.driver.switch_to.context(PageElement.native_context)

def parent_locator_str(self):
"""Return string with locator tuple for parent element
Expand Down
23 changes: 21 additions & 2 deletions toolium/pageelements/page_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ class PageElements(CommonObject):
"""
page_element_class = PageElement #: class of page elements (PageElement, Button...)

def __init__(self, by, value, parent=None, page_element_class=None, order=None):
def __init__(self, by, value, parent=None, page_element_class=None, order=None, webview=False,
webview_context_selection_callback=None, webview_csc_args=None):
"""Initialize the PageElements object with the given locator components.

If parent is not None, find_elements will be performed over it, instead of
Expand All @@ -53,6 +54,11 @@ def __init__(self, by, value, parent=None, page_element_class=None, order=None):
:param order: index value if the locator returns more than one element
:param page_element_class: class of page elements (PageElement, Button...)
:param shadowroot: CSS SELECTOR of JS element where shadowroot tag appears
:param webview: True if the element is in a mobile webiew
:param webview_context_selection_callback: method provided to select the desired webview context if
automatic_context_selection is enabled. Must return a tuple (context, window_handle) for android, and a context
for ios
:param webview_csc_args: arguments list for webview_context_selection_callback
"""
super(PageElements, self).__init__()
self.locator = (by, value) #: tuple with locator type and locator value
Expand All @@ -61,6 +67,10 @@ def __init__(self, by, value, parent=None, page_element_class=None, order=None):
self.shadowroot = None #: Not implemented for PageElements yet
self.driver_wrapper = DriverWrappersPool.get_default_wrapper() #: driver wrapper instance
# update instance element class or use PageElement class
self.webview = webview
self.webview_context_selection_callback = webview_context_selection_callback #: callback for selection of the
# webview context with automatic_context_selection
self.webview_csc_args = webview_csc_args #: arguments list for the context selection callback method
if page_element_class:
self.page_element_class = page_element_class
self._page_elements = []
Expand Down Expand Up @@ -90,6 +100,12 @@ def web_elements(self):
if self.parent:
self._web_elements = self.utils.get_web_element(self.parent).find_elements(*self.locator)
else:
# check context for mobile webviews
if self.driver_wrapper.config.getboolean_optional('Driver', 'automatic_context_selection'):
if self.driver_wrapper.is_android_test():
self._android_automatic_context_selection()
elif self.driver_wrapper.is_ios_test():
self._ios_automatic_context_selection()
self._web_elements = self.driver.find_elements(*self.locator)
return self._web_elements

Expand All @@ -105,7 +121,9 @@ def page_elements(self) -> List[Any]:
for order, web_element in enumerate(self.web_elements):
# Create multiple PageElement with original locator and order
page_element = self.page_element_class(self.locator[0], self.locator[1], parent=self.parent,
order=order)
order=order, webview = self.webview,
webview_context_selection_callback = self.webview_context_selection_callback,
webview_csc_args = self.webview_csc_args)
page_element.reset_object(self.driver_wrapper)
page_element._web_element = web_element
self._page_elements.append(page_element)
Expand All @@ -121,6 +139,7 @@ def __iter__(self):
return iter(self.page_elements)



class Buttons(PageElements):
page_element_class = Button

Expand Down
53 changes: 53 additions & 0 deletions toolium/pageobjects/common_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class CommonObject(object):
:type logger: logging.Logger
:type driver_wrapper: toolium.driver_wrapper.DriverWrapper
"""
native_context = "NATIVE_APP"
webview_context_prefix = "WEBVIEW"

def __init__(self):
"""Initialize common object"""
Expand Down Expand Up @@ -62,3 +64,54 @@ def utils(self):
:returns: utils instance
"""
return self.driver_wrapper.utils

def _android_automatic_context_selection(self):
"""Change context selection depending if the element is a webview for android devices"""
# we choose the appPackage webview context, and select the first window returned by mobile: getContexts
if self.webview:
context = None
window_handle = None
if self.webview_context_selection_callback:
context, window_handle = self.webview_context_selection_callback(*self.webview_csc_args)
else:
app_web_context = "{}_{}".format(CommonObject.webview_context_prefix,
self.driver.capabilities['appPackage'])
if app_web_context in self.driver.contexts:
context = app_web_context
if self.driver.context != context:
self.driver.switch_to.context(context)
window_handle = self.driver.window_handles[0]
else:
raise KeyError("WEBVIEW context not found")

if context:
if self.driver.context != context:
self.driver.switch_to.context(context)
if self.driver.current_window_handle != window_handle:
self.driver.switch_to.window(window_handle)
else:
raise KeyError("WEBVIEW context not found")
else:
if self.driver.context != CommonObject.native_context:
self.driver.switch_to.context(CommonObject.native_context)

def _ios_automatic_context_selection(self):
"""Change context selection depending if the element is a webview for ios devices"""
# we choose the last webview context returned by mobile: getContexts for the bundleid
if self.webview:
if self.webview_context_selection_callback:
context_id = self.webview_context_selection_callback(*self.webview_csc_args)
else:
contexts = self.driver.execute_script('mobile: getContexts')
context_id = next(
(item['id'] for item in reversed(contexts) if
'bundleId' in item and item['bundleId'] == self.driver.capabilities['bundleId']),
None)
if context_id:
if self.driver.context != context_id:
self.driver.switch_to.context(context_id)
else:
raise KeyError("WEBVIEW context not found")
else:
if self.driver.context != CommonObject.native_context:
self.driver.switch_to.context(CommonObject.native_context)
Loading