Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
138 lines
5.4 KiB
Python
Executable file
138 lines
5.4 KiB
Python
Executable file
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
import time
|
|
|
|
from marionette_driver import expected, By, Wait
|
|
from marionette_driver.errors import NoSuchElementException
|
|
|
|
from gaiatest import GaiaApps
|
|
from gaiatest import Accessibility
|
|
|
|
|
|
class Base(object):
|
|
DEFAULT_APP_HOSTNAME = '.gaiamobile.org'
|
|
DEFAULT_PROTOCOL = 'app://'
|
|
|
|
def __init__(self, marionette):
|
|
self.marionette = marionette
|
|
self.apps = GaiaApps(self.marionette)
|
|
self.accessibility = Accessibility(self.marionette)
|
|
self.frame = None
|
|
self.entry_point = hasattr(self, 'entry_point') and self.entry_point or None
|
|
|
|
def launch(self, launch_timeout=None):
|
|
self.app = self.apps.launch(self.name, self.manifest_url, self.entry_point, launch_timeout=launch_timeout)
|
|
|
|
def is_element_present(self, by, locator):
|
|
self.marionette.set_search_timeout(0)
|
|
try:
|
|
self.marionette.find_element(by, locator)
|
|
return True
|
|
except NoSuchElementException:
|
|
return False
|
|
finally:
|
|
self.marionette.set_search_timeout(self.marionette.timeout or 10000)
|
|
|
|
def is_element_displayed(self, by, locator):
|
|
self.marionette.set_search_timeout(0)
|
|
try:
|
|
return self.marionette.find_element(by, locator).is_displayed()
|
|
except NoSuchElementException:
|
|
return False
|
|
finally:
|
|
self.marionette.set_search_timeout(self.marionette.timeout or 10000)
|
|
|
|
def find_select_item(self, match_string):
|
|
_list_item_locator = (By.CSS_SELECTOR, 'section.value-selector-container li label')
|
|
|
|
# have to go back to top level to get the B2G select box wrapper
|
|
self.marionette.switch_to_frame()
|
|
# TODO we should find something suitable to wait for, but this goes too
|
|
# fast against desktop builds causing intermittent failures
|
|
time.sleep(0.2)
|
|
|
|
Wait(self.marionette).until(expected.element_present(*_list_item_locator))
|
|
|
|
for item in self.marionette.find_elements(*_list_item_locator):
|
|
if match_string == item.text.encode('ascii','ignore').strip():
|
|
# We need to keep this because the Ok button may hang over the element and stop
|
|
# Marionette from scrolling the element entirely into view
|
|
self.marionette.execute_script('arguments[0].scrollIntoView(false);', [item])
|
|
return item
|
|
|
|
def wait_for_select_closed(self, by, locator):
|
|
Wait(self.marionette).until(expected.element_not_displayed(by, locator))
|
|
|
|
# now back to app
|
|
self.apps.switch_to_displayed_app()
|
|
|
|
# TODO we should find something suitable to wait for, but this goes too
|
|
# fast against desktop builds causing intermittent failures
|
|
# This sleep is necessary to make sure the select is completely faded out,
|
|
# see bug 1148154
|
|
time.sleep(1)
|
|
|
|
def select(self, match_string, tap_close=True):
|
|
# cheeky Select wrapper until Marionette has its own
|
|
# due to the way B2G wraps the app's select box we match on text
|
|
_close_button_locator = (By.CSS_SELECTOR, 'button.value-option-confirm')
|
|
|
|
li = self.find_select_item(match_string)
|
|
li.tap()
|
|
|
|
# Tap close and wait for it to hide
|
|
if tap_close:
|
|
self.marionette.find_element(*_close_button_locator).tap()
|
|
self.wait_for_select_closed(*_close_button_locator)
|
|
|
|
def a11y_select(self, match_string):
|
|
# Accessibility specific select method
|
|
_close_button_locator = (By.CSS_SELECTOR, 'button.value-option-confirm')
|
|
|
|
li = self.find_select_item(match_string)
|
|
self.accessibility.click(li)
|
|
|
|
# A11y click close and wait for it to hide
|
|
self.accessibility.click(self.marionette.find_element(*_close_button_locator))
|
|
self.wait_for_select_closed(*_close_button_locator)
|
|
|
|
def tap_element_from_system_app(self, element=None, add_statusbar_height=False, x=None, y=None):
|
|
# Workaround for bug 1109213, where tapping on the button inside the app itself
|
|
# makes Marionette spew out NoSuchWindowException errors, see bug 1164078
|
|
cx = element.rect['x']
|
|
cy = element.rect['y']
|
|
cx += element.rect['width']//2 if x is None else x
|
|
cy += element.rect['height']//2 if y is None else y
|
|
|
|
from gaiatest.apps.system.app import System
|
|
system = System(self.marionette)
|
|
if add_statusbar_height:
|
|
cy = cy + system.status_bar.height
|
|
system.tap(cx, cy)
|
|
|
|
@property
|
|
def keyboard(self):
|
|
from gaiatest.apps.keyboard.app import Keyboard
|
|
return Keyboard(self.marionette)
|
|
|
|
@property
|
|
def manifest_url(self):
|
|
return '{}{}{}/manifest.webapp'.format(self.DEFAULT_PROTOCOL, self.__class__.__name__.lower(), self.DEFAULT_APP_HOSTNAME)
|
|
|
|
@property
|
|
def is_displayed(self):
|
|
return (self.apps.displayed_app.manifest_url == self.manifest_url and
|
|
self.apps.displayed_app.entry_point == self.entry_point)
|
|
|
|
def wait_to_be_displayed(self):
|
|
Wait(self.marionette).until(lambda m: self.is_displayed == True)
|
|
|
|
def wait_to_not_be_displayed(self):
|
|
Wait(self.marionette).until(lambda m: self.is_displayed == False)
|
|
|
|
class PageRegion(Base):
|
|
def __init__(self, marionette, element):
|
|
self.root_element = element
|
|
Base.__init__(self, marionette)
|