Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
parent
93e3a48004
commit
b38dea0597
25901 changed files with 9982925 additions and 369 deletions
1
gaia/tests/python/gaia-ui-tests/gaiatest/.gitignore
vendored
Executable file
1
gaia/tests/python/gaia-ui-tests/gaiatest/.gitignore
vendored
Executable file
|
|
@ -0,0 +1 @@
|
|||
atoms
|
||||
6
gaia/tests/python/gaia-ui-tests/gaiatest/__init__.py
Executable file
6
gaia/tests/python/gaia-ui-tests/gaiatest/__init__.py
Executable file
|
|
@ -0,0 +1,6 @@
|
|||
# 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/.
|
||||
|
||||
from gaia_test import *
|
||||
from mixins import *
|
||||
3
gaia/tests/python/gaia-ui-tests/gaiatest/apps/__init__.py
Executable file
3
gaia/tests/python/gaia-ui-tests/gaiatest/apps/__init__.py
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
# 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/.
|
||||
138
gaia/tests/python/gaia-ui-tests/gaiatest/apps/base.py
Executable file
138
gaia/tests/python/gaia-ui-tests/gaiatest/apps/base.py
Executable file
|
|
@ -0,0 +1,138 @@
|
|||
# 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)
|
||||
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/bugzillalite/__init__.py
Executable file
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/bugzillalite/__init__.py
Executable file
54
gaia/tests/python/gaia-ui-tests/gaiatest/apps/bugzillalite/app.py
Executable file
54
gaia/tests/python/gaia-ui-tests/gaiatest/apps/bugzillalite/app.py
Executable file
|
|
@ -0,0 +1,54 @@
|
|||
from gaiatest.apps.base import Base
|
||||
from marionette_driver import By, Wait, expected
|
||||
|
||||
class BugzillaLite(Base):
|
||||
|
||||
name = 'Bugzilla Lite'
|
||||
manifest_url = "https://www.bzlite.com/manifest.webapp"
|
||||
_given_username = (By.CSS_SELECTOR, "#login input[type='email']")
|
||||
_given_password = (By.CSS_SELECTOR, "#login input[type='password']")
|
||||
_button_login = (By.CSS_SELECTOR, "#login input[type='submit']")
|
||||
_profile_icon = (By.CSS_SELECTOR, "a[href='/profile/']")
|
||||
_button_logout = (By.CSS_SELECTOR, "a[href='/logout/']")
|
||||
_dashboard_navigator_locator = (By.ID, 'navigation')
|
||||
_login_form_locator = (By.ID, 'login')
|
||||
_popup_intro = (By.ID, 'intro')
|
||||
_button_popup_intro = (By.ID, 'intro-submit')
|
||||
def login (self, username, password):
|
||||
username_element = self.marionette.find_element(*self._given_username)
|
||||
username_element.tap()
|
||||
username_element.send_keys(username)
|
||||
password_element = self.marionette.find_element(*self._given_password)
|
||||
password_element.tap()
|
||||
password_element.send_keys(password)
|
||||
button_element = self.marionette.find_element(*self._button_login)
|
||||
button_element.tap()
|
||||
|
||||
def logout(self):
|
||||
profile_element = self.marionette.find_element(*self._profile_icon)
|
||||
profile_element.tap()
|
||||
logout_element = self.marionette.find_element(*self._button_logout)
|
||||
logout_element.tap()
|
||||
|
||||
@property
|
||||
def is_logged_in(self):
|
||||
self.wait_for_dashboard_navigator_to_be_displayed()
|
||||
return True
|
||||
|
||||
def wait_for_dashboard_navigator_to_be_displayed(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(*self._dashboard_navigator_locator))))
|
||||
|
||||
@property
|
||||
def is_logged_out(self):
|
||||
self.wait_for_login_form_to_be_displayed()
|
||||
return True
|
||||
|
||||
def wait_for_login_form_to_be_displayed(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(*self._login_form_locator))))
|
||||
|
||||
def dismiss_tooltip(self):
|
||||
confirm_element = Wait(self.marionette).until(expected.element_present(*self._button_popup_intro))
|
||||
Wait(self.marionette).until(expected.element_displayed(confirm_element))
|
||||
confirm_element.tap()
|
||||
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/calendar/__init__.py
Executable file
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/calendar/__init__.py
Executable file
306
gaia/tests/python/gaia-ui-tests/gaiatest/apps/calendar/app.py
Executable file
306
gaia/tests/python/gaia-ui-tests/gaiatest/apps/calendar/app.py
Executable file
|
|
@ -0,0 +1,306 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
from marionette_driver.errors import (NoSuchElementException,
|
||||
StaleElementException)
|
||||
from marionette_driver.marionette import Actions
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.base import PageRegion
|
||||
from gaiatest.apps.calendar.regions.event_details import EventDetails
|
||||
|
||||
|
||||
class Calendar(Base):
|
||||
|
||||
name = 'Calendar'
|
||||
|
||||
_current_month_year_locator = (By.ID, 'current-month-year')
|
||||
_current_month_day_agenda_locator = (By.ID, 'month-day-agenda')
|
||||
_current_monthly_calendar_locator = (By.ID, 'month-view')
|
||||
_add_event_button_locator = (By.XPATH, "//a[@href='/event/add/']")
|
||||
|
||||
_month_display_button_locator = (By.XPATH, "//a[@href='/month/']")
|
||||
_week_display_button_locator = (By.XPATH, "//a[@href='/week/']")
|
||||
_day_display_button_locator = (By.XPATH, "//a[@href='/day/']")
|
||||
_day_view_locator = (By.ID, 'day-view')
|
||||
_week_view_locator = (By.ID, 'week-view')
|
||||
|
||||
_time_views_locator = (By.ID, 'time-views')
|
||||
_modify_event_view_locator = (By.ID, 'modify-event-view')
|
||||
_event_view_locator = (By.ID, 'event-view')
|
||||
_time_header_locator = (By.ID, 'time-header')
|
||||
|
||||
_create_account_button_locator = (By.CLASS_NAME, 'create-account')
|
||||
_create_account_header_locator = (By.ID, 'create-account-header')
|
||||
_create_account_view_locator = (By.ID, 'create-account-view')
|
||||
_create_account_preset_locator = (By.CSS_SELECTOR,
|
||||
'#create-account-presets a')
|
||||
|
||||
_modify_account_header_locator = (By.ID, 'modify-account-header')
|
||||
_modify_account_view_locator = (By.ID, 'modify-account-view')
|
||||
|
||||
_settings_locator = (By.ID, 'settings')
|
||||
|
||||
_advanced_settings_view_locator = (By.ID, 'advanced-settings-view')
|
||||
_advanced_settings_done_button_locator = (By.XPATH, "//a[@href='/settings/']")
|
||||
|
||||
_event_list_date_locator = (By.ID, 'event-list-date')
|
||||
_event_list_empty_locator = (By.ID, 'empty-message')
|
||||
_event_locator = (By.CLASS_NAME, 'event')
|
||||
_today_locator = (By.CSS_SELECTOR, '.month.active .present')
|
||||
_tomorrow_locator = (By.CSS_SELECTOR, '.month.active .present + li > .day')
|
||||
|
||||
_day_view_all_day_button = (By.CSS_SELECTOR,
|
||||
'.day-view .md__allday:nth-child(2) .md__allday-events')
|
||||
_day_view_event_link = (By.CSS_SELECTOR, '.day-view .md__day:nth-child(2) .md__event')
|
||||
|
||||
def launch(self):
|
||||
Base.launch(self)
|
||||
# empty message is only displayed after first MonthsDay#render,
|
||||
# so we are sure app is "ready" after that
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._event_list_empty_locator))))
|
||||
|
||||
@property
|
||||
def current_month_year(self):
|
||||
return self.marionette.find_element(*self._current_month_year_locator).text
|
||||
|
||||
@property
|
||||
def current_month_day(self):
|
||||
return self.marionette.find_element(*self._current_month_day_agenda_locator).get_attribute('data-date')
|
||||
|
||||
@property
|
||||
def event_list_date(self):
|
||||
return self.marionette.find_element(*self._event_list_date_locator).text
|
||||
|
||||
@property
|
||||
def events(self):
|
||||
return [self.Event(marionette=self.marionette, element=event)
|
||||
for event in self.marionette.find_elements(*self._event_locator)]
|
||||
|
||||
def wait_for_events(self, number_to_wait_for=1):
|
||||
Wait(self.marionette).until(lambda m: len(m.find_elements(*self._event_locator)) == number_to_wait_for)
|
||||
|
||||
def event(self, title):
|
||||
for event in self.events:
|
||||
if event.title == title:
|
||||
return event
|
||||
|
||||
@property
|
||||
def accounts(self):
|
||||
return [account for account in self.marionette.find_elements(
|
||||
*self._create_account_preset_locator)]
|
||||
|
||||
def account(self, preset):
|
||||
for account in self.accounts:
|
||||
if account.get_attribute('data-provider') == preset:
|
||||
return account
|
||||
|
||||
@property
|
||||
def settings(self):
|
||||
return self.Settings(marionette=self.marionette,
|
||||
element=self.marionette.find_elements(*self._settings_locator))
|
||||
|
||||
def wait_for_new_event(self):
|
||||
from gaiatest.apps.calendar.regions.event import NewEvent
|
||||
new_event = NewEvent(self.marionette)
|
||||
new_event.wait_for_panel_to_load()
|
||||
return new_event
|
||||
|
||||
def a11y_click_add_event_button(self):
|
||||
self.accessibility.click(self.marionette.find_element(*self._add_event_button_locator))
|
||||
return self.wait_for_new_event()
|
||||
|
||||
def tap_add_event_button(self):
|
||||
self.marionette.find_element(*self._add_event_button_locator).tap()
|
||||
return self.wait_for_new_event()
|
||||
|
||||
def a11y_click_week_display_button(self):
|
||||
self.accessibility.click(self.marionette.find_element(*self._week_display_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._week_view_locator))))
|
||||
|
||||
def tap_week_display_button(self):
|
||||
self.marionette.find_element(*self._week_display_button_locator).tap()
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._week_view_locator))))
|
||||
|
||||
def a11y_click_month_display_button(self):
|
||||
self.accessibility.click(self.marionette.find_element(*self._month_display_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._current_monthly_calendar_locator))))
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._current_month_day_agenda_locator))))
|
||||
|
||||
def a11y_click_day_display_button(self):
|
||||
self.accessibility.click(self.marionette.find_element(*self._day_display_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._day_view_locator))))
|
||||
|
||||
def tap_day_display_button(self):
|
||||
self.marionette.find_element(*self._day_display_button_locator).tap()
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._day_view_locator))))
|
||||
|
||||
def displayed_events_in_month_view(self):
|
||||
return self.marionette.find_element(*self._get_events_locator_in_month_view()).text
|
||||
|
||||
def displayed_events_in_week_view(self, data_date):
|
||||
return self.marionette.find_element(*self._get_events_locator_in_week_view(data_date)).text
|
||||
|
||||
def displayed_events_in_day_view(self, data_date):
|
||||
return self.marionette.find_element(*self._get_events_locator_in_day_view(data_date)).text
|
||||
|
||||
def _get_events_locator_in_day_view(self, data_date):
|
||||
return (By.CSS_SELECTOR,
|
||||
"#day-view .md__day[data-date*='%s'] .md__event" % data_date)
|
||||
|
||||
def _get_events_locator_in_month_view(self):
|
||||
return (By.CSS_SELECTOR,
|
||||
'#event-list .event')
|
||||
|
||||
def _get_events_locator_in_week_view(self, data_date):
|
||||
return (By.CSS_SELECTOR,
|
||||
"#week-view .md__day[data-date*='%s'] .md__event" % data_date)
|
||||
|
||||
def a11y_click_other_day(self, next, previous):
|
||||
try:
|
||||
# Try clicking tomorrow
|
||||
self.accessibility.click(self.marionette.find_element(*self._tomorrow_locator))
|
||||
return next
|
||||
except NoSuchElementException:
|
||||
# Tomorrow is next week or month, try clicking yesterday.
|
||||
yesterday = self.marionette.execute_script(
|
||||
"return arguments[0].previousSibling.querySelector('.day');",
|
||||
[self.marionette.find_element(*self._today_locator)])
|
||||
self.accessibility.click(yesterday)
|
||||
return previous
|
||||
|
||||
def a11y_click_header(self, header, selector):
|
||||
self.accessibility.execute_async_script(
|
||||
"Accessibility.click(arguments[0].shadowRoot.querySelector('%s'));" % selector,
|
||||
[header])
|
||||
|
||||
def wait_fot_settings_drawer_animation(self):
|
||||
el = self.marionette.find_element(*self.settings._settings_drawer_locator)
|
||||
Wait(self.marionette).until(lambda m: el.get_attribute('data-animstate') == 'done')
|
||||
|
||||
def a11y_click_create_account_back(self):
|
||||
self.a11y_click_header(self.marionette.find_element(*self._create_account_header_locator),
|
||||
'button.action-button')
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._advanced_settings_view_locator))))
|
||||
|
||||
def a11y_click_modify_account_back(self):
|
||||
self.a11y_click_header(self.marionette.find_element(*self._modify_account_header_locator),
|
||||
'button.action-button')
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._create_account_view_locator))))
|
||||
|
||||
def a11y_click_settings(self):
|
||||
self.a11y_click_header(self.marionette.find_element(*self._time_header_locator),
|
||||
'button.action-button')
|
||||
self.wait_fot_settings_drawer_animation()
|
||||
|
||||
def a11y_click_close_settings(self):
|
||||
self.a11y_click_header(self.marionette.find_element(
|
||||
*self.settings._settings_header_locator), 'button.action-button')
|
||||
self.wait_fot_settings_drawer_animation()
|
||||
|
||||
def a11y_create_event(self, title):
|
||||
new_event = self.a11y_click_add_event_button()
|
||||
# create a new event
|
||||
new_event.a11y_fill_event_title(title)
|
||||
new_event.a11y_click_save_event()
|
||||
self.wait_for_events(1)
|
||||
|
||||
def a11y_click_day_view_event(self):
|
||||
self.accessibility.click(self.marionette.find_element(*self._day_view_event_link))
|
||||
el = self.marionette.find_element(*self._event_view_locator)
|
||||
Wait(self.marionette).until(expected.element_displayed(el))
|
||||
return EventDetails(self.marionette)
|
||||
|
||||
def flick_to_next_month(self):
|
||||
self._flick_to_month('next')
|
||||
|
||||
def flick_to_previous_month(self):
|
||||
self._flick_to_month('previous')
|
||||
|
||||
def a11y_wheel_to_next_month(self):
|
||||
self._a11y_wheel_to_month('left')
|
||||
|
||||
def a11y_wheel_to_previous_month(self):
|
||||
self._a11y_wheel_to_month('right')
|
||||
|
||||
def _a11y_wheel_to_month(self, direction):
|
||||
self.accessibility.wheel(self.marionette.find_element(
|
||||
*self._current_monthly_calendar_locator), direction)
|
||||
|
||||
def _flick_to_month(self, direction):
|
||||
"""Flick current monthly calendar to next or previous month.
|
||||
|
||||
@param direction: flick to next month if direction='next', else flick to previous month
|
||||
"""
|
||||
action = Actions(self.marionette)
|
||||
|
||||
month = self.marionette.find_element(
|
||||
*self._current_monthly_calendar_locator)
|
||||
month_year = self.current_month_year
|
||||
|
||||
x_start = (month.size['width'] / 100) * (direction == 'next' and 90 or 10)
|
||||
x_end = (month.size['width'] / 100) * (direction == 'next' and 10 or 90)
|
||||
y_start = month.size['height'] / 4
|
||||
y_end = month.size['height'] / 4
|
||||
|
||||
action.flick(month, x_start, y_start, x_end, y_end, 200).perform()
|
||||
|
||||
Wait(self.marionette).until(lambda m: self.current_month_year != month_year)
|
||||
|
||||
class Settings(PageRegion):
|
||||
|
||||
_calendar_local_locator = (By.CSS_SELECTOR, '#calendar-local-first .pack-checkbox')
|
||||
_calendar_local_checkbox_locator = (By.CSS_SELECTOR,
|
||||
'#calendar-local-first input[type="checkbox"]')
|
||||
_advanced_settings_button_locator = (By.CSS_SELECTOR, '.settings')
|
||||
_settings_header_locator = (By.ID, 'settings-header')
|
||||
_settings_drawer_locator = (By.CLASS_NAME, 'settings-drawer')
|
||||
|
||||
def wait_for_calendar_unchecked(self, timeout=None):
|
||||
checkbox = self.marionette.find_element(*self._calendar_local_checkbox_locator)
|
||||
Wait(self.marionette, timeout).until(expected.element_not_selected(checkbox))
|
||||
|
||||
def wait_for_a11y_calendar_unchecked(self, timeout=None):
|
||||
Wait(self.marionette, timeout, ignored_exceptions=StaleElementException).until(
|
||||
lambda m: not self.marionette.find_element(
|
||||
*self._calendar_local_locator).get_attribute('aria-selected'))
|
||||
|
||||
class Event(PageRegion):
|
||||
|
||||
_title_locator = (By.TAG_NAME, 'h5')
|
||||
_location_locator = (By.CLASS_NAME, 'location')
|
||||
_event_view_locator = (By.ID, 'event-view')
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
return self.root_element.find_element(*self._title_locator).text
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
return self.root_element.find_element(*self._location_locator).text
|
||||
|
||||
def a11y_click(self):
|
||||
self.accessibility.click(self.root_element)
|
||||
el = self.marionette.find_element(*self._event_view_locator)
|
||||
Wait(self.marionette).until(expected.element_displayed(el))
|
||||
return EventDetails(self.marionette)
|
||||
68
gaia/tests/python/gaia-ui-tests/gaiatest/apps/calendar/regions/event.py
Executable file
68
gaia/tests/python/gaia-ui-tests/gaiatest/apps/calendar/regions/event.py
Executable file
|
|
@ -0,0 +1,68 @@
|
|||
# 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/.
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.calendar.app import Calendar
|
||||
|
||||
|
||||
class NewEvent(Calendar):
|
||||
|
||||
_modify_event_view_locator = (By.ID, 'modify-event-view')
|
||||
_modify_event_header_locator = (By.ID, 'modify-event-header')
|
||||
_event_title_input_locator = (By.XPATH, "//input[@data-l10n-id='event-title']")
|
||||
_event_location_input_locator = (By.XPATH, "//input[@data-l10n-id='event-location']")
|
||||
_event_start_time_value_locator = (By.ID, "start-time-locale")
|
||||
_event_start_date_value_locator = (By.ID, "start-date-locale")
|
||||
_edit_event_button_locator = (By.CSS_SELECTOR, 'button.edit')
|
||||
_save_event_button_locator = (By.CSS_SELECTOR, 'button.save')
|
||||
|
||||
def wait_for_panel_to_load(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._event_title_input_locator))))
|
||||
|
||||
def a11y_fill_event_title(self, title):
|
||||
self.accessibility.click(self.marionette.find_element(*self._event_title_input_locator))
|
||||
self.keyboard.send(title)
|
||||
self.keyboard.dismiss()
|
||||
|
||||
def fill_event_title(self, title):
|
||||
self.marionette.find_element(*self._event_title_input_locator).tap()
|
||||
self.keyboard.send(title)
|
||||
self.keyboard.dismiss()
|
||||
|
||||
def a11y_fill_event_location(self, location):
|
||||
self.accessibility.click(self.marionette.find_element(*self._event_location_input_locator))
|
||||
self.keyboard.send(location)
|
||||
self.keyboard.dismiss()
|
||||
|
||||
def fill_event_location(self, location):
|
||||
self.marionette.find_element(*self._event_location_input_locator).tap()
|
||||
self.keyboard.send(location)
|
||||
self.keyboard.dismiss()
|
||||
|
||||
def a11y_click_close_button(self):
|
||||
self.accessibility.execute_async_script(
|
||||
"Accessibility.click(arguments[0].shadowRoot.querySelector('button.action-button'));",
|
||||
[self.marionette.find_element(*self._modify_event_header_locator)])
|
||||
|
||||
def a11y_click_save_event(self):
|
||||
event_start_time = self.marionette.find_element(*self._event_start_time_value_locator).text
|
||||
event_start_date = self.marionette.find_element(*self._event_start_date_value_locator).text
|
||||
el = self.marionette.find_element(*self._modify_event_view_locator)
|
||||
self.accessibility.click(self.marionette.find_element(*self._save_event_button_locator))
|
||||
Wait(self.marionette).until(expected.element_not_displayed(el))
|
||||
return datetime.strptime(event_start_time + event_start_date, '%I:%M %p%m/%d/%Y')
|
||||
|
||||
def tap_save_event(self):
|
||||
date_str = self.marionette.find_element(*self._event_start_date_value_locator).get_attribute('data-date')
|
||||
el = self.marionette.find_element(*self._modify_event_view_locator)
|
||||
self.marionette.find_element(*self._save_event_button_locator).tap()
|
||||
Wait(self.marionette).until(expected.element_not_displayed(el))
|
||||
|
||||
date_list = date_str.split()
|
||||
return date_list[1] + ' ' + date_list[2]
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import By
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class EventDetails(Base):
|
||||
|
||||
_event_header_locator = (By.ID, 'show-event-header')
|
||||
_title_locator = (By.CSS_SELECTOR, '.title .content')
|
||||
_location_locator = (By.CSS_SELECTOR, '.location .content')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
return self.marionette.find_element(*self._title_locator).text
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
return self.marionette.find_element(*self._location_locator).text
|
||||
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/camera/__init__.py
Executable file
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/camera/__init__.py
Executable file
240
gaia/tests/python/gaia-ui-tests/gaiatest/apps/camera/app.py
Executable file
240
gaia/tests/python/gaia-ui-tests/gaiatest/apps/camera/app.py
Executable file
|
|
@ -0,0 +1,240 @@
|
|||
# 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.marionette import Actions
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class Camera(Base):
|
||||
|
||||
name = 'Camera'
|
||||
|
||||
_secure_camera_frame_locator = (By.CSS_SELECTOR, ".secureAppWindow.active[data-manifest-name='Camera'] iframe")
|
||||
|
||||
# Controls View
|
||||
_controls_locator = (By.CSS_SELECTOR, '.controls')
|
||||
_switch_button_locator = (By.CSS_SELECTOR, '.test-switch')
|
||||
_camera_switch_locator = (By.CSS_SELECTOR, ".mode-switch_bg-icon[data-icon='camera']")
|
||||
_video_switch_locator = (By.CSS_SELECTOR, ".mode-switch_bg-icon[data-icon='video']")
|
||||
_capture_button_locator = (By.CSS_SELECTOR, '.test-capture')
|
||||
_gallery_button_locator = (By.CSS_SELECTOR, '.test-gallery')
|
||||
_thumbnail_button_locator = (By.CSS_SELECTOR, 'img.test-thumbnail')
|
||||
|
||||
_video_timer_locator = (By.CSS_SELECTOR, '.recording-timer')
|
||||
|
||||
# HUD View
|
||||
_hud_locator = (By.CSS_SELECTOR, '.hud')
|
||||
_loading_screen_locator = (By.CSS_SELECTOR, '.loading-screen')
|
||||
_toggle_flash_button_locator = (By.CSS_SELECTOR, '.test-flash-button')
|
||||
|
||||
# ConfirmDialog
|
||||
_select_button_locator = (By.CSS_SELECTOR, '.test-confirm-select')
|
||||
|
||||
def launch(self):
|
||||
Base.launch(self)
|
||||
self.wait_for_capture_ready()
|
||||
Wait(self.marionette).until(
|
||||
expected.element_not_displayed(*self._loading_screen_locator))
|
||||
|
||||
@property
|
||||
def camera_mode(self):
|
||||
return self.marionette.find_element(*self._controls_locator).get_attribute('data-mode')
|
||||
|
||||
def take_photo(self):
|
||||
self.wait_for_capture_ready()
|
||||
|
||||
self.tap_capture()
|
||||
|
||||
# Wait for thumbnail to appear
|
||||
self.wait_for_thumbnail_visible()
|
||||
Wait(self.marionette).until(
|
||||
expected.element_not_displayed(*self._loading_screen_locator))
|
||||
|
||||
def record_video(self, duration):
|
||||
# Start recording
|
||||
self.tap_capture()
|
||||
|
||||
# Wait for Controls View state to indicate that recording is in-progress
|
||||
self.wait_for_video_capturing()
|
||||
|
||||
# Wait for duration
|
||||
timeout = duration + 10
|
||||
timer_text = "00:%02d" % duration
|
||||
timer = self.marionette.find_element(*self._video_timer_locator)
|
||||
Wait(self.marionette, timeout).until(lambda m: timer.text >= timer_text)
|
||||
|
||||
# Stop recording
|
||||
self.tap_capture()
|
||||
|
||||
# Wait for thumbnail to appear
|
||||
self.wait_for_thumbnail_visible()
|
||||
|
||||
def tap_capture(self):
|
||||
capture_button = self.marionette.find_element(*self._capture_button_locator)
|
||||
Wait(self.marionette).until(expected.element_enabled(capture_button))
|
||||
capture_button.tap()
|
||||
|
||||
def tap_select_button(self):
|
||||
select = self.marionette.find_element(*self._select_button_locator)
|
||||
Wait(self.marionette).until(expected.element_enabled(select))
|
||||
self.tap_element_from_system_app(select)
|
||||
|
||||
# Fall back to app beneath the picker
|
||||
self.wait_to_not_be_displayed()
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def tap_switch_source(self):
|
||||
switch = self.marionette.find_element(*self._switch_button_locator)
|
||||
Wait(self.marionette).until(expected.element_displayed(switch))
|
||||
|
||||
camera = switch.find_element(*self._camera_switch_locator)
|
||||
video = switch.find_element(*self._video_switch_locator)
|
||||
|
||||
current_camera_mode = self.camera_mode
|
||||
# TODO: Use marionette.tap(_switch_button_locator) to switch camera mode
|
||||
Actions(self.marionette).press(camera).move(video).release().perform()
|
||||
|
||||
controls = self.marionette.find_element(*self._controls_locator)
|
||||
Wait(self.marionette).until(lambda m: controls.get_attribute('data-enabled') == 'true')
|
||||
|
||||
Wait(self.marionette).until(lambda m: not current_camera_mode == self.camera_mode)
|
||||
self.wait_for_capture_ready()
|
||||
|
||||
def tap_toggle_flash_button(self):
|
||||
initial_flash_mode = self.current_flash_mode
|
||||
toggle = self.marionette.find_element(*self._toggle_flash_button_locator)
|
||||
Wait(self.marionette).until(expected.element_enabled(toggle))
|
||||
toggle.tap()
|
||||
Wait(self.marionette).until(lambda m: self.current_flash_mode != initial_flash_mode)
|
||||
|
||||
def wait_for_capture_ready(self):
|
||||
controls = self.marionette.find_element(*self._controls_locator)
|
||||
Wait(self.marionette).until(lambda m: controls.get_attribute('data-enabled') == 'true')
|
||||
Wait(self.marionette).until(lambda m: controls.is_enabled())
|
||||
|
||||
def wait_for_video_capturing(self):
|
||||
controls = self.marionette.find_element(*self._controls_locator)
|
||||
Wait(self.marionette).until(lambda m: controls.get_attribute('data-recording') == 'true')
|
||||
|
||||
def switch_to_secure_camera_frame(self):
|
||||
# Find and switch to secure camera app frame (AppWindowManager hides it)
|
||||
# This is only used when accessing camera in locked phone state
|
||||
self.marionette.switch_to_frame()
|
||||
secure_camera_frame = self.marionette.find_element(*self._secure_camera_frame_locator)
|
||||
self.marionette.switch_to_frame(secure_camera_frame)
|
||||
self.wait_for_capture_ready()
|
||||
|
||||
def tap_switch_to_gallery(self):
|
||||
switch_to_gallery_button = self.marionette.find_element(*self._gallery_button_locator)
|
||||
switch_to_gallery_button.tap()
|
||||
from gaiatest.apps.gallery.app import Gallery
|
||||
gallery_app = Gallery(self.marionette)
|
||||
gallery_app.wait_to_be_displayed()
|
||||
self.apps.switch_to_displayed_app()
|
||||
return gallery_app
|
||||
|
||||
def wait_for_thumbnail_visible(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._thumbnail_button_locator))
|
||||
|
||||
def tap_thumbnail(self):
|
||||
self.marionette.find_element(*self._thumbnail_button_locator).tap()
|
||||
|
||||
@property
|
||||
def is_thumbnail_visible(self):
|
||||
return self.is_element_displayed(*self._thumbnail_button_locator)
|
||||
|
||||
@property
|
||||
def video_timer(self):
|
||||
text = self.marionette.find_element(*self._video_timer_locator).text
|
||||
return time.strptime(text, '%M:%S')
|
||||
|
||||
@property
|
||||
def is_gallery_button_visible(self):
|
||||
return self.is_element_displayed(*self._gallery_button_locator)
|
||||
|
||||
@property
|
||||
def current_flash_mode(self):
|
||||
return self.marionette.find_element(*self._hud_locator).get_attribute('flash-mode')
|
||||
|
||||
@property
|
||||
def current_image_src(self):
|
||||
return self.marionette.find_element(*self._thumbnail_button_locator).get_attribute('src')
|
||||
|
||||
def wait_for_picture_to_change(self, image_src):
|
||||
Wait(self.marionette).until(lambda m: self.current_image_src != image_src)
|
||||
|
||||
|
||||
class ImagePreview(Base):
|
||||
|
||||
_media_frame_locator = (By.ID, 'preview')
|
||||
_image_preview_locator = (By.CSS_SELECTOR, '#media-frame > img')
|
||||
_camera_button_locator = (By.ID, 'camera-button')
|
||||
_video_play_button_locator = (By.CLASS_NAME, 'videoPlayerPlayButton')
|
||||
_video_pause_button_locator = (By.CLASS_NAME, 'videoPlayerPauseButton')
|
||||
_video_progress_bar_locator = (By.CLASS_NAME, 'videoPlayerProgress')
|
||||
_options_button_locator = (By.CLASS_NAME, 'preview-option-icon')
|
||||
_delete_button_locator = (By.CSS_SELECTOR, 'button[data-l10n-id="delete"]')
|
||||
_gallery_button_locator = (By.CSS_SELECTOR, 'button[data-l10n-id="open-gallery"]')
|
||||
_confirm_delete_button = (By.ID, 'dialog-yes')
|
||||
_option_menu_locator = (By.CLASS_NAME, 'js-menu')
|
||||
|
||||
# for Gallery app switch
|
||||
_progress_bar_locator = (By.ID, 'progress')
|
||||
_thumbnail_list_view_locator = (By.CSS_SELECTOR, '#thumbnail-views > footer.thumbnails-list')
|
||||
|
||||
@property
|
||||
def is_image_preview_visible(self):
|
||||
return self.is_element_displayed(*self._image_preview_locator)
|
||||
|
||||
@property
|
||||
def is_video_play_button_visible(self):
|
||||
return self.is_element_displayed(*self._video_play_button_locator)
|
||||
|
||||
@property
|
||||
def is_progress_bar_showing(self):
|
||||
return self.is_element_displayed(*self._video_progress_bar_locator)
|
||||
|
||||
def wait_for_media_frame(self):
|
||||
media_frame = self.marionette.find_element(*self._media_frame_locator)
|
||||
screen_height = int(self.marionette.execute_script('return window.screen.height;'))
|
||||
Wait(self.marionette).until(lambda m: (media_frame.location['y'] + media_frame.size['height']) == screen_height)
|
||||
|
||||
def tap_video_player_play_button(self):
|
||||
self.marionette.find_element(*self._video_play_button_locator).tap()
|
||||
Wait(self.marionette).until(lambda m: self.is_progress_bar_showing is True)
|
||||
|
||||
def tap_video_player_pause_button(self):
|
||||
self.marionette.find_element(*self._video_pause_button_locator).tap()
|
||||
Wait(self.marionette).until(lambda m: self.is_progress_bar_showing is False)
|
||||
|
||||
def tap_options(self):
|
||||
self.marionette.find_element(*self._options_button_locator).tap()
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._option_menu_locator))
|
||||
|
||||
def delete_file(self):
|
||||
self.tap_options()
|
||||
self.marionette.find_element(*self._delete_button_locator).tap()
|
||||
element = Wait(self.marionette).until(expected.element_present(*self._confirm_delete_button))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
element.tap()
|
||||
|
||||
def tap_switch_to_gallery(self):
|
||||
self.tap_options()
|
||||
self.marionette.find_element(*self._gallery_button_locator).tap()
|
||||
from gaiatest.apps.gallery.app import Gallery
|
||||
gallery_app = Gallery(self.marionette)
|
||||
gallery_app.wait_to_be_displayed()
|
||||
self.apps.switch_to_displayed_app()
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._thumbnail_list_view_locator))
|
||||
|
||||
return gallery_app
|
||||
|
||||
def tap_camera(self):
|
||||
self.marionette.find_element(*self._camera_button_locator).tap()
|
||||
camera = Camera(self.marionette)
|
||||
return camera
|
||||
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/clock/__init__.py
Executable file
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/clock/__init__.py
Executable file
37
gaia/tests/python/gaia-ui-tests/gaiatest/apps/clock/app.py
Executable file
37
gaia/tests/python/gaia-ui-tests/gaiatest/apps/clock/app.py
Executable file
|
|
@ -0,0 +1,37 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class Clock(Base):
|
||||
name = 'Clock'
|
||||
_visible_clock_locator = (By.CSS_SELECTOR, '#clock-view .visible')
|
||||
_clock_views = {"stopwatch": "stopwatch-tab", "alarm": "alarm-tab", "timer": "timer-tab"}
|
||||
|
||||
def launch(self):
|
||||
Base.launch(self)
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._visible_clock_locator))))
|
||||
|
||||
def switch_view(self, view_name):
|
||||
Wait(self.marionette).until(
|
||||
expected.element_present(*(By.ID, self._clock_views.get(view_name)))).tap()
|
||||
if view_name == 'stopwatch':
|
||||
from gaiatest.apps.clock.regions.stopwatch import StopWatch
|
||||
return StopWatch(self.marionette)
|
||||
elif view_name == 'timer':
|
||||
from gaiatest.apps.clock.regions.timer import Timer
|
||||
return Timer(self.marionette)
|
||||
elif view_name == 'alarm':
|
||||
from gaiatest.apps.clock.regions.alarm import Alarm
|
||||
return Alarm(self.marionette)
|
||||
else:
|
||||
raise AttributeError('{} is not a view that you can switch to'.format(view_name))
|
||||
|
||||
|
||||
|
||||
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/clock/regions/__init__.py
Executable file
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/clock/regions/__init__.py
Executable file
82
gaia/tests/python/gaia-ui-tests/gaiatest/apps/clock/regions/alarm.py
Executable file
82
gaia/tests/python/gaia-ui-tests/gaiatest/apps/clock/regions/alarm.py
Executable file
|
|
@ -0,0 +1,82 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import PageRegion
|
||||
|
||||
|
||||
class Alarm(PageRegion):
|
||||
_alarm_create_new_locator = (By.ID, 'alarm-new')
|
||||
_alarm_view_locator = (By.ID, 'alarm-tab')
|
||||
_edit_alarm_view_locator = (By.ID, 'edit-alarm')
|
||||
_all_alarm_items_locator = (By.CSS_SELECTOR, '#alarms li')
|
||||
_banner_countdown_notification_locator = (By.ID, 'banner-countdown')
|
||||
_visible_clock_locator = (By.CSS_SELECTOR, '#clock-view .visible')
|
||||
|
||||
def __init__(self, marionette):
|
||||
PageRegion.__init__(self, marionette,self._alarm_view_locator)
|
||||
view = self.marionette.find_element(*self._alarm_view_locator)
|
||||
Wait(self.marionette).until(lambda m: view.location['x'] == 0 and view.is_displayed())
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._alarm_create_new_locator))))
|
||||
|
||||
@property
|
||||
def alarm_items(self):
|
||||
return [self.AlarmItem(self.marionette, alarm_item) for alarm_item in
|
||||
self.marionette.find_elements(*self._all_alarm_items_locator)]
|
||||
|
||||
def tap_new_alarm(self):
|
||||
new_alarm = Wait(self.marionette).until(
|
||||
expected.element_present(*self._alarm_create_new_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(new_alarm))
|
||||
new_alarm.tap()
|
||||
from gaiatest.apps.clock.regions.new_alarm import NewAlarm
|
||||
return NewAlarm(self.marionette)
|
||||
|
||||
@property
|
||||
def banner_notification(self):
|
||||
banner = Wait(self.marionette).until(
|
||||
expected.element_present(*self._banner_countdown_notification_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(banner))
|
||||
return banner.text
|
||||
|
||||
def dismiss_banner(self):
|
||||
banner = Wait(self.marionette).until(
|
||||
expected.element_present(*self._banner_countdown_notification_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(banner))
|
||||
# We can't tap to clear the banner as sometimes it taps the underlying alarm changing the UI
|
||||
Wait(self.marionette).until(expected.element_not_displayed(banner))
|
||||
|
||||
class AlarmItem(PageRegion):
|
||||
|
||||
_label_locator = (By.CSS_SELECTOR, '.label')
|
||||
_check_box_locator = (By.CSS_SELECTOR, '.input-enable')
|
||||
_enable_button_locator = (By.CSS_SELECTOR, '.alarmList.alarmEnable')
|
||||
_time_locator = (By.CSS_SELECTOR, '.time')
|
||||
|
||||
@property
|
||||
def time(self):
|
||||
return self.root_element.find_element(*self._time_locator).text
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
return self.root_element.find_element(*self._label_locator).text
|
||||
|
||||
@property
|
||||
def is_alarm_active(self):
|
||||
return self.root_element.find_element(*self._check_box_locator).is_selected()
|
||||
|
||||
def tap_checkbox(self):
|
||||
self.root_element.find_element(*self._enable_button_locator).tap()
|
||||
|
||||
def wait_for_checkbox_to_change_state(self, value):
|
||||
checkbox = self.marionette.find_element(*self._check_box_locator)
|
||||
Wait(self.marionette).until(lambda m: checkbox.is_selected() == value)
|
||||
|
||||
def tap(self):
|
||||
self.root_element.tap()
|
||||
from gaiatest.apps.clock.regions.new_alarm import EditAlarm
|
||||
return EditAlarm(self.marionette)
|
||||
32
gaia/tests/python/gaia-ui-tests/gaiatest/apps/clock/regions/alarm_alert.py
Executable file
32
gaia/tests/python/gaia-ui-tests/gaiatest/apps/clock/regions/alarm_alert.py
Executable file
|
|
@ -0,0 +1,32 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class AlarmAlertScreen(Base):
|
||||
_alarm_frame_locator = (By.CSS_SELECTOR, 'iframe[mozapp*="clock"]:nth-child(1)')
|
||||
_stop_button_locator = (By.ID, 'ring-button-stop')
|
||||
_alarm_label_locator = (By.ID, 'ring-label')
|
||||
|
||||
def wait_for_alarm_to_trigger(self):
|
||||
alarm_frame = Wait(self.marionette, timeout=60, interval=5).until(
|
||||
expected.element_present(*self._alarm_frame_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(alarm_frame))
|
||||
self.marionette.switch_to_frame(alarm_frame)
|
||||
|
||||
def tap_stop_alarm(self):
|
||||
stop_alarm_button = Wait(self.marionette).until(
|
||||
expected.element_present(*self._stop_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(stop_alarm_button))
|
||||
self.tap_element_from_system_app(stop_alarm_button)
|
||||
|
||||
@property
|
||||
def alarm_label(self):
|
||||
alarm_label = Wait(self.marionette).until(
|
||||
expected.element_present(*self._alarm_label_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(alarm_label))
|
||||
return alarm_label.text
|
||||
77
gaia/tests/python/gaia-ui-tests/gaiatest/apps/clock/regions/new_alarm.py
Executable file
77
gaia/tests/python/gaia-ui-tests/gaiatest/apps/clock/regions/new_alarm.py
Executable file
|
|
@ -0,0 +1,77 @@
|
|||
# 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 gaiatest.apps.clock.app import Clock
|
||||
|
||||
|
||||
class NewAlarm(Clock):
|
||||
|
||||
_alarm_name_locator = (By.ID, 'alarm-name')
|
||||
_new_alarm_view_locator = (By.CSS_SELECTOR, 'section[data-panel-id="alarm_edit"]')
|
||||
_repeat_menu_locator = (By.ID, 'repeat-menu')
|
||||
_sound_menu_locator = (By.ID, 'sound-menu')
|
||||
_snooze_menu_locator = (By.ID, 'snooze-menu')
|
||||
_done_locator = (By.ID, 'alarm-done')
|
||||
_time_button_locator = (By.XPATH, "//li[input[@id='time-select']]")
|
||||
|
||||
def __init__(self, marionette):
|
||||
Clock.__init__(self, marionette)
|
||||
view = self.marionette.find_element(*self._new_alarm_view_locator)
|
||||
Wait(self.marionette).until(lambda m: view.location['x'] == 0 and view.is_displayed())
|
||||
# Bug 1032852 This is to bust intermittents caused by this bug that causes keyboard not to appear upon tap
|
||||
time.sleep(1.5)
|
||||
|
||||
def type_alarm_label(self, value):
|
||||
self.marionette.find_element(*self._alarm_name_locator).tap()
|
||||
self.keyboard.send(value)
|
||||
self.keyboard.dismiss()
|
||||
|
||||
@property
|
||||
def alarm_label_placeholder(self):
|
||||
return self.marionette.find_element(*self._alarm_name_locator).get_attribute('placeholder')
|
||||
|
||||
@property
|
||||
def alarm_repeat(self):
|
||||
repeat = self.marionette.find_element(*self._repeat_menu_locator).get_attribute('data-l10n-id')
|
||||
return repeat if repeat is not None else self.marionette.find_element(*self._repeat_menu_locator).text
|
||||
|
||||
def select_repeat(self, value):
|
||||
self.marionette.find_element(*self._repeat_menu_locator).tap()
|
||||
self.select(value)
|
||||
|
||||
@property
|
||||
def alarm_snooze(self):
|
||||
return self.marionette.find_element(*self._snooze_menu_locator).get_attribute('data-l10n-args')
|
||||
|
||||
def select_snooze(self, value):
|
||||
self.marionette.find_element(*self._snooze_menu_locator).tap()
|
||||
self.select(value)
|
||||
|
||||
@property
|
||||
def alarm_sound(self):
|
||||
return self.marionette.find_element(*self._sound_menu_locator).get_attribute('data-l10n-id')
|
||||
|
||||
def select_sound(self, value):
|
||||
self.marionette.find_element(*self._sound_menu_locator).tap()
|
||||
self.select(value)
|
||||
|
||||
def tap_done(self):
|
||||
done = Wait(self.marionette).until(expected.element_present(*self._done_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(done))
|
||||
done.tap()
|
||||
from gaiatest.apps.clock.regions.alarm import Alarm
|
||||
return Alarm(self.marionette)
|
||||
|
||||
def tap_time(self):
|
||||
self.marionette.find_element(*self._time_button_locator).tap()
|
||||
from gaiatest.apps.system.regions.time_picker import TimePicker
|
||||
return TimePicker(self.marionette)
|
||||
|
||||
|
||||
class EditAlarm(NewAlarm):
|
||||
pass
|
||||
58
gaia/tests/python/gaia-ui-tests/gaiatest/apps/clock/regions/stopwatch.py
Executable file
58
gaia/tests/python/gaia-ui-tests/gaiatest/apps/clock/regions/stopwatch.py
Executable file
|
|
@ -0,0 +1,58 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
from gaiatest.apps.base import PageRegion
|
||||
|
||||
class StopWatch(PageRegion):
|
||||
_stopwatch_view_locator = (By.ID,'stopwatch-panel')
|
||||
_stopwatch_time_locator = (By.CSS_SELECTOR, ".stopwatch-time")
|
||||
_stopwatch_start_locator = (By.CSS_SELECTOR, '#stopwatch-controls .stopwatch-start')
|
||||
_stopwatch_pause_locator = (By.CSS_SELECTOR, '#stopwatch-controls .stopwatch-pause')
|
||||
_stopwatch_reset_locator = (By.CSS_SELECTOR, '#stopwatch-controls .stopwatch-reset')
|
||||
_stopwatch_resume_locator = (By.CSS_SELECTOR, '#stopwatch-controls .stopwatch-resume')
|
||||
_stopwatch_lap_locator = (By.CSS_SELECTOR, '#stopwatch-controls .stopwatch-lap')
|
||||
_all_laps_locator = (By.CSS_SELECTOR, '.stopwatch-laps li')
|
||||
|
||||
def __init__(self, marionette):
|
||||
PageRegion.__init__(self, marionette, self._stopwatch_view_locator)
|
||||
view = self.marionette.find_element(*self._stopwatch_view_locator)
|
||||
Wait(self.marionette).until(lambda m: view.location['x'] == 0 and view.is_displayed())
|
||||
|
||||
@property
|
||||
def current_time(self):
|
||||
current_time = Wait(self.marionette).until(expected.element_present(*self._stopwatch_time_locator))
|
||||
return current_time.text
|
||||
|
||||
@property
|
||||
def lap_items(self):
|
||||
return [self.LapItem(self.marionette, lap) for lap in self.marionette.find_elements(*self._all_laps_locator)]
|
||||
|
||||
def tap_start(self):
|
||||
Wait(self.marionette).until(expected.element_present(*self._stopwatch_start_locator)).tap()
|
||||
|
||||
def tap_pause(self):
|
||||
Wait(self.marionette).until(expected.element_present(*self._stopwatch_pause_locator)).tap()
|
||||
|
||||
def tap_reset(self):
|
||||
Wait(self.marionette).until(expected.element_present(*self._stopwatch_reset_locator)).tap()
|
||||
|
||||
def tap_resume(self):
|
||||
Wait(self.marionette).until(expected.element_present(*self._stopwatch_resume_locator)).tap()
|
||||
|
||||
def tap_lap(self):
|
||||
Wait(self.marionette).until(expected.element_present(*self._stopwatch_lap_locator)).tap()
|
||||
|
||||
class LapItem(PageRegion):
|
||||
_lap_name = (By.CSS_SELECTOR, '.lap-name')
|
||||
_lap_time = (By.CSS_SELECTOR, '.lap-duration')
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.root_element.find_element(*self._lap_name).text
|
||||
|
||||
@property
|
||||
def time(self):
|
||||
return self.root_element.find_element(*self._lap_time).text
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
# 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/.
|
||||
|
||||
|
||||
16
gaia/tests/python/gaia-ui-tests/gaiatest/apps/clock/regions/timer.py
Executable file
16
gaia/tests/python/gaia-ui-tests/gaiatest/apps/clock/regions/timer.py
Executable file
|
|
@ -0,0 +1,16 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import By, Wait
|
||||
|
||||
from gaiatest.apps.base import PageRegion
|
||||
|
||||
|
||||
class Timer(PageRegion):
|
||||
_timer_view_locator = (By.ID, 'timer-panel')
|
||||
|
||||
def __init__(self, marionette):
|
||||
PageRegion.__init__(self, marionette, self._timer_view_locator)
|
||||
view = self.marionette.find_element(*self._timer_view_locator)
|
||||
Wait(self.marionette).until(lambda m: view.location['x'] == 0 and view.is_displayed())
|
||||
3
gaia/tests/python/gaia-ui-tests/gaiatest/apps/contacts/__init__.py
Executable file
3
gaia/tests/python/gaia-ui-tests/gaiatest/apps/contacts/__init__.py
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
# 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/.
|
||||
191
gaia/tests/python/gaia-ui-tests/gaiatest/apps/contacts/app.py
Executable file
191
gaia/tests/python/gaia-ui-tests/gaiatest/apps/contacts/app.py
Executable file
|
|
@ -0,0 +1,191 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
from marionette_driver.errors import JavascriptException
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.base import PageRegion
|
||||
|
||||
|
||||
class Contacts(Base):
|
||||
|
||||
name = "Contacts"
|
||||
entry_point = "contacts"
|
||||
manifest_url = '{}communications{}/manifest.webapp'.format(Base.DEFAULT_PROTOCOL,Base.DEFAULT_APP_HOSTNAME)
|
||||
|
||||
_new_contact_button_locator = (By.ID, 'add-contact-button')
|
||||
_settings_button_locator = (By.ID, 'settings-button')
|
||||
_favorites_list_locator = (By.ID, 'contacts-list-favorites')
|
||||
_select_all_wrapper_locator = (By.ID, 'select-all-wrapper')
|
||||
_select_all_button_locator = (By.CSS_SELECTOR, 'button[data-l10n-id="selectAll"]')
|
||||
_select_action_button_locator = (By.ID, 'select-action')
|
||||
_status_message_locator = (By.ID, 'statusMsg')
|
||||
_confirm_delete_locator = (By.CSS_SELECTOR, 'button.danger[data-l10n-id="delete"]')
|
||||
_no_contacts_message_locator = (By.CSS_SELECTOR, '*[data-l10n-id="no-contacts"]')
|
||||
_group_container_selector = "#groups-container"
|
||||
_contact_locator = (By.CSS_SELECTOR, 'li[data-uuid]:not([data-group="ice"])')
|
||||
_ice_contact = (By.CSS_SELECTOR, 'ol#ice-group')
|
||||
_ice_list_icon_locator = (By.ID, 'contact-list-ice')
|
||||
_select_ice_contact_1_locator = (By.ID, 'select-ice-contact-1')
|
||||
|
||||
def launch(self):
|
||||
Base.launch(self)
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._settings_button_locator))))
|
||||
|
||||
# Workaround for bug 1201211
|
||||
import time
|
||||
time.sleep(1)
|
||||
|
||||
def switch_to_contacts_frame(self):
|
||||
self.wait_to_be_displayed()
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
@property
|
||||
def contacts(self):
|
||||
return [self.Contact(marionette=self.marionette, element=contact)
|
||||
for contact in self.marionette.find_elements(*self._contact_locator)]
|
||||
|
||||
def wait_for_contacts(self, number_to_wait_for=1):
|
||||
Wait(self.marionette).until(lambda m: len(m.find_elements(
|
||||
*self._contact_locator)) == number_to_wait_for)
|
||||
|
||||
# we need to scroll in order to force the rendering of all the contacts
|
||||
height = self.marionette.execute_script("return document.querySelector('[data-uuid]').clientHeight;")
|
||||
for idx in range(number_to_wait_for):
|
||||
self.marionette.execute_script("document.querySelector('{0}').scrollTop = {1}".
|
||||
format(self._group_container_selector, idx * height))
|
||||
|
||||
def contact(self, name):
|
||||
for contact in self.contacts:
|
||||
if contact.name == name:
|
||||
return contact
|
||||
|
||||
def tap_new_contact(self):
|
||||
self.marionette.find_element(*self._new_contact_button_locator).tap()
|
||||
from gaiatest.apps.contacts.regions.contact_form import NewContact
|
||||
new_contact = NewContact(self.marionette)
|
||||
new_contact.wait_for_new_contact_form_to_load()
|
||||
return new_contact
|
||||
|
||||
def a11y_click_new_contact(self):
|
||||
self.accessibility.click(self.marionette.find_element(*self._new_contact_button_locator))
|
||||
from gaiatest.apps.contacts.regions.contact_form import NewContact
|
||||
new_contact = NewContact(self.marionette)
|
||||
new_contact.wait_for_new_contact_form_to_load()
|
||||
return new_contact
|
||||
|
||||
def tap_settings(self):
|
||||
settings = self.marionette.find_element(*self._settings_button_locator)
|
||||
Wait(self.marionette).until(expected.element_displayed(settings))
|
||||
settings.tap()
|
||||
Wait(self.marionette).until(expected.element_not_displayed(settings))
|
||||
from gaiatest.apps.contacts.regions.settings_form import SettingsForm
|
||||
return SettingsForm(self.marionette)
|
||||
|
||||
def tap_select_all(self):
|
||||
window_height = self.marionette.execute_script('return window.wrappedJSObject.innerHeight')
|
||||
wrapper = self.marionette.find_element(*self._select_all_wrapper_locator)
|
||||
Wait(self.marionette).until(lambda m: int(wrapper.size['height'] + wrapper.location['y']) == window_height)
|
||||
|
||||
self.marionette.find_element(*self._select_all_button_locator).tap()
|
||||
|
||||
def tap_export(self):
|
||||
self._tap_action_button()
|
||||
|
||||
def tap_delete(self):
|
||||
self._tap_action_button()
|
||||
|
||||
def _tap_action_button(self):
|
||||
# The same button is used to do bulk operations (like delete or export). The displayed string changes though.
|
||||
# Hence, let's define more semantically explicit functions.
|
||||
self.marionette.find_element(*self._select_action_button_locator).tap()
|
||||
|
||||
def tap_confirm_delete(self):
|
||||
delete_button = Wait(self.marionette).until(expected.element_present(*self._confirm_delete_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(delete_button))
|
||||
delete_button.tap()
|
||||
|
||||
@property
|
||||
def is_favorites_list_displayed(self):
|
||||
return self.marionette.find_element(*self._favorites_list_locator).is_displayed()
|
||||
|
||||
@property
|
||||
def is_ice_list_icon_displayed(self):
|
||||
return self.marionette.find_element(*self._ice_list_icon_locator).is_displayed()
|
||||
|
||||
def open_ice_contact_list(self):
|
||||
ice_list = Wait(self.marionette).until(expected.element_present(*self._ice_list_icon_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(ice_list))
|
||||
ice_list.tap()
|
||||
return Contacts(self.marionette)
|
||||
|
||||
def wait_for_ice_contact_shown(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._ice_contact))
|
||||
|
||||
@property
|
||||
def status_message(self):
|
||||
status = Wait(self.marionette).until(expected.element_present(
|
||||
*self._status_message_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(status))
|
||||
return status.text
|
||||
|
||||
@property
|
||||
def is_no_contacts_message_displayed(self):
|
||||
return self.marionette.find_element(*self._no_contacts_message_locator).is_displayed()
|
||||
|
||||
class Contact(PageRegion):
|
||||
|
||||
_name_locator = (By.CSS_SELECTOR, 'bdi > strong')
|
||||
_full_name_locator = (By.CSS_SELECTOR, 'p.contact-text bdi')
|
||||
_image_locator = (By.CSS_SELECTOR, 'span[data-type="img"]')
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.root_element.find_element(*self._name_locator).text
|
||||
|
||||
@property
|
||||
def full_name(self):
|
||||
return self.root_element.find_element(*self._full_name_locator).text
|
||||
|
||||
@property
|
||||
def image_data_group(self):
|
||||
return self.root_element.find_element(*self._image_locator).get_attribute('data-group')
|
||||
|
||||
def tap(self, return_class='ContactDetails'):
|
||||
self.marionette.execute_script('arguments[0].scrollIntoView(false);', [self.root_element])
|
||||
if return_class == None:
|
||||
self.tap_element_from_system_app(
|
||||
self.root_element.find_element(*self._name_locator), add_statusbar_height=True)
|
||||
else:
|
||||
self.root_element.find_element(*self._name_locator).tap()
|
||||
|
||||
return self._return_class_from_tap(return_class)
|
||||
|
||||
def a11y_click(self, return_class='ContactDetails'):
|
||||
self.accessibility.click(self.root_element)
|
||||
return self._return_class_from_tap(return_class)
|
||||
|
||||
def _return_class_from_tap(self, return_class='ContactDetails'):
|
||||
if return_class == 'ContactDetails':
|
||||
Wait(self.marionette).until(lambda m: expected.element_not_displayed(self.root_element))
|
||||
from gaiatest.apps.contacts.regions.contact_details import ContactDetails
|
||||
return ContactDetails(self.marionette)
|
||||
elif return_class == 'EditContact':
|
||||
# This may seem superfluous but we can enter EditContact from Contacts, or from ActivityPicker
|
||||
Contacts(self.marionette).wait_to_be_displayed()
|
||||
self.apps.switch_to_displayed_app()
|
||||
from gaiatest.apps.contacts.regions.contact_form import EditContact
|
||||
return EditContact(self.marionette)
|
||||
elif return_class == 'SelectContact':
|
||||
return None
|
||||
elif return_class == 'SetIceContacts':
|
||||
from gaiatest.apps.contacts.regions.set_ice_contacts import SetIceContacts
|
||||
return SetIceContacts(self.marionette)
|
||||
else:
|
||||
# We are using contacts picker in activity - after choosing, fall back to open app
|
||||
Contacts(self.marionette).wait_to_not_be_displayed()
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# 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/.
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.form_controls.header import GaiaHeader
|
||||
|
||||
|
||||
class ContactDetails(Base):
|
||||
|
||||
_contact_name_title_locator = (By.ID, 'contact-name-title')
|
||||
_contact_image_locator = (By.ID, 'cover-img')
|
||||
_call_phone_number_button_locator = (By.ID, 'call-or-pick-0')
|
||||
_phone_numbers_locator = (By.CSS_SELECTOR, '#contact-detail-inner .icon-call')
|
||||
_send_sms_button_locator = (By.ID, 'send-sms-button-0')
|
||||
_edit_contact_button_locator = (By.ID, 'edit-contact-button')
|
||||
_details_header_locator = (By.ID, 'details-view-header')
|
||||
_add_remove_favorite_button_locator = (By.ID, 'toggle-favorite')
|
||||
_comments_locator = (By.ID, 'note-details-template-0')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
el = self.marionette.find_element(*self._details_header_locator)
|
||||
Wait(self.marionette).until(lambda m: el.location['x'] == 0 and el.is_displayed())
|
||||
|
||||
@property
|
||||
def full_name(self):
|
||||
return self.marionette.find_element(*self._contact_name_title_locator).text
|
||||
|
||||
@property
|
||||
def phone_number(self):
|
||||
return self.marionette.find_element(*self._call_phone_number_button_locator).text
|
||||
|
||||
@property
|
||||
def phone_numbers(self):
|
||||
return [element.text for element in self.marionette.find_elements(*self._phone_numbers_locator)]
|
||||
|
||||
@property
|
||||
def comments(self):
|
||||
return self.marionette.find_element(*self._comments_locator).text
|
||||
|
||||
@property
|
||||
def image_style(self):
|
||||
return self.marionette.find_element(*self._contact_image_locator).get_attribute('style')
|
||||
|
||||
def tap_phone_number(self):
|
||||
call = self.marionette.find_element(*self._call_phone_number_button_locator)
|
||||
Wait(self.marionette).until(expected.element_enabled(call))
|
||||
call.tap()
|
||||
from gaiatest.apps.phone.regions.call_screen import CallScreen
|
||||
return CallScreen(self.marionette)
|
||||
|
||||
def tap_send_sms(self):
|
||||
self.marionette.find_element(*self._send_sms_button_locator).tap()
|
||||
from gaiatest.apps.messages.regions.new_message import NewMessage
|
||||
return NewMessage(self.marionette)
|
||||
|
||||
def tap_edit(self):
|
||||
edit = Wait(self.marionette).until(expected.element_present(
|
||||
*self._edit_contact_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(edit))
|
||||
edit.tap()
|
||||
from gaiatest.apps.contacts.regions.contact_form import EditContact
|
||||
return EditContact(self.marionette)
|
||||
|
||||
def a11y_click_edit(self):
|
||||
edit = Wait(self.marionette).until(expected.element_present(
|
||||
*self._edit_contact_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(edit))
|
||||
self.accessibility.click(edit)
|
||||
from gaiatest.apps.contacts.regions.contact_form import EditContact
|
||||
return EditContact(self.marionette)
|
||||
|
||||
def tap_back(self):
|
||||
GaiaHeader(self.marionette, self._details_header_locator).go_back()
|
||||
|
||||
def tap_add_remove_favorite(self):
|
||||
button = self.marionette.find_element(*self._add_remove_favorite_button_locator)
|
||||
# Capture the current state of the element
|
||||
initial_state = button.get_attribute('data-l10n-id')
|
||||
self.marionette.execute_script("arguments[0].scrollIntoView(false);", [button])
|
||||
button.tap()
|
||||
# Wait for it to have toggled
|
||||
Wait(self.marionette).until(lambda m: button.get_attribute('data-l10n-id') != initial_state)
|
||||
|
||||
@property
|
||||
def add_remove_text(self):
|
||||
return self.marionette.find_element(*self._add_remove_favorite_button_locator).text
|
||||
227
gaia/tests/python/gaia-ui-tests/gaiatest/apps/contacts/regions/contact_form.py
Executable file
227
gaia/tests/python/gaia-ui-tests/gaiatest/apps/contacts/regions/contact_form.py
Executable file
|
|
@ -0,0 +1,227 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class ContactForm(Base):
|
||||
|
||||
name = 'Contacts'
|
||||
|
||||
_given_name_locator = (By.ID, 'givenName')
|
||||
_family_name_locator = (By.ID, 'familyName')
|
||||
_phone_locator = (By.ID, 'number_0')
|
||||
_email_locator = (By.ID, 'email_0')
|
||||
_street_locator = (By.ID, 'streetAddress_0')
|
||||
_zip_code_locator = (By.ID, 'postalCode_0')
|
||||
_city_locator = (By.ID, 'locality_0')
|
||||
_country_locator = (By.ID, 'countryName_0')
|
||||
_comment_locator = (By.ID, 'note_0')
|
||||
_add_new_email_locator = (By.ID, 'add-new-email')
|
||||
_add_new_address_locator = (By.ID, 'add-new-address')
|
||||
_add_new_note_locator = (By.ID, 'add-new-note')
|
||||
_add_new_phone_locator = (By.ID, 'add-new-phone')
|
||||
|
||||
_thumbnail_photo_locator = (By.ID, 'thumbnail-photo')
|
||||
|
||||
@property
|
||||
def given_name(self):
|
||||
return self.marionette.find_element(*self._given_name_locator).text
|
||||
|
||||
def type_given_name(self, value):
|
||||
element = self.marionette.find_element(*self._given_name_locator)
|
||||
element.clear()
|
||||
element.send_keys(value)
|
||||
|
||||
@property
|
||||
def family_name(self):
|
||||
return self.marionette.find_element(*self._family_name_locator).text
|
||||
|
||||
def type_family_name(self, value):
|
||||
element = self.marionette.find_element(*self._family_name_locator)
|
||||
element.clear()
|
||||
element.send_keys(value)
|
||||
|
||||
@property
|
||||
def phone(self):
|
||||
return self.marionette.find_element(*self._phone_locator).text
|
||||
|
||||
def _type_in_field(self, add_locator, field_locator, value):
|
||||
Wait(self.marionette).until(expected.element_present(*add_locator)).tap()
|
||||
element = Wait(self.marionette).until(expected.element_present(*field_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
element.clear()
|
||||
element.send_keys(value)
|
||||
|
||||
def type_phone(self, value):
|
||||
self._type_in_field(self._add_new_phone_locator, self._phone_locator, value)
|
||||
|
||||
@property
|
||||
def email(self):
|
||||
return self.marionette.find_element(*self._email_locator).text
|
||||
|
||||
def type_email(self, value):
|
||||
self._type_in_field(self._add_new_email_locator, self._email_locator, value)
|
||||
|
||||
@property
|
||||
def street(self):
|
||||
return self.marionette.find_element(*self._street_locator).text
|
||||
|
||||
def type_street(self, value):
|
||||
self._type_in_field(self._add_new_address_locator, self._street_locator, value)
|
||||
|
||||
@property
|
||||
def zip_code(self):
|
||||
return self.marionette.find_element(*self._zip_code_locator).text
|
||||
|
||||
def type_zip_code(self, value):
|
||||
element = self.marionette.find_element(*self._zip_code_locator)
|
||||
element.clear()
|
||||
element.send_keys(value)
|
||||
|
||||
@property
|
||||
def city(self):
|
||||
return self.marionette.find_element(*self._city_locator).text
|
||||
|
||||
def type_city(self, value):
|
||||
element = self.marionette.find_element(*self._city_locator)
|
||||
element.clear()
|
||||
element.send_keys(value)
|
||||
|
||||
@property
|
||||
def country(self):
|
||||
return self.marionette.find_element(*self._country_locator).text
|
||||
|
||||
def type_country(self, value):
|
||||
element = self.marionette.find_element(*self._country_locator)
|
||||
element.clear()
|
||||
element.send_keys(value)
|
||||
|
||||
@property
|
||||
def comment(self):
|
||||
return self.marionette.find_element(*self._comment_locator).text
|
||||
|
||||
def type_comment(self, value):
|
||||
if self.is_element_present(*self._comment_locator):
|
||||
element = self.marionette.find_element(*self._comment_locator)
|
||||
element.clear()
|
||||
element.send_keys(value)
|
||||
else:
|
||||
self._type_in_field(self._add_new_note_locator, self._comment_locator, value)
|
||||
|
||||
|
||||
def tap_comment(self):
|
||||
self.marionette.find_element(*self._comment_locator).tap()
|
||||
|
||||
@property
|
||||
def picture_style(self):
|
||||
return self.marionette.find_element(*self._thumbnail_photo_locator).get_attribute('style')
|
||||
|
||||
def tap_picture(self):
|
||||
self.marionette.find_element(*self._thumbnail_photo_locator).tap()
|
||||
from gaiatest.apps.system.regions.activities import Activities
|
||||
return Activities(self.marionette)
|
||||
|
||||
def wait_for_image_to_load(self):
|
||||
el = self.marionette.find_element(*self._thumbnail_photo_locator)
|
||||
Wait(self.marionette).until(lambda m: 'background-image' in el.get_attribute('style'))
|
||||
|
||||
|
||||
class EditContact(ContactForm):
|
||||
|
||||
_update_locator = (By.ID, 'save-button')
|
||||
_cancel_locator = (By.ID, 'cancel-edit')
|
||||
_delete_locator = (By.ID, 'delete-contact')
|
||||
_delete_form_locator = (By.ID, 'confirmation-message')
|
||||
_cancel_delete_locator = (By.CSS_SELECTOR, 'form#confirmation-message button:not(.danger)')
|
||||
_confirm_delete_locator = (By.CSS_SELECTOR, 'form#confirmation-message button.danger')
|
||||
|
||||
def __init__(self, marionette):
|
||||
ContactForm.__init__(self, marionette)
|
||||
update = Wait(self.marionette).until(expected.element_present(*self._update_locator))
|
||||
Wait(self.marionette).until(lambda m: update.location['y'] == 0 and update.is_displayed())
|
||||
|
||||
def tap_update(self, return_class='ContactDetails'):
|
||||
self.wait_for_update_button_enabled()
|
||||
update = self.marionette.find_element(*self._update_locator)
|
||||
update.tap()
|
||||
if return_class == 'ContactDetails':
|
||||
from gaiatest.apps.contacts.regions.contact_details import ContactDetails
|
||||
return ContactDetails(self.marionette)
|
||||
elif return_class == 'Merge':
|
||||
from gaiatest.apps.contacts.regions.merge import Merge
|
||||
return Merge(self.marionette)
|
||||
else:
|
||||
# else we drop back to the underlying app
|
||||
from gaiatest.apps.contacts.app import Contacts
|
||||
Contacts(self.marionette).wait_to_not_be_displayed()
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def tap_cancel(self):
|
||||
self.marionette.find_element(*self._cancel_locator).tap()
|
||||
from gaiatest.apps.contacts.regions.contact_details import ContactDetails
|
||||
return ContactDetails(self.marionette)
|
||||
|
||||
def tap_delete(self):
|
||||
delete_item = self.marionette.find_element(*self._delete_locator)
|
||||
self.marionette.execute_script(
|
||||
'arguments[0].scrollIntoView(true);', [delete_item])
|
||||
delete_item.tap()
|
||||
|
||||
def tap_cancel_delete(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._delete_form_locator))
|
||||
self.marionette.find_element(*self._cancel_delete_locator).tap()
|
||||
|
||||
def tap_confirm_delete(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._delete_form_locator))
|
||||
self.marionette.find_element(*self._confirm_delete_locator).tap()
|
||||
|
||||
def wait_for_update_button_enabled(self):
|
||||
update = self.marionette.find_element(*self._update_locator)
|
||||
Wait(self.marionette).until(expected.element_enabled(update))
|
||||
|
||||
|
||||
class NewContact(ContactForm):
|
||||
|
||||
_src = 'app://communications.gaiamobile.org/contacts/views/form/form.html'
|
||||
_done_button_locator = (By.ID, 'save-button')
|
||||
|
||||
def __init__(self, marionette):
|
||||
ContactForm.__init__(self, marionette)
|
||||
|
||||
def switch_to_new_contact_form(self):
|
||||
# When NewContact form is called as an ActivityWindow
|
||||
Wait(self.marionette).until(lambda m: self.apps.displayed_app.src == self._src)
|
||||
self.apps.switch_to_displayed_app()
|
||||
self.wait_for_new_contact_form_to_load()
|
||||
|
||||
def wait_for_new_contact_form_to_load(self):
|
||||
done = self.marionette.find_element(*self._done_button_locator)
|
||||
Wait(self.marionette).until(lambda m: done.location['y'] == 0)
|
||||
|
||||
def tap_done(self, return_contacts=True):
|
||||
element = self.marionette.find_element(*self._done_button_locator)
|
||||
self.tap_element_from_system_app(element, add_statusbar_height=True)
|
||||
|
||||
return self.wait_for_done(return_contacts)
|
||||
|
||||
def a11y_click_done(self, return_contacts=True):
|
||||
element = self.marionette.find_element(*self._done_button_locator)
|
||||
self.accessibility.click(element)
|
||||
Wait(self.marionette).until(expected.element_not_displayed(element))
|
||||
return self.wait_for_done(return_contacts)
|
||||
|
||||
def wait_for_done(self, return_contacts=True):
|
||||
# NewContact can be opened as an Activity from other apps. In this scenario we don't return Contacts
|
||||
if return_contacts:
|
||||
self.apps.switch_to_displayed_app()
|
||||
from gaiatest.apps.contacts.app import Contacts
|
||||
return Contacts(self.marionette)
|
||||
else:
|
||||
from gaiatest.apps.contacts.app import Contacts
|
||||
Contacts(self.marionette).wait_to_not_be_displayed()
|
||||
# Fall back to the underlying app
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
from gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class ContactImportPicker(Base):
|
||||
|
||||
_contact_import_picker_frame_locator = (By.ID, 'iframe_extensions')
|
||||
_import_button_locator = (By.ID, 'import-action')
|
||||
_friends_list_locator = (By.ID, 'friends-list')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
Wait(self.marionette).until(
|
||||
expected.element_displayed(*self._contact_import_picker_frame_locator))
|
||||
select_contacts = self.marionette.find_element(*self._contact_import_picker_frame_locator)
|
||||
self.marionette.switch_to_frame(select_contacts)
|
||||
|
||||
def tap_import_button(self, wait_for_import = True):
|
||||
self.marionette.execute_script('window.wrappedJSObject.importer.ui.importAll();')
|
||||
# TODO uncomment this when Bug 932804 is resolved
|
||||
# self.marionette.find_element(*self._import_button_locator).tap()
|
||||
self.apps.switch_to_displayed_app()
|
||||
if wait_for_import:
|
||||
Wait(self.marionette, timeout=60).until(
|
||||
expected.element_not_displayed(*self._contact_import_picker_frame_locator))
|
||||
from gaiatest.apps.contacts.regions.settings_form import SettingsForm
|
||||
return SettingsForm(self.marionette)
|
||||
|
||||
def tap_first_friend(self):
|
||||
element = self.marionette.find_element(*self._friends_list_locator)
|
||||
# TODO replace this with proper tap when Bug 932804 is resolved
|
||||
self.marionette.execute_script("""
|
||||
window.wrappedJSObject.document.getElementById("friends-list")
|
||||
.getElementsByTagName("a")[1].click()
|
||||
""")
|
||||
Wait(self.marionette).until(expected.element_not_displayed(element))
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def tap_select_all(self):
|
||||
# TODO replace this with proper tap when Bug 932804 is resolved
|
||||
self.marionette.execute_script('window.wrappedJSObject.importer.ui.selectAll();')
|
||||
el = self.marionette.find_element(*self._import_button_locator)
|
||||
Wait(self.marionette).until(expected.element_enabled(el))
|
||||
47
gaia/tests/python/gaia-ui-tests/gaiatest/apps/contacts/regions/gmail.py
Executable file
47
gaia/tests/python/gaia-ui-tests/gaiatest/apps/contacts/regions/gmail.py
Executable file
|
|
@ -0,0 +1,47 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
from gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class GmailLogin(Base):
|
||||
|
||||
_gmail_sign_in_frame_locator = (By.CSS_SELECTOR, '.popupWindow.active iframe[data-url*="google"]')
|
||||
_email_locator = (By.ID, 'Email')
|
||||
_password_locator = (By.ID, 'Passwd')
|
||||
_sign_in_locator = (By.ID, 'signIn')
|
||||
_grant_access_button_locator = (By.ID, 'submit_approve_access')
|
||||
_next_locator = (By.ID, 'next')
|
||||
|
||||
def switch_to_gmail_login_frame(self):
|
||||
self.marionette.switch_to_frame()
|
||||
gmail_sign_in = self.marionette.find_element(*self._gmail_sign_in_frame_locator)
|
||||
self.marionette.switch_to_frame(gmail_sign_in)
|
||||
|
||||
def gmail_login(self, user, passwd):
|
||||
email = Wait(self.marionette).until(
|
||||
expected.element_present(*self._email_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(email))
|
||||
email.tap()
|
||||
email.send_keys(user)
|
||||
self.marionette.find_element(*self._next_locator).tap()
|
||||
password = Wait(self.marionette).until(
|
||||
expected.element_present(*self._password_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(password))
|
||||
password.tap()
|
||||
password.send_keys(passwd)
|
||||
self.keyboard.dismiss()
|
||||
self.marionette.find_element(*self._sign_in_locator).tap()
|
||||
|
||||
def tap_grant_access(self):
|
||||
grant_access = self.marionette.find_element(*self._grant_access_button_locator)
|
||||
Wait(self.marionette).until(expected.element_enabled(grant_access))
|
||||
grant_access.tap()
|
||||
# Go back to displayed Contacts app before waiting for the picker
|
||||
from gaiatest.apps.contacts.app import Contacts
|
||||
Contacts(self.marionette).wait_to_be_displayed()
|
||||
self.apps.switch_to_displayed_app()
|
||||
from gaiatest.apps.contacts.regions.contact_import_picker import ContactImportPicker
|
||||
return ContactImportPicker(self.marionette)
|
||||
30
gaia/tests/python/gaia-ui-tests/gaiatest/apps/contacts/regions/merge.py
Executable file
30
gaia/tests/python/gaia-ui-tests/gaiatest/apps/contacts/regions/merge.py
Executable file
|
|
@ -0,0 +1,30 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class Merge(Base):
|
||||
|
||||
_iframe_locator = (By.CSS_SELECTOR, '.popupWindow.active iframe[data-url*="matching"]')
|
||||
_body_locator = (By.TAG_NAME, 'body')
|
||||
_merge_button = (By.ID, 'merge-action')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
marionette.switch_to_frame()
|
||||
|
||||
merge_iframe = Wait(marionette).until(
|
||||
expected.element_present(*self._iframe_locator))
|
||||
Wait(marionette).until(expected.element_displayed(merge_iframe))
|
||||
marionette.switch_to_frame(merge_iframe)
|
||||
|
||||
body = marionette.find_element(*self._body_locator)
|
||||
Wait(marionette).until(lambda m: body.rect['y'] == 0)
|
||||
|
||||
def tap_on_merge(self):
|
||||
Wait(self.marionette).until(
|
||||
expected.element_present(*self._merge_button)).tap()
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
# 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/.
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest import GaiaApps
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.contacts.app import Contacts
|
||||
from gaiatest.form_controls.header import GaiaHeader
|
||||
from gaiatest.form_controls.binarycontrol import GaiaBinaryControl
|
||||
|
||||
|
||||
class SetIceContacts(Base):
|
||||
|
||||
_toggle_locator = (By.CSS_SELECTOR, 'gaia-switch[name="ice-contact-1-enabled"]')
|
||||
_select_ice_contact_1_locator = (By.ID, 'select-ice-contact-1')
|
||||
_ice_settings_header_locator = (By.ID, 'ice-settings-header')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
GaiaApps(marionette).switch_to_displayed_app()
|
||||
header = self.marionette.find_element(*self._ice_settings_header_locator)
|
||||
Wait(self.marionette).until(lambda m: header.rect['x'] == 0 and header.is_displayed())
|
||||
|
||||
def enable_set_ice_contact(self):
|
||||
GaiaBinaryControl(self.marionette, self._toggle_locator).enable()
|
||||
return SetIceContacts(self.marionette)
|
||||
|
||||
def select_ice_contact(self):
|
||||
self.marionette.find_element(*self._select_ice_contact_1_locator).tap()
|
||||
from gaiatest.apps.contacts.app import Contacts
|
||||
return Contacts(self.marionette)
|
||||
|
||||
def go_back(self):
|
||||
GaiaHeader(self.marionette, self._ice_settings_header_locator).go_back()
|
||||
from gaiatest.apps.contacts.regions.settings_form import SettingsForm
|
||||
return SettingsForm(self.marionette)
|
||||
179
gaia/tests/python/gaia-ui-tests/gaiatest/apps/contacts/regions/settings_form.py
Executable file
179
gaia/tests/python/gaia-ui-tests/gaiatest/apps/contacts/regions/settings_form.py
Executable file
|
|
@ -0,0 +1,179 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
from gaiatest import GaiaApps
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.form_controls.binarycontrol import GaiaBinaryControl
|
||||
from gaiatest.apps.contacts.regions.set_ice_contacts import SetIceContacts
|
||||
|
||||
|
||||
class SettingsForm(Base):
|
||||
|
||||
_settings_view_locator = (By.ID, 'view-settings')
|
||||
_loading_overlay_locator = (By.ID, 'loading-overlay')
|
||||
_settings_close_button_locator = (By.ID, 'settings-close')
|
||||
_order_by_last_name_switch_locator = (By.CSS_SELECTOR, 'gaia-switch[name="order.lastname"]')
|
||||
_import_from_sim_button_locator = (By.CSS_SELECTOR, "li[id*='import-sim-option'] button")
|
||||
_import_from_sdcard_locator = (By.CSS_SELECTOR, 'button.icon-sd')
|
||||
_import_from_gmail_button_locator = (By.CSS_SELECTOR, 'button.icon-gmail')
|
||||
_import_from_windows_live_button_locator = (By.CSS_SELECTOR, 'button.icon-live')
|
||||
_import_settings_header = (By.ID, 'import-settings-header')
|
||||
_export_to_sd_button_locator = (By.CSS_SELECTOR, 'button[data-l10n-id="memoryCard"]')
|
||||
_export_to_sim_button_locator = (By.CSS_SELECTOR, '#export-options button.icon-sim')
|
||||
_import_contacts_locator = (By.CSS_SELECTOR, 'button[data-l10n-id="importContactsButton"]')
|
||||
_export_contacts_locator = (By.CSS_SELECTOR, 'button[data-l10n-id="exportContactsButton"]')
|
||||
_delete_contacts_locator = (By.ID, 'bulkDelete')
|
||||
_gmail_contacts_imported_locator = (By.CSS_SELECTOR, '.icon.icon-gmail > p > span')
|
||||
_gmail_import_option_locator = (By.ID, 'import-gmail-option')
|
||||
_import_settings_locator = (By.ID, 'import-settings')
|
||||
_select_contacts_locator = (By.ID, 'selectable-form')
|
||||
_import_error_message_locator = (By.CSS_SELECTOR, '#import-live-option > p.error-message')
|
||||
_outlook_import_option_locator = (By.ID, 'import-live-option')
|
||||
_import_from_outlook_button_locator = (By.CSS_SELECTOR, 'button.icon-live')
|
||||
_set_ice_contact_button_locator = (By.ID, 'set-ice')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
view = self.marionette.find_element(*self._settings_view_locator)
|
||||
Wait(self.marionette).until(lambda m: view.rect['y'] == 0)
|
||||
|
||||
def enable_order_by_last_name(self):
|
||||
self._order_by_last_name_switch.enable()
|
||||
|
||||
def disable_order_by_last_name(self):
|
||||
self._order_by_last_name_switch.disable()
|
||||
|
||||
@property
|
||||
def _order_by_last_name_switch(self):
|
||||
return GaiaBinaryControl(self.marionette, self._order_by_last_name_switch_locator)
|
||||
|
||||
def tap_import_contacts(self):
|
||||
import_contacts = Wait(self.marionette).until(
|
||||
expected.element_present(*self._import_contacts_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(import_contacts))
|
||||
import_contacts.tap()
|
||||
import_settings = self.marionette.find_element(*self._import_settings_locator)
|
||||
Wait(self.marionette).until(lambda m: import_settings.location['x'] == 0)
|
||||
|
||||
def tap_export_contacts(self):
|
||||
export_contacts = Wait(self.marionette).until(
|
||||
expected.element_present(*self._export_contacts_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(export_contacts))
|
||||
export_contacts.tap()
|
||||
import_settings = self.marionette.find_element(*self._import_settings_locator)
|
||||
Wait(self.marionette).until(lambda m: import_settings.location['x'] == 0)
|
||||
|
||||
def tap_delete_contacts(self):
|
||||
delete_contacts = Wait(self.marionette).until(
|
||||
expected.element_present(*self._delete_contacts_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(delete_contacts))
|
||||
delete_contacts.tap()
|
||||
select_contacts = self.marionette.find_element(*self._select_contacts_locator)
|
||||
Wait(self.marionette).until(lambda m: select_contacts.location['y'] == 0)
|
||||
|
||||
def tap_import_from_sim(self):
|
||||
import_from_sim = Wait(self.marionette).until(
|
||||
expected.element_present(*self._import_from_sim_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(import_from_sim))
|
||||
import_from_sim.tap()
|
||||
from gaiatest.apps.contacts.app import Contacts
|
||||
status_message = Wait(self.marionette).until(
|
||||
expected.element_present(*Contacts._status_message_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(status_message))
|
||||
Wait(self.marionette).until(expected.element_not_displayed(status_message))
|
||||
|
||||
@property
|
||||
def gmail_imported_contacts(self):
|
||||
return self.marionette.find_element(*self._gmail_contacts_imported_locator).text
|
||||
|
||||
def tap_import_from_gmail(self):
|
||||
import_from_gmail = Wait(self.marionette).until(
|
||||
expected.element_present(*self._import_from_gmail_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(import_from_gmail))
|
||||
import_from_gmail.tap()
|
||||
from gaiatest.apps.contacts.regions.gmail import GmailLogin
|
||||
return GmailLogin(self.marionette)
|
||||
|
||||
def tap_import_from_sdcard(self):
|
||||
import_from_sdcard = Wait(self.marionette).until(
|
||||
expected.element_present(*self._import_from_sdcard_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(import_from_sdcard))
|
||||
import_from_sdcard.tap()
|
||||
from gaiatest.apps.contacts.app import Contacts
|
||||
status_message = Wait(self.marionette).until(
|
||||
expected.element_present(*Contacts._status_message_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(status_message))
|
||||
Wait(self.marionette).until(expected.element_not_displayed(status_message))
|
||||
|
||||
def tap_export_to_sd(self):
|
||||
export_to_sdcard = Wait(self.marionette).until(
|
||||
expected.element_present(*self._export_to_sd_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(export_to_sdcard))
|
||||
export_to_sdcard.tap()
|
||||
select_contacts = self.marionette.find_element(*self._select_contacts_locator)
|
||||
Wait(self.marionette).until(lambda m: select_contacts.location['y'] == 0)
|
||||
|
||||
def tap_export_to_sim(self):
|
||||
export_to_sim = Wait(self.marionette).until(
|
||||
expected.element_present(*self._export_to_sim_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(export_to_sim))
|
||||
export_to_sim.tap()
|
||||
select_contacts = self.marionette.find_element(*self._select_contacts_locator)
|
||||
Wait(self.marionette).until(
|
||||
lambda m: select_contacts.rect['y'] == 0 and select_contacts.is_displayed())
|
||||
|
||||
def tap_done(self):
|
||||
close = self.marionette.find_element(*self._settings_close_button_locator)
|
||||
close.tap()
|
||||
Wait(self.marionette).until(expected.element_not_displayed(close))
|
||||
from gaiatest.apps.contacts.app import Contacts
|
||||
return Contacts(self.marionette)
|
||||
|
||||
def tap_back_from_import_contacts(self):
|
||||
header = self.marionette.find_element(*self._import_settings_header)
|
||||
# TODO: remove tap with coordinates after Bug 1061698 is fixed
|
||||
header.tap(25, 25)
|
||||
Wait(self.marionette).until(expected.element_not_displayed(header))
|
||||
|
||||
def tap_set_ice_contact(self):
|
||||
self.marionette.find_element(*self._set_ice_contact_button_locator).tap()
|
||||
return SetIceContacts(self.marionette)
|
||||
|
||||
@property
|
||||
def is_gmail_import_service_in_error(self):
|
||||
gmail_import_service = self.marionette.find_element(*self._gmail_import_option_locator)
|
||||
return 'error' in gmail_import_service.get_attribute('class')
|
||||
|
||||
@property
|
||||
def is_gmail_import_enabled(self):
|
||||
return self.marionette.find_element(*self._import_from_gmail_button_locator).is_enabled()
|
||||
|
||||
@property
|
||||
def is_error_message_displayed(self):
|
||||
return self.is_element_displayed(*self._import_error_message_locator)
|
||||
|
||||
@property
|
||||
def is_outlook_import_service_in_error(self):
|
||||
outlook_import_service = self.marionette.find_element(*self._outlook_import_option_locator)
|
||||
return 'error' in outlook_import_service.get_attribute('class')
|
||||
|
||||
@property
|
||||
def is_outlook_import_enabled(self):
|
||||
return self.marionette.find_element(*self._import_from_outlook_button_locator).is_enabled()
|
||||
|
||||
|
||||
class ConfirmationView(Base):
|
||||
|
||||
_confirmation_locator = (By.ID, 'confirmation-message')
|
||||
_error_message_locator = (By.CSS_SELECTOR, '#confirmation-message p')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
view = self.marionette.find_element(*self._confirmation_locator)
|
||||
Wait(self.marionette).until(lambda m: view.location['y'] == 0)
|
||||
|
||||
@property
|
||||
def error_message(self):
|
||||
return self.marionette.find_element(*self._error_message_locator).text
|
||||
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/cost_control/__init__.py
Executable file
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/cost_control/__init__.py
Executable file
82
gaia/tests/python/gaia-ui-tests/gaiatest/apps/cost_control/app.py
Executable file
82
gaia/tests/python/gaia-ui-tests/gaiatest/apps/cost_control/app.py
Executable file
|
|
@ -0,0 +1,82 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.form_controls.binarycontrol import GaiaBinaryControl
|
||||
|
||||
|
||||
class CostControl(Base):
|
||||
|
||||
name = 'Usage'
|
||||
|
||||
_usage_app_main_locator = (By.ID, 'datausage-tab')
|
||||
_usage_app_title_locator = (By.CSS_SELECTOR, 'h1[data-l10n-id="usage"]')
|
||||
_settings_button_locator = (By.CSS_SELECTOR, 'button.settings-button')
|
||||
|
||||
_mobile_data_item_locator = (By.ID, 'mobileItem')
|
||||
_mobile_data_tracking_locator = (By.ID, 'mobileCheck')
|
||||
_mobile_data_label_locator = (By.CSS_SELECTOR, '#mobileItem label')
|
||||
_mobile_data_usage_figure_locator = (By.ID, 'mobileOverview')
|
||||
_wifi_data_item_locator = (By.ID, 'mobileItem')
|
||||
_wifi_data_tracking_locator = (By.ID, 'wifiCheck')
|
||||
_wifi_data_label_locator = (By.CSS_SELECTOR, '#wifiItem label')
|
||||
_wifi_data_usage_figure_locator = (By.ID, 'wifiOverview')
|
||||
|
||||
# FTE
|
||||
_ftu_frame_locator = (By.ID, 'fte_view')
|
||||
_ftu_section_locator = (By.ID, 'firsttime-view')
|
||||
|
||||
@property
|
||||
def is_mobile_data_tracking_on(self):
|
||||
return self._mobile_tracking_switch.is_checked
|
||||
|
||||
def disable_mobile_data_tracking(self):
|
||||
self._mobile_tracking_switch.disable()
|
||||
|
||||
@property
|
||||
def _mobile_tracking_switch(self):
|
||||
return GaiaBinaryControl(self.marionette, self._mobile_data_tracking_locator)
|
||||
|
||||
@property
|
||||
def is_wifi_data_tracking_on(self):
|
||||
return self._wifi_tracking_switch.is_checked
|
||||
|
||||
def enable_wifi_data_tracking(self):
|
||||
self._wifi_tracking_switch.enable()
|
||||
|
||||
@property
|
||||
def _wifi_tracking_switch(self):
|
||||
return GaiaBinaryControl(self.marionette, self._wifi_data_tracking_locator)
|
||||
|
||||
@property
|
||||
def mobile_data_usage_figure(self):
|
||||
return self.marionette.find_element(*self._mobile_data_usage_figure_locator).text
|
||||
|
||||
@property
|
||||
def wifi_data_usage_figure(self):
|
||||
return self.marionette.find_element(*self._wifi_data_usage_figure_locator).text
|
||||
|
||||
def run_ftu_accepting_defaults(self):
|
||||
"""Complete the 3 steps of the Usage app's FTU accepting all default values."""
|
||||
from gaiatest.apps.cost_control.regions.ftu_step1 import FTUStep1
|
||||
ftu_step1 = FTUStep1(self.marionette)
|
||||
ftu_step2 = ftu_step1.tap_next()
|
||||
ftu_step3 = ftu_step2.tap_next()
|
||||
ftu_step3.tap_lets_go()
|
||||
|
||||
def tap_settings(self):
|
||||
settings = Wait(self.marionette).until(
|
||||
expected.element_present(*self._settings_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(settings))
|
||||
settings.tap()
|
||||
from gaiatest.apps.cost_control.regions.settings import Settings
|
||||
return Settings(self.marionette)
|
||||
|
||||
def switch_to_ftu(self):
|
||||
ftu_iframe = self.marionette.find_element(*self._ftu_frame_locator)
|
||||
Wait(self.marionette).until(
|
||||
lambda m: 'non-ready' not in ftu_iframe.get_attribute('class') and
|
||||
ftu_iframe.is_displayed())
|
||||
self.marionette.switch_to_frame(ftu_iframe)
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
# 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 gaiatest.apps.base import Base
|
||||
from gaiatest.apps.cost_control.regions.ftu_step2 import FTUStep2
|
||||
|
||||
|
||||
class FTUStep1(Base):
|
||||
|
||||
_welcome_title_locator = (By.CSS_SELECTOR, 'h1[data-l10n-id="fte-welcome-title"]')
|
||||
_next_button_locator = (By.CSS_SELECTOR, '#step-1 button[data-l10n-id="next"]')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
title = self.marionette.find_element(*self._welcome_title_locator)
|
||||
Wait(self.marionette).until(lambda m: title.location['x'] == 0)
|
||||
|
||||
def tap_next(self):
|
||||
# TODO Remove the sleep when Bug 1013249 is fixed
|
||||
time.sleep(2)
|
||||
next = Wait(self.marionette).until(
|
||||
expected.element_present(*self._next_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(next))
|
||||
next.tap()
|
||||
return FTUStep2(self.marionette)
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import By, Wait
|
||||
|
||||
from gaiatest.apps.cost_control.app import CostControl
|
||||
from gaiatest.apps.cost_control.regions.ftu_step3 import FTUStep3
|
||||
|
||||
|
||||
class FTUStep2(CostControl):
|
||||
|
||||
_view_locator = (By.ID, 'non-vivo-step-1')
|
||||
_reset_report_period_select_locator = (By.CSS_SELECTOR, '#non-vivo-step-1 gaia-select')
|
||||
_next_button_locator = (By.CSS_SELECTOR, '#non-vivo-step-1 button[data-l10n-id="next"]')
|
||||
|
||||
def __init__(self, marionette):
|
||||
CostControl.__init__(self, marionette)
|
||||
view = self.marionette.find_element(*self._view_locator)
|
||||
Wait(self.marionette).until(lambda m: view.location['x'] == 0)
|
||||
|
||||
def select_reset_report_value(self, value):
|
||||
self.marionette.find_element(
|
||||
*self._reset_report_period_select_locator).tap()
|
||||
self.select(value)
|
||||
self.switch_to_ftu()
|
||||
|
||||
def tap_next(self):
|
||||
self.marionette.find_element(*self._next_button_locator).tap()
|
||||
return FTUStep3(self.marionette)
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
# 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 gaiatest.apps.cost_control.app import CostControl
|
||||
from gaiatest.form_controls.binarycontrol import GaiaBinaryControl
|
||||
|
||||
|
||||
class FTUStep3(CostControl):
|
||||
|
||||
_view_locator = (By.ID, 'non-vivo-step-2')
|
||||
_data_alert_switch_locator = (By.CSS_SELECTOR, '#non-vivo-step-2 gaia-switch[data-option="dataLimit"]')
|
||||
_data_alert_selector_locator = (By.CSS_SELECTOR, '#non-vivo-step-2 button[data-widget-type="data-limit"]')
|
||||
|
||||
# Data limit popup for changing limit volume and unit
|
||||
_data_limit_view_locator = (By.ID, 'data-limit-dialog')
|
||||
_data_limit_dialog_input_locator = (By.ID, 'data-limit-input')
|
||||
_data_limit_dialog_done_locator = (By.ID, 'data-usage-done-button')
|
||||
_data_limit_switch_unit_locator = (By.CSS_SELECTOR, '#data-limit-dialog .switch-unit-button')
|
||||
|
||||
_go_button_locator = (By.CSS_SELECTOR, '#non-vivo-step-2 button.recommend')
|
||||
|
||||
def __init__(self, marionette):
|
||||
CostControl.__init__(self, marionette)
|
||||
view = self.marionette.find_element(*self._view_locator)
|
||||
Wait(self.marionette).until(lambda m: view.rect['x'] == 0)
|
||||
|
||||
def enable_data_alert(self):
|
||||
self._data_alert_switch.enable()
|
||||
# Wait for Usage section to hide/display as required
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._data_alert_selector_locator))
|
||||
|
||||
@property
|
||||
def is_data_alert_switch_checked(self):
|
||||
return self._data_alert_switch.is_checked
|
||||
|
||||
@property
|
||||
def _data_alert_switch(self):
|
||||
return GaiaBinaryControl(self.marionette, self._data_alert_switch_locator)
|
||||
|
||||
def select_when_use_is_above_unit_and_value(self, unit, value):
|
||||
self.marionette.find_element(*self._data_alert_selector_locator).tap()
|
||||
|
||||
data_limit_view = self.marionette.find_element(
|
||||
*self._data_limit_view_locator)
|
||||
Wait(self.marionette).until(lambda m: data_limit_view.location['y'] == 0)
|
||||
|
||||
current_unit = Wait(self.marionette).until(
|
||||
expected.element_present(*self._data_limit_switch_unit_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(current_unit))
|
||||
|
||||
if current_unit.text != unit:
|
||||
current_unit.tap()
|
||||
Wait(self.marionette).until(lambda m: current_unit.text == unit)
|
||||
|
||||
# clear the original assigned value and set it to the new value
|
||||
self.marionette.find_element(*self._data_limit_dialog_input_locator).clear()
|
||||
self.keyboard.send(value)
|
||||
self.switch_to_ftu()
|
||||
self.marionette.find_element(*self._data_limit_dialog_done_locator).tap()
|
||||
|
||||
data_limit_view = self.marionette.find_element(
|
||||
*self._data_limit_view_locator)
|
||||
Wait(self.marionette).until(lambda m: int(data_limit_view.location['y']) == int(data_limit_view.size['height']))
|
||||
|
||||
def tap_lets_go(self):
|
||||
self.marionette.find_element(*self._go_button_locator).tap()
|
||||
Wait(self.marionette).until(expected.element_not_displayed(*self._ftu_frame_locator))
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
# TODO Some wait for Usage to fully initialize
|
||||
time.sleep(2)
|
||||
108
gaia/tests/python/gaia-ui-tests/gaiatest/apps/cost_control/regions/settings.py
Executable file
108
gaia/tests/python/gaia-ui-tests/gaiatest/apps/cost_control/regions/settings.py
Executable file
|
|
@ -0,0 +1,108 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.form_controls.binarycontrol import GaiaBinaryControl
|
||||
|
||||
|
||||
class Settings(Base):
|
||||
_settings_iframe_locator = (By.ID, 'settings-view-placeholder')
|
||||
_settings_title_locator = (By.CSS_SELECTOR, 'section#settings-view h1')
|
||||
|
||||
_data_alert_switch_locator = (By.CSS_SELECTOR, 'gaia-switch[data-option="dataLimit"]')
|
||||
_when_use_is_above_button_locator = (By.CSS_SELECTOR, 'button[data-widget-type="data-limit"]')
|
||||
_unit_button_locator = (By.CSS_SELECTOR, '#data-limit-dialog form button')
|
||||
_size_input_locator = (By.CSS_SELECTOR, '#data-limit-dialog form input')
|
||||
_usage_done_button_locator = (By.ID, 'data-usage-done-button')
|
||||
|
||||
_reset_button_locator = (By.ID, 'reset-data-usage')
|
||||
_reset_dialog_locator = (By.ID, 'reset-data-dialog')
|
||||
_reset_wifi_usage_button_locator = (By.ID, 'reset-wifi-data-usage')
|
||||
_reset_mobile_usage_button_locator = (By.ID, 'reset-mobile-data-usage')
|
||||
_done_button_locator = (By.ID, 'close-settings')
|
||||
_confirm_reset_button_locator = (By.CSS_SELECTOR, '#reset-dialog button.danger')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
self.switch_to_settings_iframe()
|
||||
|
||||
def switch_to_settings_iframe(self):
|
||||
# go into iframe of usage app settings
|
||||
frame = Wait(self.marionette).until(expected.element_present(
|
||||
*self._settings_iframe_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(frame))
|
||||
self.marionette.switch_to_frame(frame)
|
||||
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._settings_title_locator))))
|
||||
|
||||
def enable_data_alert_switch(self):
|
||||
GaiaBinaryControl(self.marionette, self._data_alert_switch_locator).enable()
|
||||
|
||||
@property
|
||||
def is_data_alert_switch_checked(self):
|
||||
return GaiaBinaryControl(self.marionette, self._data_alert_switch_locator).is_checked
|
||||
|
||||
def select_when_use_is_above_unit_and_value(self, unit, value):
|
||||
when_use_is_above_button = self.marionette.find_element(*self._when_use_is_above_button_locator)
|
||||
Wait(self.marionette).until(lambda m: when_use_is_above_button.get_attribute('disabled') == 'false')
|
||||
when_use_is_above_button.tap()
|
||||
|
||||
current_unit = Wait(self.marionette).until(
|
||||
expected.element_present(*self._unit_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(current_unit))
|
||||
if current_unit.text != unit:
|
||||
current_unit.tap()
|
||||
# We need to wait for the javascript to do its stuff
|
||||
Wait(self.marionette).until(lambda m: current_unit.text == unit)
|
||||
|
||||
# clear the original assigned value and set it to the new value
|
||||
size = Wait(self.marionette).until(expected.element_present(*self._size_input_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(size))
|
||||
size.clear()
|
||||
size.send_keys(value)
|
||||
self.marionette.find_element(*self._usage_done_button_locator).tap()
|
||||
|
||||
def tap_confirm_reset(self):
|
||||
confirm_reset_button = Wait(self.marionette).until(
|
||||
expected.element_present(*self._confirm_reset_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(confirm_reset_button))
|
||||
|
||||
self.tap_element_from_system_app(confirm_reset_button)
|
||||
|
||||
# go back to iframe of usage app settings
|
||||
self.apps.switch_to_displayed_app()
|
||||
self.switch_to_settings_iframe()
|
||||
|
||||
def reset_wifi_usage(self):
|
||||
self.marionette.find_element(*self._reset_button_locator).tap()
|
||||
|
||||
reset_wifi_usage = Wait(self.marionette).until(
|
||||
expected.element_present(*self._reset_wifi_usage_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(reset_wifi_usage))
|
||||
reset_dialog = self.marionette.find_element(*self._reset_dialog_locator)
|
||||
reset_wifi_usage.tap()
|
||||
|
||||
self.tap_confirm_reset()
|
||||
|
||||
|
||||
def reset_mobile_usage(self):
|
||||
self.marionette.find_element(*self._reset_button_locator).tap()
|
||||
reset_mobile_usage = Wait(self.marionette).until(
|
||||
expected.element_present(*self._reset_mobile_usage_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(reset_mobile_usage))
|
||||
reset_dialog = self.marionette.find_element(*self._reset_dialog_locator)
|
||||
reset_mobile_usage.tap()
|
||||
|
||||
self.tap_confirm_reset()
|
||||
|
||||
def tap_done(self):
|
||||
done_button = Wait(self.marionette).until(
|
||||
expected.element_present(*self._done_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(done_button))
|
||||
done_button.tap()
|
||||
# Switch back to Cost Control app frame
|
||||
self.apps.switch_to_displayed_app()
|
||||
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/email/__init__.py
Executable file
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/email/__init__.py
Executable file
318
gaia/tests/python/gaia-ui-tests/gaiatest/apps/email/app.py
Executable file
318
gaia/tests/python/gaia-ui-tests/gaiatest/apps/email/app.py
Executable file
|
|
@ -0,0 +1,318 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.base import PageRegion
|
||||
from gaiatest.apps.email.regions.setup import SetupEmail
|
||||
from gaiatest.apps.email.regions.setup import ManualSetupEmail
|
||||
from gaiatest.apps.email.regions.settings import Settings
|
||||
from gaiatest.apps.email.regions.google import GoogleLogin
|
||||
|
||||
|
||||
class Email(Base):
|
||||
|
||||
name = 'E-Mail'
|
||||
|
||||
_email_locator = (By.CSS_SELECTOR, '#cardContainer .msg-header-item:not([data-index="-1"])')
|
||||
_syncing_locator = (By.CSS_SELECTOR, '#cardContainer .msg-messages-syncing > .small')
|
||||
_manual_setup_locator = (By.CSS_SELECTOR, '#cardContainer .sup-manual-config-btn')
|
||||
_message_list_locator = (By.CSS_SELECTOR, 'cards-message-list')
|
||||
_setup_account_info = (By.TAG_NAME, 'cards-setup-account-info')
|
||||
_setup_manual_config = (By.TAG_NAME, 'cards-setup-manual-config')
|
||||
_folder_picker_locator = (By.TAG_NAME, 'cards-folder-picker')
|
||||
_settings_main_locator = (By.TAG_NAME, 'cards-settings-main')
|
||||
_settings_account_locator = (By.TAG_NAME, 'cards-settings-account')
|
||||
_confirm_dialog_locator = (By.TAG_NAME, 'cards-confirm-dialog')
|
||||
_refresh_button_locator = (By.CLASS_NAME, 'msg-refresh-btn')
|
||||
_search_textbox_locator = (By.CSS_SELECTOR, 'form[role="search"]')
|
||||
_email_subject_locator = (By.XPATH, '//a[@data-index!="-1"]/div/span[text()="%s"]')
|
||||
_back_button_locator = (By.CLASS_NAME, 'sup-back-btn')
|
||||
emails_list_header_locator = (By.CSS_SELECTOR, '.msg-list-header')
|
||||
|
||||
def basic_setup_email(self, name, email, password):
|
||||
|
||||
setup = SetupEmail(self.marionette)
|
||||
setup.type_name(name)
|
||||
setup.type_email(email)
|
||||
|
||||
setup.tap_next()
|
||||
|
||||
google_login = GoogleLogin(self.marionette)
|
||||
|
||||
# check if the google autocomplete on email field works as expected
|
||||
assert google_login.email == email
|
||||
|
||||
# dismiss the keyboard and return to the correct frame
|
||||
google_login.keyboard.dismiss()
|
||||
google_login.switch_to_frame()
|
||||
|
||||
google_login.tap_next()
|
||||
google_login.type_password(password)
|
||||
google_login.tap_sign_in()
|
||||
|
||||
# approve access to your account
|
||||
google_login.wait_for_approve_access()
|
||||
google_login.tap_approve_access()
|
||||
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
setup.tap_account_prefs_next()
|
||||
|
||||
setup.wait_for_setup_complete()
|
||||
|
||||
setup.tap_continue()
|
||||
self.wait_for_message_list()
|
||||
|
||||
def setup_IMAP_email(self, imap, smtp):
|
||||
basic_setup = SetupEmail(self.marionette)
|
||||
basic_setup.type_name('IMAP account')
|
||||
basic_setup.type_email(imap['email'])
|
||||
|
||||
setup = self.tap_manual_setup()
|
||||
|
||||
setup.select_account_type('IMAP+SMTP')
|
||||
|
||||
setup.type_imap_hostname(imap['hostname'])
|
||||
setup.type_imap_name(imap['username'])
|
||||
setup.type_imap_password(imap['password'])
|
||||
setup.type_imap_port(imap['port'])
|
||||
|
||||
setup.type_smtp_hostname(smtp['hostname'])
|
||||
setup.type_smtp_name(smtp['username'])
|
||||
setup.type_smtp_password(smtp['password'])
|
||||
setup.type_smtp_port(smtp['port'])
|
||||
|
||||
setup.tap_next()
|
||||
setup.check_for_emails_interval('20000')
|
||||
|
||||
setup.tap_account_prefs_next()
|
||||
|
||||
setup.wait_for_setup_complete()
|
||||
setup.tap_continue()
|
||||
self.wait_for_message_list()
|
||||
|
||||
def setup_active_sync_email(self, active_sync):
|
||||
basic_setup = SetupEmail(self.marionette)
|
||||
basic_setup.type_name('ActiveSync account')
|
||||
basic_setup.type_email(active_sync['email'])
|
||||
|
||||
setup = self.tap_manual_setup()
|
||||
|
||||
setup.select_account_type('ActiveSync')
|
||||
|
||||
setup.type_password(active_sync['password'])
|
||||
setup.type_activesync_hostname(active_sync['hostname'])
|
||||
setup.type_activesync_name(active_sync['username'])
|
||||
|
||||
setup.tap_next()
|
||||
|
||||
setup.check_for_emails_interval('20000')
|
||||
setup.tap_account_prefs_next()
|
||||
|
||||
setup.wait_for_setup_complete()
|
||||
setup.tap_continue()
|
||||
self.wait_for_message_list()
|
||||
|
||||
def delete_email_account(self, index):
|
||||
|
||||
toolbar = self.header.tap_menu()
|
||||
toolbar.tap_settings()
|
||||
settings = Settings(self.marionette)
|
||||
account_settings = settings.email_accounts[index].tap()
|
||||
delete_confirmation = account_settings.tap_delete()
|
||||
delete_confirmation.tap_delete()
|
||||
|
||||
def tap_manual_setup(self):
|
||||
manual_setup = Wait(self.marionette).until(
|
||||
expected.element_present(*self._manual_setup_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(manual_setup))
|
||||
manual_setup.tap()
|
||||
return ManualSetupEmail(self.marionette)
|
||||
|
||||
def a11y_click_manual_setup(self):
|
||||
manual_setup = Wait(self.marionette).until(
|
||||
expected.element_present(*self._manual_setup_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(manual_setup))
|
||||
self.accessibility.click(manual_setup)
|
||||
return ManualSetupEmail(self.marionette)
|
||||
|
||||
def a11y_navigate_to_manual_setup(self, name, email):
|
||||
setup = SetupEmail(self.marionette)
|
||||
setup.type_name(name)
|
||||
setup.type_email(email)
|
||||
setup = self.a11y_click_manual_setup()
|
||||
|
||||
@property
|
||||
def header(self):
|
||||
return Header(self.marionette, self.marionette.find_element(*self.emails_list_header_locator))
|
||||
|
||||
@property
|
||||
def toolbar(self):
|
||||
return ToolBar(self.marionette)
|
||||
|
||||
@property
|
||||
def mails(self):
|
||||
return [Message(self.marionette, mail) for mail in self.marionette.find_elements(*self._email_locator)]
|
||||
|
||||
def wait_for_emails_to_sync(self):
|
||||
element = self.marionette.find_element(*self._refresh_button_locator)
|
||||
Wait(self.marionette, timeout=60).until(
|
||||
lambda m: element.get_attribute(
|
||||
'data-state') == 'synchronized')
|
||||
|
||||
def wait_for_message_list(self):
|
||||
element = self.marionette.find_element(*self._message_list_locator)
|
||||
Wait(self.marionette).until(
|
||||
lambda m: element.is_displayed() and
|
||||
element.location['x'] == 0)
|
||||
|
||||
def wait_for_search_textbox_displayed(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._search_textbox_locator))
|
||||
|
||||
def tap_email_subject(self, subject):
|
||||
subject_locator = (
|
||||
self._email_subject_locator[0],
|
||||
self._email_subject_locator[1] % subject
|
||||
)
|
||||
self.marionette.find_element(*subject_locator).tap()
|
||||
from gaiatest.apps.email.regions.read_email import ReadEmail
|
||||
return ReadEmail(self.marionette)
|
||||
|
||||
def wait_for_email(self, subject, timeout=120):
|
||||
Wait(self.marionette, timeout, interval=5).until(
|
||||
self.email_exists(self, subject))
|
||||
|
||||
class email_exists(object):
|
||||
|
||||
def __init__(self, app, subject):
|
||||
self.app = app
|
||||
self.subject = subject
|
||||
|
||||
def __call__(self, marionette):
|
||||
if self.subject in [mail.subject for mail in self.app.mails]:
|
||||
return True
|
||||
else:
|
||||
self.app.toolbar.tap_refresh()
|
||||
self.app.wait_for_emails_to_sync()
|
||||
self.app.mails[0].scroll_to_message()
|
||||
return False
|
||||
|
||||
|
||||
class Header(PageRegion):
|
||||
|
||||
_menu_button_locator = (By.CSS_SELECTOR, '.msg-folder-list-btn')
|
||||
_compose_button_locator = (By.CSS_SELECTOR, '.msg-compose-btn')
|
||||
_label_locator = (By.CSS_SELECTOR, '.msg-list-header-folder-label.header-label')
|
||||
|
||||
def a11y_click_menu(self):
|
||||
self.accessibility.click(self.root_element.find_element(*self._menu_button_locator))
|
||||
toolbar = ToolBar(self.marionette)
|
||||
Wait(self.marionette).until(lambda m: toolbar.is_a11y_visible)
|
||||
return toolbar
|
||||
|
||||
def tap_menu(self):
|
||||
self.root_element.find_element(*self._menu_button_locator).tap()
|
||||
toolbar = ToolBar(self.marionette)
|
||||
Wait(self.marionette).until(lambda m: toolbar.is_visible)
|
||||
return toolbar
|
||||
|
||||
def tap_compose(self):
|
||||
self.root_element.find_element(*self._compose_button_locator).tap()
|
||||
from gaiatest.apps.email.regions.new_email import NewEmail
|
||||
return NewEmail(self.marionette)
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
return self.root_element.find_element(*self._label_locator).text
|
||||
|
||||
@property
|
||||
def is_menu_visible(self):
|
||||
return self.is_element_displayed(*self._menu_button_locator)
|
||||
|
||||
@property
|
||||
def is_compose_visible(self):
|
||||
return self.is_element_displayed(*self._compose_button_locator)
|
||||
|
||||
|
||||
class ToolBar(Base):
|
||||
_toolbar_locator = (By.CSS_SELECTOR, '#cardContainer .card.center .fld-nav-toolbar')
|
||||
_refresh_locator = (By.CSS_SELECTOR, '#cardContainer .card.center .msg-refresh-btn')
|
||||
_search_locator = (By.CSS_SELECTOR, '#cardContainer .card.center .msg-search-btn')
|
||||
_edit_locator = (By.CSS_SELECTOR, '#cardContainer .card.center .msg-edit-btn')
|
||||
_settings_locator = (By.CSS_SELECTOR, '#cardContainer .card.center .fld-nav-settings-btn')
|
||||
_settings_a11y_locator = (By.CSS_SELECTOR,
|
||||
'#cardContainer .card.center .fld-nav-toolbar.bottom-toolbar')
|
||||
|
||||
def tap_refresh(self):
|
||||
refresh = Wait(self.marionette).until(
|
||||
expected.element_present(*self._refresh_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(refresh))
|
||||
refresh.tap()
|
||||
|
||||
def tap_search(self):
|
||||
search = Wait(self.marionette).until(
|
||||
expected.element_present(*self._search_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(search))
|
||||
search.tap()
|
||||
|
||||
def tap_edit(self):
|
||||
edit = Wait(self.marionette).until(
|
||||
expected.element_present(*self._edit_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(edit))
|
||||
edit.tap()
|
||||
|
||||
def a11y_click_settings(self):
|
||||
settings = Wait(self.marionette).until(
|
||||
expected.element_present(*self._settings_a11y_locator))
|
||||
Wait(self.marionette).until(lambda m: self.accessibility.is_visible(settings))
|
||||
self.accessibility.click(settings)
|
||||
return Settings(self.marionette)
|
||||
|
||||
def tap_settings(self):
|
||||
settings = Wait(self.marionette).until(
|
||||
expected.element_present(*self._settings_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(settings))
|
||||
settings.tap()
|
||||
|
||||
@property
|
||||
def is_visible(self):
|
||||
return self.marionette.find_element(*self._toolbar_locator).location['x'] == 0
|
||||
|
||||
@property
|
||||
def is_a11y_visible(self):
|
||||
return self.accessibility.is_visible(self.marionette.find_element(*self._toolbar_locator))
|
||||
|
||||
@property
|
||||
def is_refresh_visible(self):
|
||||
return self.is_element_displayed(*self._refresh_locator)
|
||||
|
||||
@property
|
||||
def is_search_visible(self):
|
||||
return self.is_element_displayed(*self._search_locator)
|
||||
|
||||
@property
|
||||
def is_edit_visible(self):
|
||||
return self.is_element_displayed(*self._edit_locator)
|
||||
|
||||
@property
|
||||
def is_settings_visible(self):
|
||||
return self.is_element_displayed(*self._settings_locator)
|
||||
|
||||
|
||||
class Message(PageRegion):
|
||||
_subject_locator = (By.CSS_SELECTOR, '.msg-header-subject')
|
||||
_senders_email_locator = (By.CSS_SELECTOR, '.msg-header-author')
|
||||
|
||||
@property
|
||||
def subject(self):
|
||||
return self.root_element.find_element(*self._subject_locator).text
|
||||
|
||||
@property
|
||||
def senders_email(self):
|
||||
return self.root_element.find_element(*self._senders_email_locator).text
|
||||
|
||||
def scroll_to_message(self):
|
||||
self.marionette.execute_script("arguments[0].scrollIntoView(false);", [self.root_element])
|
||||
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/email/regions/__init__.py
Executable file
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/email/regions/__init__.py
Executable file
56
gaia/tests/python/gaia-ui-tests/gaiatest/apps/email/regions/google.py
Executable file
56
gaia/tests/python/gaia-ui-tests/gaiatest/apps/email/regions/google.py
Executable file
|
|
@ -0,0 +1,56 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class GoogleLogin(Base):
|
||||
_iframe_locator = (By.CSS_SELECTOR, "iframe.sup-oauth2-browser[src *= 'google']")
|
||||
_email_locator = (By.ID, 'Email')
|
||||
_password_locator = (By.ID, 'Passwd')
|
||||
_sign_in_locator = (By.ID, 'signIn')
|
||||
_approve_access_locator = (By.CSS_SELECTOR, '#submit_approve_access.goog-buttonset-action')
|
||||
_next_locator = (By.ID, 'next')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
self.switch_to_frame()
|
||||
# wait for the page to load
|
||||
email = Wait(self.marionette).until(
|
||||
expected.element_present(*self._email_locator))
|
||||
Wait(self.marionette).until(lambda m: email.get_attribute('value') != '')
|
||||
|
||||
@property
|
||||
def email(self):
|
||||
return self.marionette.find_element(*self._email_locator).get_attribute('value')
|
||||
|
||||
def type_password(self, password):
|
||||
element = Wait(self.marionette).until(expected.element_present(*self._password_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
element.send_keys(password)
|
||||
|
||||
def tap_sign_in(self):
|
||||
self.marionette.find_element(*self._sign_in_locator).tap()
|
||||
|
||||
def tap_next(self):
|
||||
self.marionette.find_element(*self._next_locator).tap()
|
||||
|
||||
def wait_for_approve_access(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._approve_access_locator))))
|
||||
|
||||
def tap_approve_access(self):
|
||||
approve_access = Wait(self.marionette).until(
|
||||
expected.element_present(*self._approve_access_locator))
|
||||
Wait(self.marionette).until(expected.element_enabled(approve_access))
|
||||
approve_access.tap()
|
||||
|
||||
def switch_to_frame(self):
|
||||
# wait for the pop up screen to open
|
||||
view = Wait(self.marionette).until(
|
||||
expected.element_present(*self._iframe_locator))
|
||||
self.marionette.switch_to_frame(view)
|
||||
56
gaia/tests/python/gaia-ui-tests/gaiatest/apps/email/regions/new_email.py
Executable file
56
gaia/tests/python/gaia-ui-tests/gaiatest/apps/email/regions/new_email.py
Executable file
|
|
@ -0,0 +1,56 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class NewEmail(Base):
|
||||
# Write new email
|
||||
|
||||
_view_locator = (By.CSS_SELECTOR, '#cardContainer cards-compose')
|
||||
_to_locator = (By.CSS_SELECTOR, '#cardContainer .card.center .cmp-to-text.cmp-addr-text')
|
||||
_cc_locator = (By.CSS_SELECTOR, '#cardContainer .card.center .cmp-cc-text.cmp-addr-text')
|
||||
_bcc_locator = (By.CSS_SELECTOR, '#cardContainer .card.center .cmp-bcc-text.cmp-addr-text')
|
||||
_subject_locator = (By.CSS_SELECTOR, '#cardContainer .card.center .cmp-subject-text')
|
||||
_body_locator = (By.CSS_SELECTOR, '#cardContainer .card.center .cmp-body-text')
|
||||
_send_locator = (By.CSS_SELECTOR, '#cardContainer .card.center .icon.icon-send')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
view = self.marionette.find_element(*self._view_locator)
|
||||
Wait(self.marionette).until(lambda m: view.location['x'] == 0)
|
||||
|
||||
def type_to(self, value):
|
||||
self.marionette.find_element(*self._to_locator).tap()
|
||||
self.keyboard.send(value)
|
||||
self.keyboard.dismiss()
|
||||
|
||||
def type_cc(self, value):
|
||||
self.marionette.find_element(*self._cc_locator).tap()
|
||||
self.keyboard.send(value)
|
||||
self.keyboard.dismiss()
|
||||
|
||||
def type_bcc(self, value):
|
||||
self.marionette.find_element(*self._bcc_locator).tap()
|
||||
self.keyboard.send(value)
|
||||
self.keyboard.dismiss()
|
||||
|
||||
def type_subject(self, value):
|
||||
self.marionette.find_element(*self._subject_locator).tap()
|
||||
self.keyboard.send(value)
|
||||
self.keyboard.dismiss()
|
||||
|
||||
def type_body(self, value):
|
||||
self.marionette.find_element(*self._body_locator).tap()
|
||||
self.keyboard.send(value)
|
||||
self.keyboard.dismiss()
|
||||
|
||||
def tap_send(self):
|
||||
self.marionette.find_element(*self._send_locator).tap()
|
||||
from gaiatest.apps.email.app import Email
|
||||
email = Email(self.marionette)
|
||||
email.wait_for_message_list()
|
||||
return email
|
||||
69
gaia/tests/python/gaia-ui-tests/gaiatest/apps/email/regions/read_email.py
Executable file
69
gaia/tests/python/gaia-ui-tests/gaiatest/apps/email/regions/read_email.py
Executable file
|
|
@ -0,0 +1,69 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class ReadEmail(Base):
|
||||
|
||||
manifest_url = '{}email{}/manifest.webapp'.format(Base.DEFAULT_PROTOCOL,Base.DEFAULT_APP_HOSTNAME)
|
||||
|
||||
_body_locator = (By.CSS_SELECTOR, '.card.center .msg-body-content')
|
||||
_subject_locator = (By.CSS_SELECTOR, '.card.center .msg-envelope-subject')
|
||||
_senders_email_locator = (By.CSS_SELECTOR, '.msg-reader-header-label')
|
||||
|
||||
_delete_button_locator = (By.CSS_SELECTOR, '.msg-reader-action-toolbar .icon.msg-delete-btn')
|
||||
_star_button_locator = (By.CSS_SELECTOR, '.msg-reader-action-toolbar .icon.msg-star-btn')
|
||||
_mark_button_locator = (By.CSS_SELECTOR, '.msg-reader-action-toolbar .icon.msg-mark-read-btn')
|
||||
_move_button_locator = (By.CSS_SELECTOR, '.msg-reader-action-toolbar .icon.msg-move-btn')
|
||||
_reply_button_locator = (By.CSS_SELECTOR, '.msg-reader-action-toolbar .icon.msg-reply-btn')
|
||||
|
||||
_delete_approve_button_locator = (By.ID, 'msg-delete-ok')
|
||||
_delete_cancel_button_locator = (By.ID, 'msg-delete-cancel')
|
||||
_move_cancel_button_locator = (By.CSS_SELECTOR, '.full')
|
||||
_reply_cancel_button_locator = (By.CSS_SELECTOR, '.msg-reply-menu-cancel')
|
||||
|
||||
@property
|
||||
def body(self):
|
||||
return self.marionette.find_element(*self._body_locator).text
|
||||
|
||||
@property
|
||||
def subject(self):
|
||||
return self.marionette.find_element(*self._subject_locator).text
|
||||
|
||||
def wait_for_senders_email_displayed(self):
|
||||
Wait(self.marionette).until(lambda m: m.find_element(*self._senders_email_locator).text != '')
|
||||
|
||||
@property
|
||||
def senders_email(self):
|
||||
return self.marionette.find_element(*self._senders_email_locator).text
|
||||
|
||||
def tap_delete_button(self):
|
||||
self.marionette.find_element(*self._delete_button_locator).tap()
|
||||
|
||||
def tap_star_button(self):
|
||||
self.marionette.find_element(*self._star_button_locator).tap()
|
||||
|
||||
def tap_mark_button(self):
|
||||
self.marionette.find_element(*self._mark_button_locator).tap()
|
||||
|
||||
def tap_move_button(self):
|
||||
self.marionette.find_element(*self._move_button_locator).tap()
|
||||
|
||||
def tap_reply_button(self):
|
||||
self.marionette.find_element(*self._reply_button_locator).tap()
|
||||
|
||||
def approve_delete(self):
|
||||
self.marionette.find_element(*self._delete_approve_button_locator).tap()
|
||||
|
||||
def cancel_delete(self):
|
||||
self.marionette.find_element(*self._delete_cancel_button_locator).tap()
|
||||
|
||||
def cancel_move(self):
|
||||
self.marionette.find_element(*self._move_cancel_button_locator).tap()
|
||||
|
||||
def cancel_reply(self):
|
||||
self.marionette.find_element(*self._reply_cancel_button_locator).tap()
|
||||
73
gaia/tests/python/gaia-ui-tests/gaiatest/apps/email/regions/settings.py
Executable file
73
gaia/tests/python/gaia-ui-tests/gaiatest/apps/email/regions/settings.py
Executable file
|
|
@ -0,0 +1,73 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.base import PageRegion
|
||||
|
||||
|
||||
class Settings(Base):
|
||||
#general email settings
|
||||
_email_account_locator = (By.CSS_SELECTOR, '.tng-account-item')
|
||||
_account_add_locator = (By.CLASS_NAME, 'tng-account-add')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._email_account_locator))))
|
||||
|
||||
@property
|
||||
def email_accounts(self):
|
||||
return [self.Account(self.marionette, email_account) for email_account in self.marionette.find_elements(*self._email_account_locator)]
|
||||
|
||||
class Account(PageRegion):
|
||||
_name_locator = (By.CSS_SELECTOR, 'a.tng-account-item-label')
|
||||
|
||||
def tap(self):
|
||||
self.root_element.tap()
|
||||
return EmailAccountSettings(self.marionette)
|
||||
|
||||
def a11y_click(self):
|
||||
self.accessibility.click(self.root_element)
|
||||
return EmailAccountSettings(self.marionette)
|
||||
|
||||
|
||||
class EmailAccountSettings(Base):
|
||||
#settings for a specific email account
|
||||
|
||||
_delete_account_locator = (By.CSS_SELECTOR, '.tng-account-delete')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._delete_account_locator))))
|
||||
|
||||
def tap_delete(self):
|
||||
self.marionette.find_element(*self._delete_account_locator).tap()
|
||||
return DeleteConfirmation(self.marionette)
|
||||
|
||||
def a11y_click_delete(self):
|
||||
self.accessibility.click(self.marionette.find_element(*self._delete_account_locator))
|
||||
return DeleteConfirmation(self.marionette)
|
||||
|
||||
|
||||
class DeleteConfirmation(Base):
|
||||
_delete_locator = (By.CSS_SELECTOR, '.tng-account-delete-confirm #account-delete-ok')
|
||||
_cancel_locator = (By.CSS_SELECTOR, '.tng-account-delete-confirm #account-delete-cancel')
|
||||
_message_locator = (By.CSS_SELECTOR, '.tng-account-delete-confirm > section > p')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._delete_locator))))
|
||||
|
||||
def tap_delete(self):
|
||||
self.marionette.find_element(*self._delete_locator).tap()
|
||||
|
||||
def a11y_click_delete(self):
|
||||
self.accessibility.click(self.marionette.find_element(*self._delete_locator))
|
||||
201
gaia/tests/python/gaia-ui-tests/gaiatest/apps/email/regions/setup.py
Executable file
201
gaia/tests/python/gaia-ui-tests/gaiatest/apps/email/regions/setup.py
Executable file
|
|
@ -0,0 +1,201 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class SetupEmail(Base):
|
||||
|
||||
_name_locator = (By.CSS_SELECTOR, 'cards-setup-account-info input.sup-info-name')
|
||||
_email_locator = (By.CSS_SELECTOR, 'cards-setup-account-info input.sup-info-email')
|
||||
_next_locator = (By.CSS_SELECTOR, '.sup-info-next-btn')
|
||||
_continue_button_locator = ('class name', 'sup-show-mail-btn sup-form-btn recommend')
|
||||
_check_for_new_messages_locator = (By.CSS_SELECTOR, '.tng-account-check-interval.mail-select')
|
||||
_account_prefs_section_locator = (By.CSS_SELECTOR, 'cards-setup-account-prefs section')
|
||||
_account_prefs_next_locator = (By.CSS_SELECTOR, 'cards-setup-account-prefs .sup-info-next-btn')
|
||||
_done_section_locator = (By.CSS_SELECTOR, 'cards-setup-done section')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._name_locator))))
|
||||
|
||||
def type_name(self, value):
|
||||
self.marionette.find_element(*self._name_locator).send_keys(value)
|
||||
|
||||
def type_email(self, value):
|
||||
self.marionette.find_element(*self._email_locator).send_keys(value)
|
||||
|
||||
def tap_next(self):
|
||||
self.marionette.find_element(*self._next_locator).tap()
|
||||
|
||||
def tap_account_prefs_next(self):
|
||||
next = Wait(self.marionette, timeout=120).until(
|
||||
expected.element_present(*self._account_prefs_next_locator))
|
||||
Wait(self.marionette, timeout=120).until(
|
||||
expected.element_displayed(next))
|
||||
next.tap()
|
||||
|
||||
def wait_for_setup_complete(self):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._done_section_locator))
|
||||
Wait(self.marionette).until(lambda m: element.location['x'] == 0)
|
||||
|
||||
def tap_continue(self):
|
||||
self.marionette.find_element(*self._continue_button_locator).tap()
|
||||
|
||||
|
||||
class ManualSetupEmail(Base):
|
||||
|
||||
name = 'E-Mail' # hack to be able to use select
|
||||
|
||||
_name_locator = (By.CSS_SELECTOR, 'cards-setup-manual-config input.sup-info-name')
|
||||
_email_locator = (By.CSS_SELECTOR, 'cards-setup-manual-config input.sup-info-email')
|
||||
_password_locator = (By.CSS_SELECTOR, 'cards-setup-manual-config input.sup-info-password')
|
||||
|
||||
_account_type_locator = (By.CSS_SELECTOR, 'cards-setup-manual-config .sup-manual-account-type')
|
||||
|
||||
_imap_username_locator = (By.CSS_SELECTOR, 'cards-setup-manual-config .sup-manual-composite-username')
|
||||
_imap_password_locator = (By.CSS_SELECTOR, 'cards-setup-manual-config .sup-manual-composite-password')
|
||||
_imap_hostname_locator = (By.CSS_SELECTOR, 'cards-setup-manual-config .sup-manual-composite-hostname')
|
||||
_imap_port_locator = (By.CSS_SELECTOR, 'cards-setup-manual-config .sup-manual-composite-port')
|
||||
|
||||
_smtp_username_locator = (By.CSS_SELECTOR, 'cards-setup-manual-config .sup-manual-smtp-username')
|
||||
_smtp_password_locator = (By.CSS_SELECTOR, 'cards-setup-manual-config .sup-manual-smtp-password')
|
||||
_smtp_hostname_locator = (By.CSS_SELECTOR, 'cards-setup-manual-config .sup-manual-smtp-hostname')
|
||||
_smtp_port_locator = (By.CSS_SELECTOR, 'cards-setup-manual-config .sup-manual-smtp-port')
|
||||
|
||||
_activesync_hostname_locator = (By.CSS_SELECTOR, 'cards-setup-manual-config .sup-manual-activesync-hostname')
|
||||
_activesync_username_locator = (By.CSS_SELECTOR, 'cards-setup-manual-config .sup-manual-activesync-username')
|
||||
|
||||
_next_locator = (By.CSS_SELECTOR, '.sup-manual-next-btn')
|
||||
_continue_button_locator = (By.CLASS_NAME, 'sup-show-mail-btn sup-form-btn recommend')
|
||||
|
||||
_check_for_new_messages_locator = (By.CSS_SELECTOR, '.tng-account-check-interval.mail-select')
|
||||
_account_prefs_section_locator = (By.CSS_SELECTOR, 'cards-setup-account-prefs')
|
||||
_account_prefs_next_locator = (By.CSS_SELECTOR, 'cards-setup-account-prefs .sup-info-next-btn')
|
||||
_done_section_locator = (By.CSS_SELECTOR, 'cards-setup-done section')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._name_locator))))
|
||||
|
||||
def type_name(self, value):
|
||||
el = self.marionette.find_element(*self._name_locator)
|
||||
el.clear()
|
||||
el.send_keys(value)
|
||||
self.keyboard.dismiss()
|
||||
|
||||
def type_email(self, value):
|
||||
el = self.marionette.find_element(*self._email_locator)
|
||||
el.clear()
|
||||
el.send_keys(value)
|
||||
self.keyboard.dismiss()
|
||||
|
||||
def type_password(self, value):
|
||||
el = self.marionette.find_element(*self._password_locator)
|
||||
el.clear()
|
||||
el.send_keys(value)
|
||||
self.keyboard.dismiss()
|
||||
|
||||
def select_account_type(self, value):
|
||||
account_type = self.marionette.find_element(*self._account_type_locator)
|
||||
account_type.click()
|
||||
self.marionette.switch_to_frame()
|
||||
self.select(value)
|
||||
|
||||
def type_imap_name(self, value):
|
||||
el = self.marionette.find_element(*self._imap_username_locator)
|
||||
el.clear()
|
||||
el.send_keys(value)
|
||||
|
||||
def type_imap_hostname(self, value):
|
||||
el = self.marionette.find_element(*self._imap_hostname_locator)
|
||||
el.clear()
|
||||
el.send_keys(value)
|
||||
|
||||
def type_imap_password(self, value):
|
||||
el = self.marionette.find_element(*self._imap_password_locator)
|
||||
el.clear()
|
||||
el.send_keys(value)
|
||||
|
||||
def type_imap_port(self, value):
|
||||
el = self.marionette.find_element(*self._imap_port_locator)
|
||||
el.clear()
|
||||
el.send_keys(value)
|
||||
|
||||
def type_smtp_name(self, value):
|
||||
el = self.marionette.find_element(*self._smtp_username_locator)
|
||||
el.clear()
|
||||
el.send_keys(value)
|
||||
|
||||
def type_smtp_hostname(self, value):
|
||||
el = self.marionette.find_element(*self._smtp_hostname_locator)
|
||||
el.clear()
|
||||
el.send_keys(value)
|
||||
|
||||
def type_smtp_password(self, value):
|
||||
el = self.marionette.find_element(*self._smtp_password_locator)
|
||||
el.clear()
|
||||
el.send_keys(value)
|
||||
|
||||
def type_smtp_port(self, value):
|
||||
el = self.marionette.find_element(*self._smtp_port_locator)
|
||||
el.clear()
|
||||
el.send_keys(value)
|
||||
self.keyboard.dismiss()
|
||||
|
||||
def type_activesync_name(self, value):
|
||||
el = self.marionette.find_element(*self._activesync_username_locator)
|
||||
el.clear()
|
||||
el.send_keys(value)
|
||||
self.keyboard.dismiss()
|
||||
|
||||
def type_activesync_hostname(self, value):
|
||||
el = self.marionette.find_element(*self._activesync_hostname_locator)
|
||||
el.clear()
|
||||
el.send_keys(value)
|
||||
|
||||
def tap_next(self):
|
||||
next = Wait(self.marionette).until(expected.element_present(*self._next_locator))
|
||||
Wait(self.marionette).until(lambda m: next.get_attribute('disabled') != 'true')
|
||||
next.tap()
|
||||
|
||||
account = Wait(self.marionette).until(
|
||||
expected.element_present(*self._account_prefs_section_locator))
|
||||
Wait(self.marionette).until(lambda m: account.location['x'] == 0)
|
||||
|
||||
Wait(self.marionette, timeout=120).until(expected.element_displayed(
|
||||
Wait(self.marionette, timeout=120).until(expected.element_present(
|
||||
*self._account_prefs_next_locator))))
|
||||
|
||||
def check_for_emails_interval(self, value):
|
||||
# The following pref change allows us to check the mail within 1 second or longer,
|
||||
# rather than the default value of 100 seconds
|
||||
# The UI data layer of the UI is changed, because the minimum check mail time value is 5 min,
|
||||
# which is far too long to check for in a test. This allows us to check earlier
|
||||
with self.marionette.using_context('chrome'):
|
||||
self.marionette.execute_script(
|
||||
"Services.prefs.setIntPref('dom.requestSync.minInterval', 1);")
|
||||
self.marionette.execute_script("""
|
||||
document.querySelector("[data-l10n-id = settings-check-every-5min]").value = '%s';
|
||||
""" % value)
|
||||
self.marionette.find_element(*self._check_for_new_messages_locator).tap()
|
||||
self.select('Every 5 minutes')
|
||||
|
||||
def tap_account_prefs_next(self):
|
||||
self.marionette.find_element(*self._account_prefs_next_locator).tap()
|
||||
|
||||
def wait_for_setup_complete(self):
|
||||
done = Wait(self.marionette).until(
|
||||
expected.element_present(*self._done_section_locator))
|
||||
Wait(self.marionette).until(lambda m: done.location['x'] == 0)
|
||||
|
||||
def tap_continue(self):
|
||||
self.marionette.find_element(*self._continue_button_locator).tap()
|
||||
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/emergency_call/__init__.py
Executable file
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/emergency_call/__init__.py
Executable file
34
gaia/tests/python/gaia-ui-tests/gaiatest/apps/emergency_call/app.py
Executable file
34
gaia/tests/python/gaia-ui-tests/gaiatest/apps/emergency_call/app.py
Executable file
|
|
@ -0,0 +1,34 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class EmergencyCall(Base):
|
||||
|
||||
_emergency_frame_locator = (By.CSS_SELECTOR, ".secureAppWindow.active[data-manifest-name='EmergencyCall'] iframe")
|
||||
_emergency_dialer_keypad_locator = (By.ID, 'keypad')
|
||||
_emergency_call_only_title_locator = (By.CSS_SELECTOR, 'h1[data-l10n-id="emergency-call-only"]')
|
||||
|
||||
@property
|
||||
def keypad(self):
|
||||
from gaiatest.apps.phone.regions.keypad import BaseKeypad
|
||||
return BaseKeypad(self.marionette)
|
||||
|
||||
def switch_to_emergency_call_frame(self):
|
||||
frame = Wait(self.marionette).until(
|
||||
expected.element_present(*self._emergency_frame_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(frame))
|
||||
self.marionette.switch_to_frame(frame)
|
||||
|
||||
@property
|
||||
def is_emergency_dialer_keypad_displayed(self):
|
||||
return self.marionette.find_element(
|
||||
*self._emergency_dialer_keypad_locator).is_displayed()
|
||||
|
||||
@property
|
||||
def is_emergency_call_only_title_displayed(self):
|
||||
return self.marionette.find_element(*self._emergency_call_only_title_locator).is_displayed()
|
||||
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/fmradio/__init__.py
Executable file
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/fmradio/__init__.py
Executable file
111
gaia/tests/python/gaia-ui-tests/gaiatest/apps/fmradio/app.py
Executable file
111
gaia/tests/python/gaia-ui-tests/gaiatest/apps/fmradio/app.py
Executable file
|
|
@ -0,0 +1,111 @@
|
|||
# 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 re
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
from marionette_driver.marionette import Actions
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.base import PageRegion
|
||||
|
||||
|
||||
class FmRadio(Base):
|
||||
name = 'FM Radio'
|
||||
manifest_url = '{}fm{}/manifest.webapp'.format(Base.DEFAULT_PROTOCOL,Base.DEFAULT_APP_HOSTNAME)
|
||||
|
||||
_power_button_locator = (By.ID, 'power-switch')
|
||||
_favorite_list_locator = (By.CSS_SELECTOR, 'div.fav-list-item')
|
||||
_frequency_display_locator = (By.ID, 'frequency')
|
||||
_frequency_dialer_locator = (By.ID, 'dialer-bar')
|
||||
_favorite_button_locator = (By.ID, 'bookmark-button')
|
||||
_next_button_locator = (By.ID, 'frequency-op-seekup')
|
||||
_prev_button_locator = (By.ID, 'frequency-op-seekdown')
|
||||
_airplane_mode_title_locator = (By.CSS_SELECTOR, 'div[data-l10n-id="airplaneModeHeader"]')
|
||||
_airplane_mode_text_locator = (By.CSS_SELECTOR, 'div[data-l10n-id="airplaneModeMsg"]')
|
||||
|
||||
|
||||
def launch(self, airplane_mode=False):
|
||||
Base.launch(self)
|
||||
power = Wait(self.marionette).until(
|
||||
expected.element_present(*self._power_button_locator))
|
||||
if not airplane_mode:
|
||||
Wait(self.marionette).until(lambda m: power.get_attribute('data-enabled') == 'true')
|
||||
|
||||
@property
|
||||
def airplane_warning_title(self):
|
||||
return self.marionette.find_element(*self._airplane_mode_title_locator).text
|
||||
|
||||
@property
|
||||
def airplane_warning_text(self):
|
||||
return self.marionette.find_element(*self._airplane_mode_text_locator).text
|
||||
|
||||
def flick_frequency_dialer_up(self):
|
||||
dialer = self.marionette.find_element(*self._frequency_dialer_locator)
|
||||
|
||||
dialer_x_center = int(dialer.size['width'] / 2)
|
||||
dialer_y_center = int(dialer.size['height'] / 2)
|
||||
Actions(self.marionette).flick(dialer, dialer_x_center, dialer_y_center, 0, 800, 800).perform()
|
||||
|
||||
def tap_next(self):
|
||||
frequency = Wait(self.marionette).until(
|
||||
expected.element_present(*self._frequency_display_locator))
|
||||
current = frequency.text
|
||||
self.marionette.find_element(*self._next_button_locator).tap()
|
||||
Wait(self.marionette).until(lambda m: frequency.text != current)
|
||||
|
||||
def tap_previous(self):
|
||||
frequency = Wait(self.marionette).until(
|
||||
expected.element_present(*self._frequency_display_locator))
|
||||
current = frequency.text
|
||||
self.marionette.find_element(*self._prev_button_locator).tap()
|
||||
Wait(self.marionette).until(lambda m: frequency.text != current)
|
||||
|
||||
def tap_power_button(self):
|
||||
self.marionette.find_element(*self._power_button_locator).tap()
|
||||
|
||||
def wait_for_radio_off(self):
|
||||
power = Wait(self.marionette).until(
|
||||
expected.element_present(*self._power_button_locator))
|
||||
Wait(self.marionette).until(
|
||||
lambda m: not power.get_attribute('data-enabled') == 'true')
|
||||
|
||||
def tap_add_favorite(self):
|
||||
current = len(self.favorite_channels)
|
||||
self.marionette.find_element(*self._favorite_button_locator).tap()
|
||||
Wait(self.marionette).until(
|
||||
lambda m: len(self.favorite_channels) == current + 1)
|
||||
|
||||
@property
|
||||
def is_power_button_on(self):
|
||||
return self.marionette.find_element(*self._power_button_locator).get_attribute('data-enabled') == 'true'
|
||||
|
||||
@property
|
||||
def frequency(self):
|
||||
raw_frequency = self.marionette.find_element(*self._frequency_display_locator).text
|
||||
return float(self._crop_trailing_mhz_and_invisible_characters(raw_frequency))
|
||||
|
||||
@staticmethod
|
||||
def _crop_trailing_mhz_and_invisible_characters(raw_frequency):
|
||||
match = re.search(r'\d+\.\d', raw_frequency)
|
||||
frequency = match.group()
|
||||
return frequency
|
||||
|
||||
@property
|
||||
def favorite_channels(self):
|
||||
return [self.FavoriteChannel(self.marionette, channel) for channel in self.marionette.find_elements(*self._favorite_list_locator)]
|
||||
|
||||
class FavoriteChannel(PageRegion):
|
||||
_remove_locator = (By.CSS_SELECTOR, 'div.fav-list-remove-button')
|
||||
_frequency_locator = (By.CSS_SELECTOR, 'div.fav-list-frequency')
|
||||
|
||||
@property
|
||||
def text(self):
|
||||
raw_frequency = self.root_element.find_element(*self._frequency_locator).text
|
||||
return float(FmRadio._crop_trailing_mhz_and_invisible_characters(raw_frequency))
|
||||
|
||||
def remove(self):
|
||||
frequency = self.marionette.find_element(*self._frequency_locator)
|
||||
self.root_element.find_element(*self._remove_locator).tap()
|
||||
Wait(self.marionette).until(expected.element_not_displayed(frequency))
|
||||
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/ftu/__init__.py
Executable file
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/ftu/__init__.py
Executable file
465
gaia/tests/python/gaia-ui-tests/gaiatest/apps/ftu/app.py
Executable file
465
gaia/tests/python/gaia-ui-tests/gaiatest/apps/ftu/app.py
Executable file
|
|
@ -0,0 +1,465 @@
|
|||
# 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 re
|
||||
import time
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.form_controls.binarycontrol import GaiaBinaryControl
|
||||
|
||||
|
||||
class Ftu(Base):
|
||||
|
||||
name = 'FTU'
|
||||
|
||||
_next_button_locator = (By.ID, 'forward')
|
||||
|
||||
# Step Languages section
|
||||
_section_languages_locator = (By.ID, 'languages')
|
||||
_listed_languages_locator = (By.CSS_SELECTOR, "#languages ul li")
|
||||
_language_locator = (By.CSS_SELECTOR, "#languages ul li[data-value='%s']")
|
||||
_language_input_locator = (By.CSS_SELECTOR,
|
||||
"#languages ul li gaia-radio[name='language.current'][value='%s']")
|
||||
_selected_language_input_locator = (By.CSS_SELECTOR, "#languages ul li gaia-radio:checked")
|
||||
|
||||
# Step Cell data section
|
||||
_section_cell_data_locator = (By.ID, 'data_3g')
|
||||
_enable_data_checkbox_locator = (By.ID, 'data-connection-switch')
|
||||
|
||||
# Step Wifi
|
||||
_section_wifi_locator = (By.ID, 'wifi')
|
||||
_found_wifi_networks_locator = (By.CSS_SELECTOR, 'ul#networks-list li')
|
||||
_password_input_locator = (By.ID, 'wifi_password')
|
||||
_join_network_locator = (By.ID, 'wifi-join-button')
|
||||
_loading_overlay_locator = (By.ID, 'loading-overlay')
|
||||
|
||||
# Step Date & Time
|
||||
_section_date_time_locator = (By.ID, 'date_and_time')
|
||||
_timezone_continent_locator = (By.CSS_SELECTOR, '#time-form li:nth-child(1) > .change.icon.icon-dialog')
|
||||
_timezone_city_locator = (By.CSS_SELECTOR, '#time-form li:nth-child(2) > .change.icon.icon-dialog')
|
||||
_time_zone_title_locator = (By.ID, 'time-zone-title')
|
||||
|
||||
# Step Geolocation
|
||||
_section_geolocation_locator = (By.ID, 'geolocation')
|
||||
_enable_geolocation_checkbox_locator = (By.ID, 'geolocation-switch')
|
||||
|
||||
# Section Import contacts
|
||||
_section_import_contacts_locator = (By.ID, 'import_contacts')
|
||||
_import_from_sim_locator = (By.ID, 'sim-import-button')
|
||||
_sim_import_feedback_locator = (By.ID, 'statusMsg')
|
||||
|
||||
# Step Firefox Accounts
|
||||
_section_firefox_accounts_locator = (By.ID, 'firefox_accounts')
|
||||
|
||||
# Section late customization
|
||||
_section_late_customization_locator = (By.ID, 'late_customization')
|
||||
|
||||
# Section Welcome Browser
|
||||
_section_welcome_browser_locator = (By.ID, 'welcome_browser')
|
||||
_metrics_basic_locator = (By.ID, 'metrics-basic')
|
||||
_metrics_enhanced_locator = (By.ID, 'metrics-enhanced')
|
||||
_metrics_none_locator = (By.ID, 'metrics-none')
|
||||
|
||||
# Section Privacy Choices
|
||||
_section_browser_privacy_locator = (By.ID, 'browser_privacy')
|
||||
_email_field_locator = (By.CSS_SELECTOR, 'input[type="email"]')
|
||||
|
||||
# Section Finish
|
||||
_section_finish_locator = (By.ID, 'finish-screen')
|
||||
_skip_tour_button_locator = (By.ID, 'skip-tutorial-button')
|
||||
_take_tour_button_locator = (By.ID, 'lets-go-button')
|
||||
|
||||
# Section Tour
|
||||
_step_header_locator = (By.ID, 'tutorial-step-title')
|
||||
_tour_next_button_locator = (By.ID, 'forward-tutorial')
|
||||
_tour_back_button_locator = (By.ID, 'back-tutorial')
|
||||
|
||||
# Section Tutorial Finish
|
||||
_section_tutorial_finish_locator = (By.ID, 'tutorial-finish-tiny')
|
||||
_lets_go_button_locator = (By.ID, 'tutorialFinished')
|
||||
|
||||
# Pattern for import sim contacts message
|
||||
_pattern_contacts = re.compile("^No contacts detected on SIM to import$|^Imported one contact$|^Imported [0-9]+ contacts$")
|
||||
_pattern_contacts_0 = re.compile("^No contacts detected on SIM to import$")
|
||||
_pattern_contacts_1 = re.compile("^Imported one contact$")
|
||||
_pattern_contacts_N = re.compile("^Imported ([0-9]+) contacts$")
|
||||
|
||||
def launch(self):
|
||||
Base.launch(self)
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._section_languages_locator))
|
||||
|
||||
@property
|
||||
def languages_list(self):
|
||||
return len(self.marionette.find_elements(*self._listed_languages_locator))
|
||||
|
||||
@property
|
||||
def selected_language(self):
|
||||
return self.marionette.find_element(*self._selected_language_input_locator).get_attribute(
|
||||
'value')
|
||||
|
||||
def tap_language(self, language):
|
||||
self.marionette.find_element(self._language_locator[0], self._language_locator[1] % language).tap()
|
||||
|
||||
def a11y_click_language(self, language):
|
||||
self.accessibility.click(self.marionette.find_element(self._language_input_locator[0],
|
||||
self._language_input_locator[1] % language))
|
||||
|
||||
@property
|
||||
def is_take_tour_button_visible(self):
|
||||
return self.is_element_displayed(*self._take_tour_button_locator)
|
||||
|
||||
@property
|
||||
def is_lets_go_button_visible(self):
|
||||
return self.is_element_displayed(*self._lets_go_button_locator)
|
||||
|
||||
def tap_next(self):
|
||||
next_button = Wait(self.marionette).until(
|
||||
expected.element_present(*self._next_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(next_button))
|
||||
Wait(self.marionette).until(expected.element_enabled(next_button))
|
||||
# In b2g desktop builds, this sleep prevents intermittent failures
|
||||
time.sleep(0.2)
|
||||
next_button.tap()
|
||||
|
||||
def a11y_click_next(self):
|
||||
self.accessibility.click(self.marionette.find_element(*self._next_button_locator))
|
||||
|
||||
def tap_next_to_cell_data_section(self):
|
||||
self.tap_next()
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._section_cell_data_locator))
|
||||
|
||||
def a11y_click_next_to_cell_data_section(self):
|
||||
self.a11y_click_next()
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._section_cell_data_locator))
|
||||
|
||||
def enable_data(self):
|
||||
checkbox = Wait(self.marionette).until(
|
||||
expected.element_present(*self._enable_data_checkbox_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(checkbox))
|
||||
checkbox.tap()
|
||||
|
||||
def a11y_enable_data(self):
|
||||
checkbox = Wait(self.marionette).until(
|
||||
expected.element_present(*self._enable_data_checkbox_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(checkbox))
|
||||
self.accessibility.click(checkbox)
|
||||
|
||||
def tap_next_to_wifi_section(self):
|
||||
progress = self.marionette.find_element(*self._loading_overlay_locator)
|
||||
self.tap_next()
|
||||
Wait(self.marionette).until(expected.element_not_displayed(progress))
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._section_wifi_locator))
|
||||
|
||||
def a11y_click_next_to_wifi_section(self):
|
||||
self.a11y_click_next()
|
||||
Wait(self.marionette).until(
|
||||
expected.element_not_displayed(*self._loading_overlay_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._section_wifi_locator))
|
||||
|
||||
def wait_for_networks_available(self):
|
||||
Wait(self.marionette).until(lambda m: len(m.find_elements(
|
||||
*self._found_wifi_networks_locator)) > 0,
|
||||
message='No networks listed on screen')
|
||||
|
||||
def find_wifi_network(self, network_ssid):
|
||||
wifi_network_locator = (By.CSS_SELECTOR, '#networks-list li[data-ssid="%s"]' % network_ssid)
|
||||
wifi_network = Wait(self.marionette).until(
|
||||
expected.element_present(*wifi_network_locator))
|
||||
self.marionette.execute_script("arguments[0].scrollIntoView(false);", [wifi_network])
|
||||
Wait(self.marionette).until(expected.element_displayed(wifi_network))
|
||||
return wifi_network
|
||||
|
||||
def connect_to_wifi(self, network_ssid, password, key_management=None):
|
||||
wifi_network = self.find_wifi_network(network_ssid)
|
||||
wifi_network.tap()
|
||||
|
||||
# This is in the event we are using a Wifi Network that requires a password
|
||||
# We cannot be sure of this thus need the logic
|
||||
if key_management:
|
||||
password_element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._password_input_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(password_element))
|
||||
password_element.send_keys(password)
|
||||
self.marionette.find_element(*self._join_network_locator).tap()
|
||||
|
||||
def a11y_connect_to_wifi(self, network_ssid, password, key_management=None):
|
||||
wifi_network = self.find_wifi_network(network_ssid)
|
||||
self.accessibility.click(wifi_network)
|
||||
|
||||
# This is in the event we are using a Wifi Network that requires a password
|
||||
# We cannot be sure of this thus need the logic
|
||||
if key_management:
|
||||
password_element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._password_input_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(password_element))
|
||||
password_element.send_keys(password)
|
||||
self.accessibility.click(self.marionette.find_element(*self._join_network_locator))
|
||||
|
||||
def tap_next_to_timezone_section(self):
|
||||
self.tap_next()
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._section_date_time_locator))
|
||||
|
||||
def a11y_click_next_to_timezone_section(self):
|
||||
self.a11y_click_next()
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._section_date_time_locator))
|
||||
|
||||
def set_timezone_continent(self, continent):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._timezone_continent_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
element.tap()
|
||||
self.select(continent)
|
||||
|
||||
def a11y_set_timezone_continent(self, continent):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._timezone_continent_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
self.accessibility.click(element)
|
||||
self.a11y_select(continent)
|
||||
|
||||
def set_timezone_city(self, city):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._timezone_city_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
element.tap()
|
||||
self.select(city)
|
||||
|
||||
def a11y_set_timezone_city(self, city):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._timezone_city_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
self.accessibility.click(element)
|
||||
self.a11y_select(city)
|
||||
|
||||
@property
|
||||
def timezone_title(self):
|
||||
return self.marionette.find_element(*self._time_zone_title_locator).text
|
||||
|
||||
def tap_next_to_geolocation_section(self):
|
||||
self.tap_next()
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._section_geolocation_locator))
|
||||
|
||||
def a11y_click_next_to_geolocation_section(self):
|
||||
self.a11y_click_next()
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._section_geolocation_locator))
|
||||
|
||||
def disable_geolocation(self):
|
||||
self._geolocation_switch.disable()
|
||||
|
||||
@property
|
||||
def is_geolocation_enabled(self):
|
||||
return self._geolocation_switch.is_checked
|
||||
|
||||
@property
|
||||
def _geolocation_switch(self):
|
||||
return GaiaBinaryControl(self.marionette, self._enable_geolocation_checkbox_locator)
|
||||
|
||||
def a11y_disable_geolocation(self):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._enable_geolocation_checkbox_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
self.accessibility.click(element)
|
||||
|
||||
def tap_next_to_import_contacts_section(self):
|
||||
self.tap_next()
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._section_import_contacts_locator))
|
||||
|
||||
def a11y_click_next_to_import_contacts_section(self):
|
||||
self.a11y_click_next()
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._section_import_contacts_locator))
|
||||
|
||||
def tap_import_from_sim(self):
|
||||
self.marionette.find_element(*self._import_from_sim_locator).tap()
|
||||
|
||||
def wait_for_contacts_imported(self):
|
||||
feedback = self.marionette.find_element(
|
||||
*self._sim_import_feedback_locator)
|
||||
Wait(self.marionette).until(
|
||||
lambda m: self._pattern_contacts.match(feedback.text) is not None,
|
||||
message='Contact did not import from sim before timeout')
|
||||
|
||||
@property
|
||||
def count_imported_contacts(self):
|
||||
import_sim_message = self.marionette.find_element(*self._sim_import_feedback_locator).text
|
||||
import_sim_count = None
|
||||
if self._pattern_contacts_0.match(import_sim_message) is not None:
|
||||
import_sim_count = 0
|
||||
elif self._pattern_contacts_1.match(import_sim_message) is not None:
|
||||
import_sim_count = 1
|
||||
elif self._pattern_contacts_N.match(import_sim_message) is not None:
|
||||
count = self._pattern_contacts_N.match(import_sim_message).group(1)
|
||||
import_sim_count = int(count)
|
||||
return import_sim_count
|
||||
|
||||
def tap_next_to_firefox_accounts_section(self):
|
||||
self.tap_next()
|
||||
Wait(self.marionette).until(
|
||||
expected.element_displayed(*self._section_firefox_accounts_locator))
|
||||
|
||||
def a11y_click_next_to_firefox_accounts_section(self):
|
||||
self.a11y_click_next()
|
||||
Wait(self.marionette).until(
|
||||
expected.element_displayed(*self._section_firefox_accounts_locator))
|
||||
|
||||
def tap_next_to_late_customization_section(self):
|
||||
self.tap_next()
|
||||
Wait(self.marionette).until(
|
||||
expected.element_displayed(*self._section_late_customization_locator))
|
||||
|
||||
def tap_next_to_welcome_browser_section(self):
|
||||
self.tap_next()
|
||||
Wait(self.marionette).until(
|
||||
expected.element_displayed(*self._section_welcome_browser_locator))
|
||||
|
||||
def a11y_click_next_to_welcome_browser_section(self):
|
||||
self.a11y_click_next()
|
||||
Wait(self.marionette).until(
|
||||
expected.element_displayed(*self._section_welcome_browser_locator))
|
||||
|
||||
@property
|
||||
def is_metrics_basic_enabled(self):
|
||||
return self._metrics_basic_radio.is_checked
|
||||
|
||||
def enable_metrics_basic(self):
|
||||
self._metrics_basic_radio.enable()
|
||||
|
||||
@property
|
||||
def _metrics_basic_radio(self):
|
||||
return GaiaBinaryControl(self.marionette, self._metrics_basic_locator)
|
||||
|
||||
@property
|
||||
def is_metrics_enhanced_enabled(self):
|
||||
return self._metrics_enhanced_radio.is_checked
|
||||
|
||||
def enable_metrics_enhanced(self):
|
||||
self._metrics_enhanced_radio.enable()
|
||||
|
||||
@property
|
||||
def _metrics_enhanced_radio(self):
|
||||
return GaiaBinaryControl(self.marionette, self._metrics_enhanced_locator)
|
||||
|
||||
@property
|
||||
def is_metrics_none_enabled(self):
|
||||
return self._metrics_none_radio.is_checked
|
||||
|
||||
def enable_metrics_none(self):
|
||||
self._metrics_none_radio.enable()
|
||||
|
||||
@property
|
||||
def _metrics_none_radio(self):
|
||||
return GaiaBinaryControl(self.marionette, self._metrics_none_locator)
|
||||
|
||||
def tap_next_to_privacy_browser_section(self):
|
||||
self.tap_next()
|
||||
Wait(self.marionette).until(
|
||||
expected.element_displayed(*self._section_browser_privacy_locator))
|
||||
|
||||
def a11y_click_next_to_privacy_browser_section(self):
|
||||
self.a11y_click_next()
|
||||
Wait(self.marionette).until(
|
||||
expected.element_displayed(*self._section_browser_privacy_locator))
|
||||
|
||||
def enter_email_address(self, email):
|
||||
# TODO assert that this is preserved in the system somewhere. Currently it is not used
|
||||
self.marionette.find_element(*self._email_field_locator).send_keys(email)
|
||||
self.marionette.switch_to_frame()
|
||||
Wait(self.marionette).until(lambda m: self.keyboard.is_keyboard_displayed)
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def tap_next_to_finish_section(self):
|
||||
self.tap_next()
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._section_finish_locator))
|
||||
|
||||
def a11y_click_next_to_finish_section(self):
|
||||
self.a11y_click_next()
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._section_finish_locator))
|
||||
|
||||
def tap_skip_tour(self):
|
||||
element = self.marionette.find_element(*self._skip_tour_button_locator)
|
||||
self.tap_element_from_system_app(element, add_statusbar_height=True)
|
||||
|
||||
def a11y_click_skip_tour(self):
|
||||
self.accessibility.click(self.marionette.find_element(*self._skip_tour_button_locator))
|
||||
|
||||
def run_ftu_setup_with_default_values(self):
|
||||
count = 0
|
||||
while not self.is_element_displayed(*self._take_tour_button_locator):
|
||||
if self.is_element_displayed(*self._next_button_locator):
|
||||
self.tap_next()
|
||||
else:
|
||||
count = count + 1
|
||||
if count > 5:
|
||||
break
|
||||
|
||||
def tap_take_tour(self):
|
||||
take_tour = Wait(self.marionette).until(
|
||||
expected.element_present(*self._take_tour_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(take_tour))
|
||||
Wait(self.marionette).until(expected.element_enabled(take_tour))
|
||||
take_tour.tap()
|
||||
|
||||
@property
|
||||
def step1_header_text(self):
|
||||
header = Wait(self.marionette).until(
|
||||
expected.element_present(*self._step_header_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(header))
|
||||
return header.text
|
||||
|
||||
def tap_tour_next(self):
|
||||
next = Wait(self.marionette).until(
|
||||
expected.element_present(*self._tour_next_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(next))
|
||||
Wait(self.marionette).until(expected.element_enabled(next))
|
||||
next.tap()
|
||||
|
||||
def tap_back(self):
|
||||
back = Wait(self.marionette).until(
|
||||
expected.element_present(*self._tour_back_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(back))
|
||||
back.tap()
|
||||
|
||||
@property
|
||||
def step2_header_text(self):
|
||||
header = Wait(self.marionette).until(
|
||||
expected.element_present(*self._step_header_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(header))
|
||||
return header.text
|
||||
|
||||
@property
|
||||
def step3_header_text(self):
|
||||
header = Wait(self.marionette).until(
|
||||
expected.element_present(*self._step_header_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(header))
|
||||
return header.text
|
||||
|
||||
@property
|
||||
def step4_header_text(self):
|
||||
header = Wait(self.marionette).until(
|
||||
expected.element_present(*self._step_header_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(header))
|
||||
return header.text
|
||||
|
||||
@property
|
||||
def step5_header_text(self):
|
||||
header = Wait(self.marionette).until(
|
||||
expected.element_present(*self._step_header_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(header))
|
||||
return header.text
|
||||
|
||||
@property
|
||||
def step6_header_text(self):
|
||||
header = Wait(self.marionette).until(
|
||||
expected.element_present(*self._step_header_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(header))
|
||||
return header.text
|
||||
|
||||
def wait_for_finish_tutorial_section(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._section_tutorial_finish_locator))))
|
||||
|
||||
def tap_lets_go_button(self):
|
||||
element = self.marionette.find_element(*self._lets_go_button_locator)
|
||||
self.tap_element_from_system_app(element, add_statusbar_height=True)
|
||||
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/gallery/__init__.py
Executable file
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/gallery/__init__.py
Executable file
109
gaia/tests/python/gaia-ui-tests/gaiatest/apps/gallery/app.py
Executable file
109
gaia/tests/python/gaia-ui-tests/gaiatest/apps/gallery/app.py
Executable file
|
|
@ -0,0 +1,109 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.base import PageRegion
|
||||
|
||||
import gaiatest.apps.camera.app
|
||||
|
||||
|
||||
class Gallery(Base):
|
||||
|
||||
name = 'Gallery'
|
||||
|
||||
_gallery_items_locator = (By.CSS_SELECTOR, 'div.thumbnail')
|
||||
_overlay_locator = (By.ID, 'overlay')
|
||||
_empty_gallery_title_locator = (By.ID, 'overlay-title')
|
||||
_empty_gallery_text_locator = (By.ID, 'overlay-text')
|
||||
_progress_bar_locator = (By.ID, 'progress')
|
||||
_thumbnail_list_view_locator = (By.CSS_SELECTOR, '#thumbnail-views > footer.thumbnails-list')
|
||||
_switch_to_camera_button_locator = (By.ID, 'thumbnails-camera-button')
|
||||
_switch_to_multiple_selection_view_locator = (By.ID, 'thumbnails-select-button')
|
||||
|
||||
def launch(self, empty=False):
|
||||
Base.launch(self)
|
||||
if empty:
|
||||
self.wait_for_overlay_to_show()
|
||||
else:
|
||||
self.wait_for_thumbnail_view_to_load()
|
||||
|
||||
def wait_for_thumbnail_view_to_load(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._thumbnail_list_view_locator))
|
||||
|
||||
def wait_for_overlay_to_show(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._overlay_locator))
|
||||
|
||||
def wait_for_files_to_load(self, files_number):
|
||||
Wait(self.marionette).until(lambda m: m.execute_script(
|
||||
'return window.wrappedJSObject.files.length;') == files_number)
|
||||
|
||||
def wait_for_thumbnails_to_load(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._gallery_items_locator))
|
||||
|
||||
@property
|
||||
def gallery_items_number(self):
|
||||
return len(self.thumbnails)
|
||||
|
||||
def tap_first_gallery_item(self):
|
||||
first_gallery_item = self.thumbnails[0]
|
||||
if self.is_element_displayed(*self._thumbnail_list_view_locator):
|
||||
from gaiatest.apps.gallery.regions.fullscreen_image import FullscreenImage as NextView
|
||||
else:
|
||||
from gaiatest.apps.gallery.regions.crop_view import CropView as NextView
|
||||
first_gallery_item.tap()
|
||||
return NextView(self.marionette)
|
||||
|
||||
@property
|
||||
def empty_gallery_title(self):
|
||||
return self.marionette.find_element(*self._empty_gallery_title_locator).text
|
||||
|
||||
@property
|
||||
def empty_gallery_text(self):
|
||||
return self.marionette.find_element(*self._empty_gallery_text_locator).text
|
||||
|
||||
@property
|
||||
def are_gallery_items_displayed(self):
|
||||
return self.is_element_displayed(*self._gallery_items_locator)
|
||||
|
||||
@property
|
||||
def thumbnails(self):
|
||||
if self.are_gallery_items_displayed:
|
||||
return [self.Thumbnail(self.marionette, thumbnail, index)
|
||||
for index, thumbnail in enumerate(self.marionette.find_elements(*self._gallery_items_locator))]
|
||||
else:
|
||||
return []
|
||||
|
||||
def switch_to_camera(self):
|
||||
switch_to_camera_button = self.marionette.find_element(*self._switch_to_camera_button_locator)
|
||||
switch_to_camera_button.tap()
|
||||
camera_app = gaiatest.apps.camera.app.Camera(self.marionette)
|
||||
camera_app.wait_to_be_displayed()
|
||||
self.apps.switch_to_displayed_app()
|
||||
return camera_app
|
||||
|
||||
def switch_to_multiple_selection_view(self):
|
||||
self.marionette.find_element(*self._switch_to_multiple_selection_view_locator).tap()
|
||||
from gaiatest.apps.gallery.regions.multiple_selection_view import MultipleSelectionView
|
||||
return MultipleSelectionView(self.marionette)
|
||||
|
||||
class Thumbnail(PageRegion):
|
||||
|
||||
def __init__(self, marionette, element, index):
|
||||
self.root_element = element
|
||||
# Save the index of the element so we can match it to the js files object
|
||||
self.index = index
|
||||
Base.__init__(self, marionette)
|
||||
|
||||
@property
|
||||
def absolute_image_size(self):
|
||||
'''
|
||||
The dimensions of the image on disk, is drawn from the image's metadata
|
||||
'''
|
||||
return {"height": self.marionette.execute_script('return window.wrappedJSObject.files[%s].metadata.height' % self.index),
|
||||
"width": self.marionette.execute_script('return window.wrappedJSObject.files[%s].metadata.width' % self.index)}
|
||||
|
||||
def tap(self):
|
||||
self.root_element.tap()
|
||||
35
gaia/tests/python/gaia-ui-tests/gaiatest/apps/gallery/regions/crop_view.py
Executable file
35
gaia/tests/python/gaia-ui-tests/gaiatest/apps/gallery/regions/crop_view.py
Executable file
|
|
@ -0,0 +1,35 @@
|
|||
# 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 gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class CropView(Base):
|
||||
_src = 'app://gallery.gaiamobile.org/index.html#pick'
|
||||
|
||||
_crop_done_button_locator = (By.ID, 'crop-done-button')
|
||||
_edit_preview_canvas_locator = (By.ID, 'edit-preview-canvas')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._edit_preview_canvas_locator))))
|
||||
# I have tried waiting for all the elements in the UI, but the crash
|
||||
# still occurs so the only solution I found was the hardcoded sleep - Bug 1111981
|
||||
time.sleep(3)
|
||||
done = self.marionette.find_element(*self._crop_done_button_locator)
|
||||
Wait(self.marionette).until(expected.element_enabled(done))
|
||||
|
||||
def tap_crop_done(self):
|
||||
element = self.marionette.find_element(*self._crop_done_button_locator)
|
||||
self.tap_element_from_system_app(element)
|
||||
|
||||
# Fall back to the app underneath
|
||||
Wait(self.marionette).until(lambda m: self.apps.displayed_app.src != self._src)
|
||||
self.apps.switch_to_displayed_app()
|
||||
73
gaia/tests/python/gaia-ui-tests/gaiatest/apps/gallery/regions/edit_photo.py
Executable file
73
gaia/tests/python/gaia-ui-tests/gaiatest/apps/gallery/regions/edit_photo.py
Executable file
|
|
@ -0,0 +1,73 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.base import PageRegion
|
||||
|
||||
|
||||
class EditPhoto(Base):
|
||||
|
||||
_canvas_locator = (By.ID, 'edit-preview-canvas')
|
||||
_edit_effect_button_locator = (By.ID, 'edit-effect-button')
|
||||
_effect_options_locator = (By.CSS_SELECTOR, '#edit-effect-options a')
|
||||
_edit_save_locator = (By.ID, 'edit-save-button')
|
||||
_edit_crop_button_locator = (By.ID, 'edit-crop-button')
|
||||
_crop_portrait_locator = (By.ID, 'edit-crop-aspect-portrait')
|
||||
_save_progress_bar_locator = (By.ID, 'save-progress')
|
||||
_edit_tool_apply_button_locator = (By.ID, 'edit-tool-apply-button')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
# <canvas> is dynamically inserted
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._canvas_locator))))
|
||||
|
||||
def tap_edit_effects_button(self):
|
||||
self.marionette.find_element(*self._edit_effect_button_locator).tap()
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._effect_options_locator))))
|
||||
|
||||
def tap_edit_crop_button(self):
|
||||
self.marionette.find_element(*self._edit_crop_button_locator).tap()
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._crop_portrait_locator))))
|
||||
|
||||
def tap_edit_tool_apply_button(self):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._edit_tool_apply_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
element.tap()
|
||||
|
||||
def tap_edit_save_button(self):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._edit_save_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
element.tap()
|
||||
progress = self.marionette.find_element(*self._save_progress_bar_locator)
|
||||
Wait(self.marionette).until(expected.element_not_displayed(progress))
|
||||
from gaiatest.apps.gallery.regions.fullscreen_image import FullscreenImage
|
||||
return FullscreenImage(self.marionette)
|
||||
|
||||
def tap_portrait_crop(self):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._crop_portrait_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
element.tap()
|
||||
Wait(self.marionette).until(lambda m: 'selected' in element.get_attribute('class'))
|
||||
|
||||
@property
|
||||
def effects(self):
|
||||
return [self.Effect(marionette=self.marionette, element=effect)
|
||||
for effect in self.marionette.find_elements(*self._effect_options_locator)]
|
||||
|
||||
class Effect(PageRegion):
|
||||
|
||||
def tap(self):
|
||||
self.root_element.tap()
|
||||
Wait(self.marionette).until(lambda m: 'selected' in self.root_element.get_attribute('class'))
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
from marionette_driver.marionette import Actions
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class FullscreenImage(Base):
|
||||
'''
|
||||
This is not the actual image file - it is a blob of the image file in storage
|
||||
'''
|
||||
_current_image_locator = (By.CSS_SELECTOR, '#frames .current > .image-view')
|
||||
_current_frame_locator = (By.CSS_SELECTOR, '#frames .current')
|
||||
_photos_toolbar_locator = (By.ID, 'fullscreen-toolbar')
|
||||
_delete_image_locator = (By.ID, 'fullscreen-delete-button-tiny')
|
||||
_confirm_delete_locator = (By.ID, 'confirm-ok')
|
||||
_edit_photo_locator = (By.ID, 'fullscreen-edit-button-tiny')
|
||||
_go_back_locator = (By.ID, 'fullscreen-back-button-tiny')
|
||||
_camera_locator = (By.ID, 'fullscreen-camera-button-tiny')
|
||||
_photo_toolbar_options_locator = (By.CSS_SELECTOR, '#fullscreen-toolbar > a')
|
||||
|
||||
# for camera app switch
|
||||
_loading_screen_locator = (By.CSS_SELECTOR, '.loading-screen')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._current_image_locator))))
|
||||
Wait(self.marionette).until(lambda m: self.marionette.find_element(*self._current_image_locator).get_attribute('src') != '')
|
||||
|
||||
@property
|
||||
def is_photo_toolbar_displayed(self):
|
||||
return self.marionette.find_element(*self._photos_toolbar_locator).is_displayed()
|
||||
|
||||
@property
|
||||
def current_image_source(self):
|
||||
return self.marionette.find_element(*self._current_image_locator).get_attribute('src')
|
||||
|
||||
@property
|
||||
def current_image_size_width(self):
|
||||
return self.marionette.find_element(*self._current_image_locator).size['width']
|
||||
|
||||
@property
|
||||
def current_image_size_height(self):
|
||||
return self.marionette.find_element(*self._current_image_locator).size['height']
|
||||
|
||||
@property
|
||||
def current_image_frame(self):
|
||||
return self.marionette.find_element(*self._current_frame_locator)
|
||||
|
||||
def flick_to_next_image(self):
|
||||
self._flick_to_image('next')
|
||||
|
||||
def flick_to_previous_image(self):
|
||||
self._flick_to_image('previous')
|
||||
|
||||
def _flick_to_image(self, direction):
|
||||
image = self.marionette.find_element(*self._current_image_locator)
|
||||
action = Actions(self.marionette)
|
||||
x_start = (image.size['width'] / 100) * (direction == 'next' and 90 or 10)
|
||||
x_end = (image.size['width'] / 100) * (direction == 'next' and 10 or 90)
|
||||
y_start = image.size['height'] / 4
|
||||
y_end = image.size['height'] / 4
|
||||
action.flick(image, x_start, y_start, x_end, y_end, 200).perform()
|
||||
Wait(self.marionette).until(
|
||||
lambda m: abs(image.location['x']) >= image.size['width'])
|
||||
# Workaround for bug 1161441, the transitionend event is not firing in this
|
||||
# case with a Marionette flick action, as opposed to a manual flick action
|
||||
self.marionette.execute_script("""
|
||||
arguments[0].dispatchEvent(new CustomEvent("transitionend"));
|
||||
""", [self.current_image_frame])
|
||||
|
||||
def tap_delete_button(self):
|
||||
self.marionette.find_element(*self._delete_image_locator).tap()
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._confirm_delete_locator))
|
||||
|
||||
def tap_confirm_deletion_button(self):
|
||||
element = self.marionette.find_element(*self._confirm_delete_locator)
|
||||
element.tap()
|
||||
Wait(self.marionette).until(expected.element_not_displayed(element))
|
||||
|
||||
def tap_edit_button(self):
|
||||
self.marionette.find_element(*self._edit_photo_locator).tap()
|
||||
from gaiatest.apps.gallery.regions.edit_photo import EditPhoto
|
||||
return EditPhoto(self.marionette)
|
||||
|
||||
def go_back(self):
|
||||
element = self.marionette.find_element(*self._go_back_locator)
|
||||
element.tap()
|
||||
Wait(self.marionette).until(expected.element_not_displayed(element))
|
||||
from gaiatest.apps.gallery.app import Gallery
|
||||
return Gallery(self.marionette)
|
||||
|
||||
def tap_switch_to_camera(self):
|
||||
self.marionette.find_element(*self._camera_locator).tap()
|
||||
from gaiatest.apps.camera.app import Camera
|
||||
camera_app = Camera(self.marionette)
|
||||
camera_app.wait_to_be_displayed()
|
||||
self.apps.switch_to_displayed_app()
|
||||
camera_app.wait_for_capture_ready()
|
||||
Wait(self.marionette).until(expected.element_not_displayed(*self._loading_screen_locator))
|
||||
return camera_app
|
||||
|
||||
def double_tap_image(self):
|
||||
image = self.marionette.find_element(*self._current_image_locator)
|
||||
action = Actions(self.marionette)
|
||||
action.double_tap(image)
|
||||
action.perform()
|
||||
|
||||
@property
|
||||
def photo_toolbar_width(self):
|
||||
return self.marionette.find_element(*self._photos_toolbar_locator).rect['width']
|
||||
|
||||
@property
|
||||
def photo_toolbar_options(self):
|
||||
return self.marionette.find_elements(*self._photo_toolbar_options_locator)
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class MultipleSelectionView(Base):
|
||||
|
||||
_select_picture_header_locator = (By.ID, 'thumbnails-number-selected')
|
||||
_thumbnail_list_view_locator = (By.CSS_SELECTOR, '.thumbnail')
|
||||
_share_thumbnail_locator = (By.ID, 'thumbnails-share-button')
|
||||
_delete_thumbnail_locator = (By.ID, 'thumbnails-delete-button')
|
||||
_delete_confirm_locator = (By.ID, 'confirm-ok')
|
||||
_delete_cancel_locator = (By.ID, 'confirm-cancel')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
select_picture_header = Wait(self.marionette).until(
|
||||
expected.element_present(*self._select_picture_header_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(select_picture_header))
|
||||
|
||||
def select_first_picture(self):
|
||||
self.thumbnails[0].tap()
|
||||
|
||||
def select_nth_picture(self, n):
|
||||
assert len(self.thumbnails) > n
|
||||
self.thumbnails[n].tap()
|
||||
|
||||
@property
|
||||
def number_of_selected_images(self):
|
||||
select_picture_header = Wait(self.marionette).until(
|
||||
expected.element_present(*self._select_picture_header_locator))
|
||||
|
||||
if 'selected' in select_picture_header.text:
|
||||
return int(select_picture_header.text[:1])
|
||||
else:
|
||||
return 0
|
||||
|
||||
@property
|
||||
def thumbnails(self):
|
||||
return self.marionette.find_elements(*self._thumbnail_list_view_locator)
|
||||
|
||||
def tap_share_button(self):
|
||||
share_button = Wait(self.marionette).until(
|
||||
expected.element_present(*self._share_thumbnail_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(share_button))
|
||||
share_button.tap()
|
||||
from gaiatest.apps.system.regions.activities import Activities
|
||||
return Activities(self.marionette)
|
||||
|
||||
# one can choose to cancel deletion by entering optional parameter
|
||||
def tap_delete_button(self, confirm=True):
|
||||
delete_button = Wait(self.marionette).until(
|
||||
expected.element_present(*self._delete_thumbnail_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(delete_button))
|
||||
delete_button.tap()
|
||||
|
||||
if confirm:
|
||||
confirm_decision_button = Wait(self.marionette).until(
|
||||
expected.element_present(*self._delete_confirm_locator))
|
||||
else:
|
||||
confirm_decision_button = Wait(self.marionette).until(
|
||||
expected.element_present(*self._delete_cancel_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(confirm_decision_button))
|
||||
confirm_decision_button.tap()
|
||||
43
gaia/tests/python/gaia-ui-tests/gaiatest/apps/gallery/regions/view_image.py
Executable file
43
gaia/tests/python/gaia-ui-tests/gaiatest/apps/gallery/regions/view_image.py
Executable file
|
|
@ -0,0 +1,43 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.form_controls.header import GaiaHeader
|
||||
|
||||
|
||||
class ViewImage(Base):
|
||||
|
||||
_header_locator = (By.ID, 'header')
|
||||
_banner_message_locator = (By.ID, 'message')
|
||||
_save_image_button_locator = (By.ID, 'save')
|
||||
_image_locator = (By.CSS_SELECTOR, 'img.image-view')
|
||||
manifest_url = '{}gallery{}/manifest.webapp'.format(Base.DEFAULT_PROTOCOL,Base.DEFAULT_APP_HOSTNAME)
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
from gaiatest.apps.gallery.app import Gallery
|
||||
Gallery(self.marionette).wait_to_be_displayed()
|
||||
self.apps.switch_to_displayed_app()
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._image_locator))))
|
||||
|
||||
@property
|
||||
def is_image_visible(self):
|
||||
return self.is_element_displayed(*self._image_locator)
|
||||
|
||||
@property
|
||||
def banner_message(self):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._banner_message_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
return element.text
|
||||
|
||||
def tap_back_button(self):
|
||||
GaiaHeader(self.marionette, self._header_locator).go_back(exit_app=True, app=self)
|
||||
|
||||
def tap_save_image(self):
|
||||
self.marionette.find_element(*self._save_image_button_locator).tap()
|
||||
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/homescreen/__init__.py
Executable file
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/homescreen/__init__.py
Executable file
161
gaia/tests/python/gaia-ui-tests/gaiatest/apps/homescreen/app.py
Executable file
161
gaia/tests/python/gaia-ui-tests/gaiatest/apps/homescreen/app.py
Executable file
|
|
@ -0,0 +1,161 @@
|
|||
# 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.marionette import Actions
|
||||
from marionette_driver.errors import NoSuchElementException
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.base import PageRegion
|
||||
from gaiatest.apps.homescreen.regions.bottom_bar import BottomBar
|
||||
|
||||
|
||||
class Homescreen(Base):
|
||||
|
||||
name = 'Default Home Screen'
|
||||
|
||||
_homescreen_icon_locator = (By.CSS_SELECTOR, 'gaia-grid .icon')
|
||||
_all_icons_locator = (By.TAG_NAME, 'gaia-app-icon')
|
||||
_edit_mode_locator = (By.CSS_SELECTOR, 'body.edit-mode')
|
||||
_search_bar_icon_locator = (By.ID, 'search-input')
|
||||
_landing_page_locator = (By.ID, 'icons')
|
||||
_bookmark_icons_locator = (By.CSS_SELECTOR, 'gaia-grid .bookmark')
|
||||
_divider_locator = (By.CSS_SELECTOR, 'section.divider')
|
||||
_divider_separator_locator = (By.CSS_SELECTOR, 'section.divider .separator > span')
|
||||
_exit_edit_mode_locator = (By.ID, 'exit-edit-mode')
|
||||
_body_dragging_locator = (By.CSS_SELECTOR, 'body.dragging')
|
||||
_apps_locator = (By.ID, 'apps')
|
||||
_app_icon_locator = (By.CSS_SELECTOR, 'gaia-app-icon[data-identifier="%s"]')
|
||||
_scollable_div_locator = (By.CSS_SELECTOR, '#apps-panel div.scrollable')
|
||||
|
||||
def wait_for_app_icon_present(self, app_manifest):
|
||||
Wait(self.marionette, timeout=30).until(lambda m: self.installed_app(app_manifest))
|
||||
|
||||
def wait_for_app_icon_not_present(self, app_manifest):
|
||||
def _app_is_not_found(_):
|
||||
try:
|
||||
self.installed_app(app_manifest)
|
||||
except NoSuchElementException:
|
||||
return True
|
||||
return False
|
||||
|
||||
Wait(self.marionette).until(_app_is_not_found)
|
||||
|
||||
def wait_for_bookmark_icon_not_present(self, bookmark_title):
|
||||
Wait(self.marionette).until(lambda m: self.bookmark(bookmark_title) is None)
|
||||
|
||||
def is_app_installed(self, app_manifest):
|
||||
"""Checks whether app is installed"""
|
||||
return self.installed_app(app_manifest) is not None
|
||||
|
||||
@property
|
||||
def is_at_topmost_position(self):
|
||||
position = self.marionette.execute_script("""
|
||||
return {x:arguments[0].scrollLeft, y: arguments[0].scrollTop}
|
||||
""", [self.marionette.find_element(*self._scollable_div_locator)])
|
||||
return (position['x'] == 0 and position['y'] == 0)
|
||||
|
||||
def scroll_to_icon(self, icon_position=0):
|
||||
app_icon = self.visible_apps[icon_position]
|
||||
self.marionette.execute_script(
|
||||
'arguments[0].scrollIntoView(true);', [app_icon.root_element])
|
||||
|
||||
def move_app_to_position(self, app_position, to_position):
|
||||
app = self.app_elements[app_position]
|
||||
destination_element = self.app_elements[to_position].root_element
|
||||
app.move_to(destination_element)
|
||||
|
||||
@property
|
||||
def app_elements(self):
|
||||
return [self.GaiaAppIcon(self.marionette, app_element)
|
||||
for app_element in self.marionette.find_elements(*self._all_icons_locator)]
|
||||
|
||||
@property
|
||||
def visible_apps(self):
|
||||
return [homescreen_element for homescreen_element in self.app_elements if homescreen_element.is_displayed]
|
||||
|
||||
def wait_for_number_of_apps(self, number_of_apps=1):
|
||||
Wait(self.marionette).until(lambda m: len(self.app_elements) >= number_of_apps)
|
||||
|
||||
def installed_app(self, app_manifest):
|
||||
apps_container = self.marionette.find_elements(*self._apps_locator)
|
||||
self.marionette.switch_to_shadow_root(apps_container)
|
||||
icon_locator = (self._app_icon_locator[0], self._app_icon_locator[1] % app_manifest)
|
||||
app_icon = self.marionette.find_element(*icon_locator)
|
||||
return self.GaiaAppIcon(self.marionette, app_icon)
|
||||
|
||||
def bookmark(self, bookmark_title):
|
||||
for root_el in self.marionette.find_elements(*self._bookmark_icons_locator):
|
||||
if root_el.text == bookmark_title:
|
||||
return self.GaiaAppIcon(self.marionette, root_el)
|
||||
|
||||
@property
|
||||
def number_of_columns(self):
|
||||
_icon_container_text = 'div.gaia-container-child:nth-child(%s)'
|
||||
#first element is always on the first column
|
||||
_first_icon_locator = (By.CSS_SELECTOR, _icon_container_text % str(1))
|
||||
# wait until the icons are fully drawn
|
||||
Wait(self.marionette).until(lambda m: self.marionette.find_element(*_first_icon_locator).rect['x'] != 0)
|
||||
base_x_axis = self.marionette.find_element(*_first_icon_locator).rect['x']
|
||||
has_row_changed = False
|
||||
column = 1
|
||||
while not has_row_changed:
|
||||
_icon_locator = (By.CSS_SELECTOR, _icon_container_text % str(column+1))
|
||||
if self.marionette.find_element(*_icon_locator).rect['x'] == base_x_axis:
|
||||
has_row_changed = True
|
||||
else:
|
||||
column += 1
|
||||
|
||||
return column
|
||||
|
||||
def delete_app(self, app_manifest):
|
||||
app = self.installed_app(app_manifest)
|
||||
app.activate_edit_mode()
|
||||
|
||||
return BottomBar(self.marionette).tap_remove()
|
||||
|
||||
class GaiaAppIcon(PageRegion):
|
||||
|
||||
@property
|
||||
def manifest_url(self):
|
||||
return self.root_element.get_attribute('data-identifier')
|
||||
|
||||
@property
|
||||
def is_app_installed(self):
|
||||
self.marionette.switch_to_shadow_root(self.root_element)
|
||||
app_installed = self.root_element.get_attribute('data-test-icon-url') == 'app-icon'
|
||||
self.marionette.switch_to_shadow_root()
|
||||
return app_installed
|
||||
|
||||
@property
|
||||
def is_displayed(self):
|
||||
return self.root_element.is_displayed()
|
||||
|
||||
def tap_icon(self):
|
||||
expected_manifest_url = self.manifest_url
|
||||
self.root_element.tap()
|
||||
Wait(self.marionette).until(lambda m: self.apps.displayed_app.manifest_url == expected_manifest_url)
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def activate_edit_mode(self):
|
||||
self._start_long_press_action().\
|
||||
release().\
|
||||
perform()
|
||||
|
||||
def move_to(self, html_element):
|
||||
self._start_long_press_action().\
|
||||
move(html_element).\
|
||||
wait(1).\
|
||||
release().\
|
||||
wait(1).\
|
||||
perform()
|
||||
|
||||
def _start_long_press_action(self):
|
||||
self.marionette.execute_script('arguments[0].scrollIntoView(false);', [self.root_element])
|
||||
|
||||
return Actions(self.marionette).\
|
||||
press(self.root_element).\
|
||||
wait(3)
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
# 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 gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class BookmarkMenu(Base):
|
||||
|
||||
name = "Bookmark"
|
||||
manifest_url = '{}bookmark{}/manifest.webapp'.format(Base.DEFAULT_PROTOCOL,Base.DEFAULT_APP_HOSTNAME)
|
||||
|
||||
# System app - add bookmark to homescreen dialog
|
||||
_add_bookmark_to_home_screen_frame_locator = (By.CSS_SELECTOR, 'iframe[src^="app://bookmark"][src$="save.html"]')
|
||||
_add_bookmark_to_home_screen_dialog_button_locator = (By.ID, 'done-button')
|
||||
_bookmark_title_input_locator = (By.ID, 'bookmark-title')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
self.wait_to_be_displayed()
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def tap_add_bookmark_to_home_screen_dialog_button(self):
|
||||
element = Wait(self.marionette).until(expected.element_present(
|
||||
*self._add_bookmark_to_home_screen_dialog_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
# This sleep is necessary for the button to react to the tap call
|
||||
time.sleep(0.2)
|
||||
self.tap_element_from_system_app(element)
|
||||
|
||||
# Wait for the Add to bookmark frame to be dismissed
|
||||
self.wait_to_not_be_displayed()
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def type_bookmark_title(self, value):
|
||||
element = self.marionette.find_element(
|
||||
*self._bookmark_title_input_locator)
|
||||
|
||||
# Wait for the default value to load into the input field
|
||||
Wait(self.marionette).until(lambda m: element.get_attribute('value') != '')
|
||||
element.clear()
|
||||
|
||||
self.keyboard.send(value)
|
||||
self.keyboard.dismiss()
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
# 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/.
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest import GaiaApps
|
||||
from gaiatest.apps.base import PageRegion
|
||||
|
||||
|
||||
class BottomBar(PageRegion):
|
||||
_bottom_bar_locator = (By.ID, 'bottombar')
|
||||
_remove_locator = (By.ID, 'remove')
|
||||
_done_locator = (By.ID, 'done')
|
||||
|
||||
def __init__(self, marionette):
|
||||
GaiaApps(marionette).switch_to_displayed_app()
|
||||
root = Wait(marionette).until(
|
||||
expected.element_present(*self._bottom_bar_locator))
|
||||
Wait(marionette).until(expected.element_displayed(root))
|
||||
|
||||
window_height = marionette.execute_script('return window.wrappedJSObject.innerHeight')
|
||||
Wait(marionette).until(lambda m: int(root.rect['y'] + root.size['height']) == window_height)
|
||||
|
||||
PageRegion.__init__(self, marionette, root)
|
||||
|
||||
def tap_remove(self):
|
||||
self.root_element.find_element(*self._remove_locator).tap()
|
||||
|
||||
from gaiatest.apps.homescreen.regions.confirm_dialog import ConfirmDialog
|
||||
return ConfirmDialog(self.marionette)
|
||||
|
||||
def tap_exit_edit_mode(self):
|
||||
self.apps.switch_to_displayed_app()
|
||||
self.root_element = self.marionette.find_element(*self._bottom_bar_locator)
|
||||
self.root_element.find_element(*self._done_locator).tap()
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
# 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 gaiatest.apps.base import Base
|
||||
from gaiatest.apps.homescreen.regions.bottom_bar import BottomBar
|
||||
|
||||
|
||||
class ConfirmDialog(Base):
|
||||
|
||||
_confirm_button_locator = (By.CSS_SELECTOR, 'gaia-confirm .confirm')
|
||||
|
||||
def tap_confirm(self, bookmark=False):
|
||||
# TODO add a good wait here when Bug 1008961 is resolved
|
||||
time.sleep(1)
|
||||
if not bookmark:
|
||||
self.marionette.switch_to_frame()
|
||||
confirm = Wait(self.marionette).until(expected.element_present(
|
||||
*self._confirm_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(confirm))
|
||||
confirm.tap()
|
||||
|
||||
return BottomBar(self.marionette)
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# 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 gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class ConfirmInstall(Base):
|
||||
|
||||
_confirm_install_button_locator = (By.ID, 'app-install-install-button')
|
||||
|
||||
def tap_confirm(self):
|
||||
# TODO add a good wait here when Bug 1008961 is resolved
|
||||
self.marionette.switch_to_frame()
|
||||
confirm = Wait(self.marionette).until(expected.element_present(
|
||||
*self._confirm_install_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(confirm))
|
||||
confirm.tap()
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class PermissionDialog(Base):
|
||||
|
||||
_permission_dialog_locator = (By.ID, 'permission-dialog')
|
||||
_permission_dialog_message_locator = (By.ID, 'permission-message')
|
||||
_permission_confirm_button_locator = (By.ID, 'permission-yes')
|
||||
_permission_dismiss_button_locator = (By.ID, 'permission-no')
|
||||
|
||||
def wait_for_permission_dialog_displayed(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._permission_dialog_locator))))
|
||||
|
||||
@property
|
||||
def permission_dialog_message(self):
|
||||
return self.marionette.find_element(*self._permission_dialog_message_locator).text
|
||||
|
||||
def tap_to_confirm_permission(self):
|
||||
self.marionette.find_element(*self._permission_confirm_button_locator).tap()
|
||||
from gaiatest.apps.system.app import System
|
||||
return System(self.marionette)
|
||||
|
||||
def tap_to_dismiss_permission(self):
|
||||
self.marionette.find_element(*self._permission_dismiss_button_locator).tap()
|
||||
3
gaia/tests/python/gaia-ui-tests/gaiatest/apps/keyboard/__init__.py
Executable file
3
gaia/tests/python/gaia-ui-tests/gaiatest/apps/keyboard/__init__.py
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
# 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/.
|
||||
430
gaia/tests/python/gaia-ui-tests/gaiatest/apps/keyboard/app.py
Executable file
430
gaia/tests/python/gaia-ui-tests/gaiatest/apps/keyboard/app.py
Executable file
|
|
@ -0,0 +1,430 @@
|
|||
# -*- coding: UTF-8 -*-
|
||||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
from marionette_driver.marionette import Actions
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.system.app import System
|
||||
|
||||
|
||||
class Keyboard(Base):
|
||||
'''
|
||||
There are two underlying strategies in this class;
|
||||
|
||||
* send() method which uses logic to traverse the keyboard to type the
|
||||
string sent to it. Send should be used in tests where the layout of the
|
||||
keyboard is not tested and only string input is important
|
||||
* tap_x() or anything not send() methods which do not use logic to change
|
||||
keyboard panels. Tap should be used where the keyboard is expected to
|
||||
open with that key visible
|
||||
|
||||
The methods in this class employ a lot of aggressive frame switching to the keyboard and back to the
|
||||
displayed app because it predominantly acts as a utility class and thus it works best when the main focus
|
||||
of the test is on the web app rather than the keyboard itself.
|
||||
'''
|
||||
|
||||
name = "Keyboard"
|
||||
|
||||
# special characters look-up table in English standard keyboard
|
||||
lookup_table = {'0': 'º',
|
||||
'?': '¿',
|
||||
'$': '€£¥',
|
||||
'!': '¡',
|
||||
'a': 'áàâäåãāæ',
|
||||
'c': 'çćč',
|
||||
'e': 'éèêëēę€ɛ',
|
||||
'i': 'įīîìíï',
|
||||
'l': '£ł',
|
||||
'n': 'ńñ',
|
||||
'o': 'ɵøœōôòóö',
|
||||
's': 'ßśš$',
|
||||
'u': 'ūûùúü',
|
||||
'y': '¥ÿ',
|
||||
'z': 'žźż',
|
||||
'A': 'ÁÀÂÄÅÃĀÆ',
|
||||
'C': 'ÇĆČ',
|
||||
'E': 'ÉÈÊËĒĘ€Ɛ',
|
||||
'I': 'ĮĪÎÌÍÏ',
|
||||
'L': '£Ł',
|
||||
'N': 'ŃÑ',
|
||||
'O': 'ƟØŒŌÔÒÓÖ',
|
||||
'S': 'ŚŠŞ',
|
||||
'U': 'ŪÛÙÚÜ',
|
||||
'Y': '¥Ÿ',
|
||||
'Z': 'ŽŹŻ'}
|
||||
|
||||
# keyboard table
|
||||
keyboard_table = ['english',
|
||||
'dvorak',
|
||||
'otherlatins',
|
||||
'cyrillic',
|
||||
'arabic',
|
||||
'hebrew',
|
||||
'zhuyin',
|
||||
'pinyin',
|
||||
'greek',
|
||||
'japanese',
|
||||
'portuguese',
|
||||
'spanish']
|
||||
|
||||
# special keys locators
|
||||
_language_key_locator = (By.CSS_SELECTOR, ".keyboard-type-container[data-active='true'] .keyboard-row button[data-keycode='-3']")
|
||||
_dotcom_key_locator = (By.CSS_SELECTOR, ".keyboard-row button[data-compositekey='.com']")
|
||||
_page_switching_key_locator = (By.CSS_SELECTOR, '.keyboard-type-container[data-active] button.keyboard-key[data-target-page="%s"]')
|
||||
_backspace_key = '8'
|
||||
_enter_key = '13'
|
||||
_alt_key = '18'
|
||||
_upper_case_key = '20'
|
||||
_space_key = '32'
|
||||
|
||||
# keyboard app locators
|
||||
_keyboard_active_frame_locator = (By.CSS_SELECTOR, '#keyboards .inputWindow.active iframe')
|
||||
_input_window_locator = (By.CSS_SELECTOR, '#keyboards .inputWindow')
|
||||
_button_locator = (By.CSS_SELECTOR, '.keyboard-type-container[data-active] button.keyboard-key[data-keycode="%s"], .keyboard-type-container[data-active] button.keyboard-key[data-keycode-upper="%s"]')
|
||||
_highlight_key_locator = (By.CSS_SELECTOR, '#keyboard-accent-char-menu button')
|
||||
_predicted_word_locator = (By.CSS_SELECTOR, '.autocorrect')
|
||||
_candidate_panel_locator = (By.CSS_SELECTOR, '.keyboard-candidate-panel')
|
||||
_suggestions_container_locator = (By.CSS_SELECTOR, '.suggestions-container')
|
||||
_dismiss_suggestions_button_locator = (By.CSS_SELECTOR, '.dismiss-suggestions-button')
|
||||
|
||||
# find the key to long press and return
|
||||
def _find_key_for_longpress(self, input_value):
|
||||
for key_to_press, extended_values in self.lookup_table.iteritems():
|
||||
if input_value in extended_values:
|
||||
return key_to_press
|
||||
|
||||
# Try to switch to the correct layout. There are 3 keyboard layers:
|
||||
# Basic (layoutPage = 0), Alternate (layoutPage = 1) and Symbol (layoutPage = 2)
|
||||
def _switch_to_correct_layout(self, val):
|
||||
if val.isspace() or val in [',', '.']:
|
||||
# certain keys are available on every keyboard panel
|
||||
pass
|
||||
# Alphabetic keys available on the basic page
|
||||
elif val.isalpha():
|
||||
is_upper_case = self._is_upper_case
|
||||
# If the key to press isalpha and the keyboard layout is not, go back to Basic
|
||||
if not self._layout_page == 0:
|
||||
self._tap_page_switching_key(0)
|
||||
Wait(self.marionette).until(lambda m: self._layout_page == 0)
|
||||
# If the key to press isupper and the keyboard is not (or vice versa) then press shift
|
||||
if not val.isupper() == is_upper_case:
|
||||
self._tap(self._upper_case_key)
|
||||
Wait(self.marionette).until(lambda m: is_upper_case != self._is_upper_case)
|
||||
# Numbers and symbols are in other keyboard panels
|
||||
else:
|
||||
# If it's not space or alpha then it must be in Alternate or Symbol.
|
||||
# It can't be in Basic so let's go into Alternate and then try to find it
|
||||
if self._layout_page == 0 and not self._current_input_type == 'number' and not self._current_input_mode == 'numeric':
|
||||
self._tap_page_switching_key(1)
|
||||
page_0_key_locator = (self._page_switching_key_locator[0], self._page_switching_key_locator[1] % (0))
|
||||
Wait(self.marionette).until(expected.element_displayed(*page_0_key_locator))
|
||||
# If it is not present here then it must be in the other non-Basic page
|
||||
# (since we must be in either Alternate or Symbol at this stage)
|
||||
if not self.is_element_present(*self._key_locator(val)):
|
||||
if self._layout_page == 1:
|
||||
self._tap_page_switching_key(2)
|
||||
page_1_key_locator = (self._page_switching_key_locator[0], self._page_switching_key_locator[1] % (1))
|
||||
Wait(self.marionette).until(expected.element_displayed(*page_1_key_locator))
|
||||
else:
|
||||
self._tap_page_switching_key(1)
|
||||
page_2_key_locator = (self._page_switching_key_locator[0], self._page_switching_key_locator[1] % (2))
|
||||
Wait(self.marionette).until(expected.element_displayed(*page_2_key_locator))
|
||||
|
||||
@property
|
||||
def _is_upper_case(self):
|
||||
return self.marionette.execute_script('return window.wrappedJSObject.app.upperCaseStateManager.isUpperCase;')
|
||||
|
||||
@property
|
||||
def _is_upper_case_locked(self):
|
||||
return self.marionette.execute_script('return window.wrappedJSObject.app.upperCaseStateManager.isUpperCaseLocked;')
|
||||
|
||||
@property
|
||||
def _current_input_type(self):
|
||||
return self.marionette.execute_script('return window.wrappedJSObject.app.getBasicInputType();')
|
||||
|
||||
@property
|
||||
def _layout_page(self):
|
||||
return self.marionette.execute_script('return window.wrappedJSObject.app.layoutManager.currentPageIndex;')
|
||||
|
||||
@property
|
||||
def _current_input_mode(self):
|
||||
return self.marionette.execute_script('return window.wrappedJSObject.app.inputContext.inputMode;')
|
||||
|
||||
# this is to switch to the frame of keyboard
|
||||
def switch_to_keyboard(self, focus=False):
|
||||
self.marionette.switch_to_frame()
|
||||
Wait(self.marionette).until(lambda m: self.is_keyboard_displayed is True)
|
||||
|
||||
keybframe = self.marionette.find_element(*self._keyboard_active_frame_locator)
|
||||
self.marionette.switch_to_frame(keybframe, focus)
|
||||
|
||||
@property
|
||||
def current_keyboard(self):
|
||||
self.marionette.switch_to_frame()
|
||||
keyboard = self.marionette.find_element(*self._keyboard_active_frame_locator).get_attribute('data-frame-name')
|
||||
return keyboard
|
||||
|
||||
# this is to get the locator of desired key on keyboard
|
||||
def _key_locator(self, val):
|
||||
if len(val) == 1:
|
||||
val = ord(val)
|
||||
return (self._button_locator[0], self._button_locator[1] % (val, val))
|
||||
|
||||
# this is to tap on desired key on keyboard
|
||||
def _tap(self, val):
|
||||
key = Wait(self.marionette).until(expected.element_present(*self._key_locator(val)))
|
||||
Wait(self.marionette).until(expected.element_displayed(key))
|
||||
Actions(self.marionette).press(key).release().perform()
|
||||
|
||||
# These two tap cases are most important because they cause the keyboard to change state which affects next step
|
||||
if val.isspace():
|
||||
# Space switches back to Default layout
|
||||
Wait(self.marionette).until(lambda m: self._layout_page == 0)
|
||||
if val.isupper() and not self._is_upper_case_locked:
|
||||
# Tapping key with shift enabled causes the keyboard to switch back to lower
|
||||
Wait(self.marionette).until(lambda m: not self._is_upper_case)
|
||||
|
||||
def _tap_page_switching_key(self, val):
|
||||
locator = (self._page_switching_key_locator[0], self._page_switching_key_locator[1] % val)
|
||||
key = Wait(self.marionette).until(expected.element_present(*locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(key))
|
||||
Actions(self.marionette).press(key).release().perform()
|
||||
|
||||
# This is for selecting special characters after long pressing
|
||||
# "selection" is the nth special element you want to select (n>=1)
|
||||
def choose_extended_character(self, long_press_key, selection, movement=True):
|
||||
self.switch_to_keyboard()
|
||||
action = Actions(self.marionette)
|
||||
|
||||
# after switching to correct keyboard, set long press if the key is there
|
||||
self._switch_to_correct_layout(long_press_key)
|
||||
key = Wait(self.marionette).until(expected.element_present(*self._key_locator(long_press_key)))
|
||||
Wait(self.marionette).until(expected.element_displayed(key))
|
||||
action.press(key).wait(1).perform()
|
||||
|
||||
# find the extended key and perform the action chain
|
||||
extend_keys = self.marionette.find_elements(*self._highlight_key_locator)
|
||||
if movement is True:
|
||||
action.move(extend_keys[selection - 1]).perform()
|
||||
action.release().perform()
|
||||
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def enable_caps_lock(self):
|
||||
self.switch_to_keyboard()
|
||||
key_obj = self.marionette.find_element(*self._key_locator(self._upper_case_key))
|
||||
self.marionette.double_tap(key_obj)
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
# this would go through fastest way to tap/click through a string
|
||||
def send(self, string):
|
||||
self.switch_to_keyboard()
|
||||
for val in string:
|
||||
if ord(val) > 127:
|
||||
# this would get the right key to long press and switch to the right keyboard
|
||||
middle_key_val = self._find_key_for_longpress(val.encode('UTF-8'))
|
||||
self._switch_to_correct_layout(middle_key_val)
|
||||
|
||||
# find the key to long press and press it to get the extended characters list
|
||||
middle_key = self.marionette.find_element(*self._key_locator(middle_key_val))
|
||||
action = Actions(self.marionette)
|
||||
action.press(middle_key).wait(1).perform()
|
||||
|
||||
# find the targeted extended key to send
|
||||
key = Wait(self.marionette).until(
|
||||
expected.element_present(*self._key_locator(val)))
|
||||
Wait(self.marionette).until(expected.element_displayed(key))
|
||||
action.move(key).release().perform()
|
||||
else:
|
||||
# after switching to correct keyboard, tap/click if the key is there
|
||||
self._switch_to_correct_layout(val)
|
||||
self._tap(val)
|
||||
|
||||
# when we tap on '@' the layout switches to the default keyboard - Bug 996332
|
||||
if val == '@':
|
||||
Wait(self.marionette).until(
|
||||
lambda m: self._layout_page == 0)
|
||||
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
# Switch keyboard language
|
||||
# Mapping of language code => {
|
||||
# "ar":"ﺎﻠﻋﺮﺒﻳﺓ",
|
||||
# "cz":"Česká",
|
||||
# "de":"Deutsch",
|
||||
# "el":"Greek"
|
||||
# "en":"English",
|
||||
# "en-Dvorak":"Dvorak",
|
||||
# "es":"Español",
|
||||
# "fr":"français",
|
||||
# "he":"עִבְרִית",
|
||||
# "nb":"Norsk",
|
||||
# "pt_BR":"Português",
|
||||
# "pl":"polski",
|
||||
# "ru":"русский",
|
||||
# "sk":"Slovenčina",
|
||||
# "sr-Cyrl":"српска ћирилица",
|
||||
# "sr-Latn":"srpski",
|
||||
# "tr":"Türkçe"}
|
||||
def switch_keyboard_language(self, lang_code):
|
||||
# TODO At the moment this doesn't work because the UI has changed
|
||||
# An attempted repair ran into https://bugzilla.mozilla.org/show_bug.cgi?id=779284 (Modal dialog)
|
||||
|
||||
keyboard_language_locator = (By.CSS_SELECTOR, ".keyboard-row button[data-keyboard='%s']" % lang_code)
|
||||
|
||||
self.switch_to_keyboard()
|
||||
language_key = self.marionette.find_element(*self._language_key_locator)
|
||||
action = Actions(self.marionette)
|
||||
action.press(language_key).wait(1).perform()
|
||||
target_kb_layout = self.marionette.find_element(*keyboard_language_locator)
|
||||
action.move(target_kb_layout).release().perform()
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def tap_keyboard_language_key(self):
|
||||
self.switch_to_keyboard()
|
||||
key = Wait(self.marionette).until(
|
||||
expected.element_present(*self._language_key_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(key))
|
||||
key.tap()
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
# following are "5 functions" to substitute finish switch_to_frame()s and tap() for you
|
||||
def tap_shift(self):
|
||||
self.switch_to_keyboard()
|
||||
self._tap(self._upper_case_key)
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def tap_backspace(self):
|
||||
self.switch_to_keyboard()
|
||||
backspace = self.marionette.find_element(self._button_locator[0], self._button_locator[1] % (self._backspace_key, self._backspace_key))
|
||||
backspace.tap()
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def tap_space(self):
|
||||
self.switch_to_keyboard()
|
||||
self._tap(self._space_key)
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def tap_enter(self):
|
||||
self.switch_to_keyboard()
|
||||
self._tap(self._enter_key)
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def tap_dotcom(self):
|
||||
self.switch_to_keyboard()
|
||||
dotcom = self.marionette.find_element(*self._dotcom_key_locator)
|
||||
dotcom.tap()
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def dismiss(self):
|
||||
# Make sure that keyboard is focused, otherwise dismissing it doesn't work
|
||||
self.switch_to_keyboard(focus=True)
|
||||
self.marionette.switch_to_frame()
|
||||
# navigator.mozKeyboard is needed for v1.3 support
|
||||
self.marionette.execute_script("""
|
||||
var keyboard = navigator.mozKeyboard || navigator.mozInputMethod;
|
||||
keyboard.removeFocus();""")
|
||||
Wait(self.marionette).until(lambda m: self.is_keyboard_displayed is False)
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def tap_first_predictive_word(self):
|
||||
self.switch_to_keyboard()
|
||||
key = Wait(self.marionette).until(
|
||||
expected.element_present(*self._predicted_word_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(key))
|
||||
key.tap()
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def tap_suggestion(self, word):
|
||||
self.switch_to_keyboard()
|
||||
|
||||
# find the requested suggestion
|
||||
selector = (By.CSS_SELECTOR, '.suggestions-container span[data-data=\"%s\"]' % word)
|
||||
key = Wait(self.marionette).until(expected.element_present(*selector))
|
||||
Wait(self.marionette).until(expected.element_displayed(key))
|
||||
key.tap()
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
# Accessibility related properties and methods
|
||||
|
||||
def _a11y_get_role(self, locator_args):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*locator_args))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
return self.accessibility.get_role(element)
|
||||
|
||||
def _a11y_get_name(self, locator_args):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*locator_args))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
return self.accessibility.get_name(element)
|
||||
|
||||
@property
|
||||
def a11y_first_predictive_word_name(self):
|
||||
return self._a11y_get_name(self._predicted_word_locator)
|
||||
|
||||
@property
|
||||
def a11y_first_predictive_word_role(self):
|
||||
return self._a11y_get_role(self._predicted_word_locator)
|
||||
|
||||
@property
|
||||
def a11y_candidate_panel_name(self):
|
||||
return self._a11y_get_name(self._candidate_panel_locator)
|
||||
|
||||
@property
|
||||
def a11y_suggestions_container_role(self):
|
||||
return self._a11y_get_role(self._suggestions_container_locator)
|
||||
|
||||
@property
|
||||
def a11y_dismiss_suggestions_button_role(self):
|
||||
return self._a11y_get_role(self._dismiss_suggestions_button_locator)
|
||||
|
||||
@property
|
||||
def a11y_dismiss_suggestions_button_name(self):
|
||||
return self._a11y_get_name(self._dismiss_suggestions_button_locator)
|
||||
|
||||
@property
|
||||
def a11y_enter_key_role(self):
|
||||
return self._a11y_get_role(self._key_locator(self._enter_key))
|
||||
|
||||
@property
|
||||
def a11y_enter_key_name(self):
|
||||
return self._a11y_get_name(self._key_locator(self._enter_key))
|
||||
|
||||
@property
|
||||
def a11y_space_key_role(self):
|
||||
return self._a11y_get_role(self._key_locator(self._space_key))
|
||||
|
||||
@property
|
||||
def a11y_space_key_name(self):
|
||||
return self._a11y_get_name(self._key_locator(self._space_key))
|
||||
|
||||
@property
|
||||
def a11y_backspace_key_name(self):
|
||||
return self._a11y_get_name([self._button_locator[0],
|
||||
self._button_locator[1] % (self._backspace_key, self._backspace_key)])
|
||||
|
||||
@property
|
||||
def a11y_backspace_key_role(self):
|
||||
return self._a11y_get_role([self._button_locator[0],
|
||||
self._button_locator[1] % (self._backspace_key, self._backspace_key)])
|
||||
|
||||
def a11y_first_predictive_word_click(self):
|
||||
self.switch_to_keyboard()
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._predicted_word_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
self.accessibility.click(element)
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
@property
|
||||
def is_keyboard_displayed(self):
|
||||
input_window = self.marionette.find_element(*self._input_window_locator)
|
||||
|
||||
# if we have software buttons, keyboard's y will not be 0 but the minus height of the button container.
|
||||
expected_y = -System(self.marionette).software_buttons_height
|
||||
|
||||
return (input_window.is_displayed() and (int(input_window.location['y']) == expected_y))
|
||||
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/lockscreen/__init__.py
Executable file
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/lockscreen/__init__.py
Executable file
140
gaia/tests/python/gaia-ui-tests/gaiatest/apps/lockscreen/app.py
Executable file
140
gaia/tests/python/gaia-ui-tests/gaiatest/apps/lockscreen/app.py
Executable file
|
|
@ -0,0 +1,140 @@
|
|||
# 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/.
|
||||
from datetime import datetime
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
from marionette_driver.marionette import Actions
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.base import PageRegion
|
||||
from gaiatest.apps.homescreen.app import Homescreen
|
||||
from gaiatest.apps.camera.app import Camera
|
||||
from gaiatest.apps.lockscreen.regions.passcode_pad import PasscodePad
|
||||
|
||||
|
||||
class LockScreen(Base):
|
||||
|
||||
_lockscreen_window_locator = (By.CLASS_NAME, 'lockScreenWindow')
|
||||
|
||||
_lockscreen_locator = (By.ID, 'lockscreen')
|
||||
_lockscreen_handle_locator = (By.ID, 'lockscreen-area-slide')
|
||||
_lockscreen_passcode_code_locator = (By.ID, 'lockscreen-passcode-code')
|
||||
_lockscreen_passcode_pad_locator = (By.ID, 'lockscreen-passcode-pad')
|
||||
|
||||
_unlock_button_locator = (By.ID, 'lockscreen-area-unlock')
|
||||
_camera_button_locator = (By.ID, 'lockscreen-area-camera')
|
||||
|
||||
_lockscreen_container_locator = (By.ID, 'notifications-lockscreen-container')
|
||||
_notification_locator = (By.CSS_SELECTOR, '#notifications-lockscreen-container > div.notification')
|
||||
|
||||
_time_locator = (By.ID, 'lockscreen-clock-time')
|
||||
|
||||
def switch_to_frame(self):
|
||||
# XXX: Because we're not in frame yet. LockScreen team now is
|
||||
# trying hard to do decoupling & as-iframe at the same time,
|
||||
# but iframe now stuck at weird test failures, so the team decide
|
||||
# to land decoupling part first, with some dummy functions that
|
||||
# can be modified later to fit the implementation.
|
||||
#
|
||||
# If we finished to make it as an iframe, to this to switch
|
||||
# to the real frame:
|
||||
#
|
||||
# self.marionette.switch_to_frame(
|
||||
# self.marionette.find_element(*self._lockscreen_frame_locator));
|
||||
#
|
||||
# But now we're not ready to do that yet.
|
||||
self.marionette.switch_to_frame()
|
||||
|
||||
@property
|
||||
def time(self):
|
||||
# The lockscreen doesn't display AM/PM since 2.0. It's still present behind a hidden span though.
|
||||
lockscreen_time = self.marionette.execute_script(
|
||||
"return document.getElementById('%s').innerHTML" % self._time_locator[1])
|
||||
return lockscreen_time.replace('<span>', '').replace('</span>', '')
|
||||
|
||||
@property
|
||||
def time_in_datetime(self):
|
||||
return datetime.strptime(self.time, '%I:%M %p')
|
||||
|
||||
def unlock(self):
|
||||
self._slide_to_unlock('homescreen')
|
||||
self.wait_for_lockscreen_not_visible()
|
||||
return Homescreen(self.marionette)
|
||||
|
||||
def unlock_to_camera(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._lockscreen_handle_locator))
|
||||
self._slide_to_unlock('camera')
|
||||
return Camera(self.marionette)
|
||||
|
||||
def unlock_to_emergency_call(self):
|
||||
passcode_pad = self.unlock_to_passcode_pad()
|
||||
return passcode_pad.tap_emergency_call()
|
||||
|
||||
def unlock_to_passcode_pad(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._lockscreen_handle_locator))
|
||||
self._slide_to_unlock('homescreen')
|
||||
Wait(self.marionette).until(
|
||||
expected.element_displayed(*self._lockscreen_passcode_code_locator))
|
||||
return PasscodePad(self.marionette)
|
||||
|
||||
def unlock_to_homescreen_using_passcode(self, passcode):
|
||||
passcode_pad = self.unlock_to_passcode_pad()
|
||||
homescreen = passcode_pad.type_passcode(passcode)
|
||||
self.wait_for_lockscreen_not_visible()
|
||||
return homescreen
|
||||
|
||||
def _slide_to_unlock(self, destination):
|
||||
|
||||
lockscreen_handle = self.marionette.find_element(*self._lockscreen_handle_locator)
|
||||
lockscreen_handle_x_centre = int(lockscreen_handle.size['width'] / 2)
|
||||
lockscreen_handle_y_centre = int(lockscreen_handle.size['height'] / 2)
|
||||
|
||||
handle_destination = lockscreen_handle.size['width']
|
||||
if destination == 'camera':
|
||||
handle_destination *= -1
|
||||
|
||||
# Flick lockscreen handle to the destination
|
||||
Actions(self.marionette).flick(
|
||||
lockscreen_handle, lockscreen_handle_x_centre, lockscreen_handle_y_centre, handle_destination, 0
|
||||
).perform()
|
||||
|
||||
def wait_for_lockscreen_not_visible(self):
|
||||
Wait(self.marionette).until(expected.element_not_displayed(*self._lockscreen_locator))
|
||||
|
||||
def wait_for_notification(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._notification_locator))
|
||||
|
||||
def a11y_click_unlock_button(self):
|
||||
self.accessibility.click(self.marionette.find_element(*self._unlock_button_locator))
|
||||
return Homescreen(self.marionette)
|
||||
|
||||
def a11y_click_camera_button(self):
|
||||
self.accessibility.click(self.marionette.find_element(*self._camera_button_locator))
|
||||
return Camera(self.marionette)
|
||||
|
||||
@property
|
||||
def notifications(self):
|
||||
container = self.marionette.find_element(*self._lockscreen_container_locator)
|
||||
# Avoid the search timeout when there are no notifications
|
||||
if not container.is_displayed() or container.text == '':
|
||||
return []
|
||||
return [Notification(self.marionette, element)
|
||||
for element in self.marionette.find_elements(*self._notification_locator)]
|
||||
|
||||
|
||||
class Notification(PageRegion):
|
||||
_body_locator = (By.CSS_SELECTOR, 'div.detail')
|
||||
_title_locator = (By.CSS_SELECTOR, 'div.title')
|
||||
|
||||
@property
|
||||
def is_visible(self):
|
||||
return self.root_element.is_displayed()
|
||||
|
||||
@property
|
||||
def content(self):
|
||||
return self.root_element.find_element(*self._body_locator).text
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
return self.root_element.find_element(*self._title_locator).text
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import By, Wait
|
||||
from marionette_driver.marionette import Actions
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.homescreen.app import Homescreen
|
||||
from gaiatest.apps.emergency_call.app import EmergencyCall
|
||||
|
||||
|
||||
class PasscodePad(Base):
|
||||
|
||||
_lockscreen_passcode_code_locator = (By.ID, 'lockscreen-passcode-code')
|
||||
_lockscreen_passcode_pad_locator = (By.ID, 'lockscreen-passcode-pad')
|
||||
_numeric_button_locator = (By.CSS_SELECTOR, '#lockscreen-passcode-pad a[data-key="%s"]')
|
||||
_emergency_button_locator = (By.CSS_SELECTOR, '#lockscreen-passcode-pad a[data-key="e"]')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
lockscreen_passcode_pad = self.marionette.find_element(*self._lockscreen_passcode_pad_locator)
|
||||
emergency_button = self.marionette.find_element(*self._emergency_button_locator)
|
||||
# wait button * 4 rows === the pad's height
|
||||
Wait(self.marionette).until(
|
||||
lambda m: lockscreen_passcode_pad.size['height'] ==
|
||||
(4 * emergency_button.size['height']))
|
||||
|
||||
def type_passcode(self, passcode):
|
||||
for digit in passcode:
|
||||
button_locator = (self._numeric_button_locator[0],
|
||||
self._numeric_button_locator[1] % digit)
|
||||
# Workaround for bug 1203269 where the Marionette tap() method somehow enters
|
||||
# 2 digits in the passcode pad
|
||||
Actions(self.marionette).press(
|
||||
self.marionette.find_element(*button_locator)).wait(time=0.5).release().perform()
|
||||
return Homescreen(self.marionette)
|
||||
|
||||
def tap_emergency_call(self):
|
||||
self.marionette.find_element(*self._emergency_button_locator).tap()
|
||||
emergency_call = EmergencyCall(self.marionette)
|
||||
return emergency_call
|
||||
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/marketplace/__init__.py
Executable file
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/marketplace/__init__.py
Executable file
122
gaia/tests/python/gaia-ui-tests/gaiatest/apps/marketplace/app.py
Executable file
122
gaia/tests/python/gaia-ui-tests/gaiatest/apps/marketplace/app.py
Executable file
|
|
@ -0,0 +1,122 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
from marionette_driver.keys import Keys
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.base import PageRegion
|
||||
from gaiatest.apps.homescreen.regions.confirm_install import ConfirmInstall
|
||||
from gaiatest.apps.system.app import System
|
||||
|
||||
|
||||
class Marketplace(Base):
|
||||
|
||||
_loading_fragment_locator = (By.ID, 'splash-overlay')
|
||||
_search_locator = (By.ID, 'search-q')
|
||||
_filter_locator = (By.ID, 'compat-filter')
|
||||
_marketplace_iframe_locator = (By.CSS_SELECTOR, 'iframe[src*="marketplace"]')
|
||||
_search_toggle_locator = (By.CLASS_NAME, 'mkt-search-btn')
|
||||
|
||||
name = 'Marketplace'
|
||||
manifest_url = 'https://marketplace.firefox.com/packaged.webapp'
|
||||
|
||||
def _switch_to_app(self):
|
||||
iframe = Wait(self.marionette).until(
|
||||
expected.element_present(*self._marketplace_iframe_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(iframe))
|
||||
self.marionette.switch_to_frame(iframe)
|
||||
|
||||
def search(self, term):
|
||||
self._switch_to_app()
|
||||
|
||||
# This sleep seems necessary, otherwise on device we get timeout failure on display search_box sometimes, see bug 1136791
|
||||
import time
|
||||
time.sleep(10)
|
||||
|
||||
search_toggle = Wait(self.marionette).until(
|
||||
expected.element_present(*self._search_toggle_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(search_toggle))
|
||||
search_toggle.tap()
|
||||
|
||||
search_box = Wait(self.marionette).until(
|
||||
expected.element_present(*self._search_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(search_box))
|
||||
|
||||
# This sleep is necessary, otherwise the search results are not shown on desktop b2g
|
||||
import time
|
||||
time.sleep(0.5)
|
||||
|
||||
# search for the app
|
||||
search_box.send_keys(term)
|
||||
search_box.send_keys(Keys.RETURN)
|
||||
return SearchResults(self.marionette)
|
||||
|
||||
def get_current_displayed_result(self):
|
||||
self._switch_to_app()
|
||||
return SearchResults(self.marionette)
|
||||
|
||||
class SearchResults(Base):
|
||||
|
||||
_search_results_loading_locator = (By.CSS_SELECTOR, '.loading')
|
||||
_search_result_locator = (By.CSS_SELECTOR, '#search-results li.item')
|
||||
|
||||
@property
|
||||
def search_results(self):
|
||||
results = Wait(self.marionette).until(
|
||||
lambda m: m.find_elements(*self._search_result_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(results[0]))
|
||||
return [Result(self.marionette, result) for result in results]
|
||||
|
||||
class Result(PageRegion):
|
||||
|
||||
_install_button_locator = (By.CSS_SELECTOR, '.button.install')
|
||||
_name_locator = (By.CSS_SELECTOR, 'h3[itemprop="name"]')
|
||||
|
||||
def tap_install_button(self):
|
||||
self.root_element.find_element(*self._install_button_locator).tap()
|
||||
self.marionette.switch_to_frame()
|
||||
|
||||
def tap_open_app_button(self, _app_locator):
|
||||
button = self.root_element.find_element(*self._install_button_locator)
|
||||
Wait(self.marionette).until(lambda m: button.text == 'Open app')
|
||||
button.tap()
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
app_element = self.marionette.find_element(*_app_locator)
|
||||
Wait(self.marionette).until(lambda m: app_element.is_displayed())
|
||||
|
||||
def get_app_name(self):
|
||||
return self.root_element.find_element(*self._name_locator).text
|
||||
|
||||
class MarketplaceDev(Marketplace):
|
||||
|
||||
name = 'Dev'
|
||||
manifest_url = 'https://marketplace.firefox.com/app/bee10fbb-7829-4d99-8a9f-a6d0a905138e/manifest.webapp'
|
||||
|
||||
def install_addon(self, addon_name):
|
||||
# Shortcut, go directly to the Addon page
|
||||
self.marionette.navigate('https://marketplace-dev.allizom.org/addon/%s' % addon_name)
|
||||
|
||||
addon_page = AddonPage(self.marionette)
|
||||
addon_page.install_link()
|
||||
|
||||
class AddonPage(Base):
|
||||
|
||||
_addon_install_locator = (By.CSS_SELECTOR, 'button.install')
|
||||
|
||||
def install_link(self):
|
||||
element = Wait(self.marionette, timeout=20, interval=1).until(
|
||||
expected.element_present(*self._addon_install_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
element.tap()
|
||||
|
||||
confirm_install = ConfirmInstall(self.marionette)
|
||||
confirm_install.tap_confirm()
|
||||
|
||||
system = System(self.marionette)
|
||||
system.wait_for_system_banner_displayed()
|
||||
system.wait_for_system_banner_not_displayed()
|
||||
|
||||
self.apps.switch_to_displayed_app()
|
||||
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/messages/__init__.py
Executable file
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/messages/__init__.py
Executable file
122
gaia/tests/python/gaia-ui-tests/gaiatest/apps/messages/app.py
Executable file
122
gaia/tests/python/gaia-ui-tests/gaiatest/apps/messages/app.py
Executable file
|
|
@ -0,0 +1,122 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.base import PageRegion
|
||||
|
||||
|
||||
class Messages(Base):
|
||||
|
||||
name = 'Messages'
|
||||
manifest_url = '{}sms{}/manifest.webapp'.format(Base.DEFAULT_PROTOCOL, Base.DEFAULT_APP_HOSTNAME)
|
||||
|
||||
_create_new_message_locator = (By.ID, 'threads-composer-link')
|
||||
_first_message_locator = (By.ID, 'thread-1')
|
||||
_messages_frame_locator = (By.CSS_SELECTOR, 'iframe[data-url*=sms]')
|
||||
_settings_icon_locator = (By.ID, 'threads-settings-button')
|
||||
_app_ready_locator = (By.CLASS_NAME, 'js-app-ready')
|
||||
_thread_items_locator = (By.CSS_SELECTOR, 'li.threadlist-item')
|
||||
_draft_message_locator = (By.CSS_SELECTOR, 'li.draft')
|
||||
_thread_options_button = (By.ID, 'threads-options-button')
|
||||
_delete_thread_button = (By.ID, 'threads-delete-button')
|
||||
_edit_thread_header = (By.ID, 'threads-edit-header')
|
||||
_banner_locator = (By.ID, 'threads-draft-saved-banner')
|
||||
|
||||
def launch(self):
|
||||
Base.launch(self)
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._app_ready_locator))))
|
||||
|
||||
def create_new_message(self, recipients, message):
|
||||
new_message = self.tap_create_new_message()
|
||||
for recipient in recipients:
|
||||
new_message.type_phone_number(recipient)
|
||||
new_message.type_message(message)
|
||||
return new_message
|
||||
|
||||
def tap_create_new_message(self):
|
||||
self.marionette.find_element(*self._create_new_message_locator).tap()
|
||||
from gaiatest.apps.messages.regions.new_message import NewMessage
|
||||
return NewMessage(self.marionette)
|
||||
|
||||
def tap_settings(self):
|
||||
self.marionette.find_element(*self._settings_icon_locator).tap()
|
||||
from gaiatest.apps.settings.app import Settings
|
||||
Settings(self.marionette).wait_to_be_displayed()
|
||||
self.apps.switch_to_displayed_app()
|
||||
from gaiatest.apps.messages.regions.messaging_settings import MessagingSettings
|
||||
return MessagingSettings(self.marionette)
|
||||
|
||||
def wait_for_message_list(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._create_new_message_locator))))
|
||||
|
||||
def wait_for_message_received(self, timeout=180):
|
||||
Wait(self.marionette, timeout).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._first_message_locator))))
|
||||
|
||||
def tap_first_received_message(self):
|
||||
self.marionette.find_element(*self._first_message_locator).tap()
|
||||
from gaiatest.apps.messages.regions.message_thread import MessageThread
|
||||
return MessageThread(self.marionette)
|
||||
|
||||
def tap_thread_options(self):
|
||||
self.marionette.find_element(*self._thread_options_button).tap()
|
||||
from gaiatest.apps.messages.regions.options import ThreadOptions
|
||||
return ThreadOptions(self.marionette)
|
||||
|
||||
def enter_select_mode(self):
|
||||
thread_options = self.tap_thread_options()
|
||||
thread_options.select_threads()
|
||||
self.wait_for_header_to_fully_appear()
|
||||
|
||||
def wait_for_header_to_fully_appear(self):
|
||||
edit_header = self.marionette.find_element(*self._edit_thread_header)
|
||||
Wait(self.marionette).until(lambda m: edit_header.is_displayed() and edit_header.rect['y'] == 0)
|
||||
|
||||
@property
|
||||
def is_in_select_mode(self):
|
||||
return self.marionette.find_element(*self._edit_thread_header).is_displayed()
|
||||
|
||||
def delete_selection(self):
|
||||
confirm_panel = self.tap_delete_button()
|
||||
confirm_panel.confirm_delete()
|
||||
|
||||
def tap_delete_button(self):
|
||||
self.marionette.find_element(*self._delete_thread_button).tap()
|
||||
from gaiatest.apps.messages.regions.options import ConfirmDeletionOptions
|
||||
return ConfirmDeletionOptions(self.marionette)
|
||||
|
||||
def wait_for_banner_to_hide(self):
|
||||
Wait(self.marionette).until(expected.element_not_displayed(*self._banner_locator))
|
||||
|
||||
@property
|
||||
def threads(self):
|
||||
return [self.Thread(self.marionette, message)
|
||||
for message in self.marionette.find_elements(*self._thread_items_locator)]
|
||||
|
||||
@property
|
||||
def draft_threads(self):
|
||||
return [self.Thread(self.marionette, draft_message)
|
||||
for draft_message in self.marionette.find_elements(*self._draft_message_locator)]
|
||||
|
||||
class Thread(PageRegion):
|
||||
_draft_icon_locator = (By.CSS_SELECTOR, '.icon-draft[data-l10n-id="is-draft"]')
|
||||
|
||||
@property
|
||||
def is_draft_icon_displayed(self):
|
||||
return self.root_element.find_element(*self._draft_icon_locator).is_displayed()
|
||||
|
||||
def open(self):
|
||||
self.root_element.tap()
|
||||
from gaiatest.apps.messages.regions.new_message import NewMessage
|
||||
return NewMessage(self.marionette)
|
||||
|
||||
def choose(self):
|
||||
self.root_element.tap()
|
||||
78
gaia/tests/python/gaia-ui-tests/gaiatest/apps/messages/regions/activities.py
Executable file
78
gaia/tests/python/gaia-ui-tests/gaiatest/apps/messages/regions/activities.py
Executable file
|
|
@ -0,0 +1,78 @@
|
|||
# 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 gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class Activities(Base):
|
||||
|
||||
_actions_menu_locator = (By.CSS_SELECTOR, 'body > form[data-type="action"]')
|
||||
_settings_button_locator = (By.XPATH, '//*[text()="Settings"]')
|
||||
_add_subject_button_locator = (By.CSS_SELECTOR, 'button[data-l10n-id="add-subject"]')
|
||||
_add_to_contact_button_locator = (By.XPATH, '//*[text()="Add to an existing contact"]')
|
||||
_create_new_contact_button_locator = (By.CSS_SELECTOR, 'button[data-l10n-id="createNewContact"]')
|
||||
_forward_message_button_locator = (By.CSS_SELECTOR, 'button[data-l10n-id="forward"]')
|
||||
_delete_message_button_locator = (By.CSS_SELECTOR, 'form[data-type="action"] button[data-l10n-id="delete"]')
|
||||
_confirm_delete_message_locator = (By.CSS_SELECTOR, 'button.danger')
|
||||
_view_message_report_locator = (By.CSS_SELECTOR, 'button[data-l10n-id="view-message-report"]')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._actions_menu_locator))))
|
||||
# TODO Difficult intermittent bug 977052
|
||||
time.sleep(1)
|
||||
|
||||
def tap_report(self):
|
||||
self.marionette.find_element(*self._view_message_report_locator).tap()
|
||||
from gaiatest.apps.messages.regions.report import Report
|
||||
return Report(self.marionette)
|
||||
|
||||
def tap_settings(self):
|
||||
self.marionette.find_element(*self._settings_button_locator).tap()
|
||||
from gaiatest.apps.Settings.app import Settings
|
||||
Settings(self.marionette).wait_to_be_displayed()
|
||||
self.apps.switch_to_displayed_app()
|
||||
from gaiatest.apps.messages.regions.messaging_settings import MessagingSettings
|
||||
return MessagingSettings(self.marionette)
|
||||
|
||||
def tap_add_subject(self):
|
||||
self.marionette.find_element(*self._add_subject_button_locator).tap()
|
||||
|
||||
def tap_add_to_contact(self):
|
||||
self.marionette.find_element(*self._add_to_contact_button_locator).tap()
|
||||
|
||||
from gaiatest.apps.contacts.app import Contacts
|
||||
contacts = Contacts(self.marionette)
|
||||
contacts.switch_to_contacts_frame()
|
||||
return contacts
|
||||
|
||||
def tap_create_new_contact(self):
|
||||
self.marionette.find_element(*self._create_new_contact_button_locator).tap()
|
||||
|
||||
from gaiatest.apps.contacts.regions.contact_form import NewContact
|
||||
new_contact = NewContact(self.marionette)
|
||||
new_contact.switch_to_new_contact_form()
|
||||
return new_contact
|
||||
|
||||
def tap_forward_message(self):
|
||||
self.marionette.find_element(*self._forward_message_button_locator).tap()
|
||||
from gaiatest.apps.messages.regions.new_message import NewMessage
|
||||
return NewMessage(self.marionette)
|
||||
|
||||
def tap_delete_message(self):
|
||||
delete_message_button = self.marionette.find_element(*self._delete_message_button_locator)
|
||||
Wait(self.marionette).until(expected.element_displayed(delete_message_button))
|
||||
delete_message_button.tap()
|
||||
|
||||
def confirm_delete_message(self):
|
||||
confirm_delete_message = self.marionette.find_element(*self._confirm_delete_message_locator)
|
||||
Wait(self.marionette).until(expected.element_displayed(confirm_delete_message))
|
||||
confirm_delete_message.tap()
|
||||
Wait(self.marionette).until(expected.element_not_displayed(confirm_delete_message))
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class AttachmentOptions(Base):
|
||||
|
||||
_attachment_options_locator = (By.CSS_SELECTOR, 'form.visible[role="dialog"][data-subtype="menu"]')
|
||||
_view_button_locator = (By.CSS_SELECTOR, 'button[data-l10n-id="view-attachment-image"]')
|
||||
_cancel_button_locator = (By.CSS_SELECTOR, 'button[data-l10n-id="cancel"]')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
root_element = self.root_element
|
||||
Wait(self.marionette).until(lambda m: root_element.location['y'] == 0)
|
||||
|
||||
def tap_cancel(self):
|
||||
root_element = self.root_element
|
||||
root_element.find_element(*self._cancel_button_locator).tap()
|
||||
Wait(self.marionette).until(expected.element_not_displayed(root_element))
|
||||
|
||||
def tap_view_button(self):
|
||||
self.root_element.find_element(*self._view_button_locator).tap()
|
||||
from gaiatest.apps.gallery.regions.view_image import ViewImage
|
||||
return ViewImage(self.marionette)
|
||||
|
||||
@property
|
||||
def root_element(self):
|
||||
return self.marionette.find_element(*self._attachment_options_locator)
|
||||
115
gaia/tests/python/gaia-ui-tests/gaiatest/apps/messages/regions/message_thread.py
Executable file
115
gaia/tests/python/gaia-ui-tests/gaiatest/apps/messages/regions/message_thread.py
Executable file
|
|
@ -0,0 +1,115 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
from marionette_driver.marionette import Actions
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.base import PageRegion
|
||||
from gaiatest.apps.messages.app import Messages
|
||||
|
||||
|
||||
class MessageThread(Base):
|
||||
|
||||
_all_messages_locator = (By.CSS_SELECTOR, '#messages-container li.message')
|
||||
_received_message_content_locator = (By.CSS_SELECTOR, "#messages-container li.message.received")
|
||||
_sent_message_locator = (By.CSS_SELECTOR, '#messages-container li.message.sent')
|
||||
_header_link_locator = (By.ID, 'messages-header')
|
||||
_message_header_locator = (By.ID, 'messages-header-text')
|
||||
_call_button_locator = (By.ID, 'messages-call-number-button')
|
||||
|
||||
def wait_for_received_messages(self, interval=5, timeout=300):
|
||||
Wait(self.marionette, timeout).until(expected.element_displayed(
|
||||
Wait(self.marionette, timeout).until(expected.element_present(
|
||||
*self._received_message_content_locator))))
|
||||
|
||||
def tap_back_button(self):
|
||||
# In a message thread, tap the back button to return to main message list
|
||||
|
||||
# TODO: remove tap with coordinates after Bug 1061698 is fixed
|
||||
self.marionette.find_element(*self._header_link_locator).tap(25, 25)
|
||||
|
||||
messages = Messages(self.marionette)
|
||||
messages.wait_for_message_list()
|
||||
return messages
|
||||
|
||||
@property
|
||||
def received_messages(self):
|
||||
return [Message(self.marionette, message) for message in self.marionette.find_elements(*self._received_message_content_locator)]
|
||||
|
||||
@property
|
||||
def sent_messages(self):
|
||||
return [Message(self.marionette, message) for message in self.marionette.find_elements(*self._sent_message_locator)]
|
||||
|
||||
@property
|
||||
def all_messages(self):
|
||||
return [Message(self.marionette, message) for message in self.marionette.find_elements(*self._all_messages_locator)]
|
||||
|
||||
@property
|
||||
def header_text(self):
|
||||
header = Wait(self.marionette).until(
|
||||
expected.element_present(*self._message_header_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(header))
|
||||
return header.text
|
||||
|
||||
def tap_header(self):
|
||||
element = self.marionette.find_element(*self._header_link_locator)
|
||||
Wait(self.marionette).until(lambda m: element.location['x'] == 0)
|
||||
self.marionette.find_element(*self._message_header_locator).tap()
|
||||
|
||||
from gaiatest.apps.messages.regions.activities import Activities
|
||||
return Activities(self.marionette)
|
||||
|
||||
def tap_call(self):
|
||||
call = Wait(self.marionette).until(expected.element_present(*self._call_button_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(call))
|
||||
call.tap()
|
||||
from gaiatest.apps.phone.regions.keypad import Keypad
|
||||
keypad = Keypad(self.marionette)
|
||||
keypad.wait_for_phone_number_ready()
|
||||
return keypad
|
||||
|
||||
|
||||
class Message(PageRegion):
|
||||
|
||||
_text_locator = (By.CSS_SELECTOR, '.bubble p')
|
||||
_attachments_locator = (By.CSS_SELECTOR, '.bubble .attachment-container.preview')
|
||||
_message_section_locator = (By.CSS_SELECTOR, '.bubble')
|
||||
|
||||
def open_report(self):
|
||||
activity = self.long_press_message()
|
||||
return activity.tap_report()
|
||||
|
||||
@property
|
||||
def text(self):
|
||||
return self.root_element.find_element(*self._text_locator).text
|
||||
|
||||
@property
|
||||
def has_attachments(self):
|
||||
try:
|
||||
self.root_element.find_element(*self._attachments_locator)
|
||||
except:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def tap_attachment(self):
|
||||
self.root_element.find_element(*self._attachments_locator).tap()
|
||||
from gaiatest.apps.gallery.regions.view_image import ViewImage
|
||||
return ViewImage(self.marionette)
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
return self.root_element.get_attribute('id')
|
||||
|
||||
def long_press_message(self):
|
||||
message = self.root_element.find_element(*self._message_section_locator)
|
||||
Actions(self.marionette).\
|
||||
press(message).\
|
||||
wait(3).\
|
||||
release().\
|
||||
perform()
|
||||
|
||||
from gaiatest.apps.messages.regions.activities import Activities
|
||||
return Activities(self.marionette)
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class MessagingSettings(Base):
|
||||
|
||||
_messaging_settings_locator = (By.CSS_SELECTOR, "h1[data-l10n-id='messagingSettings-header']")
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(
|
||||
*self._messaging_settings_locator))))
|
||||
|
||||
def is_messaging_settings_displayed(self):
|
||||
return self.is_element_displayed(*self._messaging_settings_locator)
|
||||
156
gaia/tests/python/gaia-ui-tests/gaiatest/apps/messages/regions/new_message.py
Executable file
156
gaia/tests/python/gaia-ui-tests/gaiatest/apps/messages/regions/new_message.py
Executable file
|
|
@ -0,0 +1,156 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.contacts.app import Contacts
|
||||
from gaiatest.apps.messages.app import Messages
|
||||
from gaiatest.form_controls.header import GaiaHeader
|
||||
|
||||
|
||||
class NewMessage(Messages):
|
||||
|
||||
_recipient_section_locator = (By.ID, 'messages-recipients-list')
|
||||
_receiver_input_locator = (By.CSS_SELECTOR, '#messages-recipients-list span.recipient')
|
||||
_add_recipient_button_locator = (By.ID, 'messages-contact-pick-button')
|
||||
_message_field_locator = (By.ID, 'messages-input')
|
||||
_send_message_button_locator = (By.ID, 'messages-send-button')
|
||||
_attach_button_locator = (By.ID, 'messages-attach-button')
|
||||
_options_button_locator = (By.ID, 'messages-options-button')
|
||||
_message_sending_locator = (By.CSS_SELECTOR, "li.message.outgoing.sending")
|
||||
_panel_conversationview_locator = (By.CSS_SELECTOR, '.panel-ConversationView')
|
||||
_message_resize_notice_locator = (By.ID, 'messages-resize-notice')
|
||||
_subject_input_locator = (By.CSS_SELECTOR, '.subject-composer-input')
|
||||
_image_attachment_locator = (By.CSS_SELECTOR, '.attachment-container.preview')
|
||||
_recipients_locator = (By.CSS_SELECTOR, '#messages-recipients-list span')
|
||||
_header_locator = (By.ID, 'messages-header')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
self.wait_to_be_displayed()
|
||||
self.apps.switch_to_displayed_app()
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._panel_conversationview_locator))
|
||||
Wait(self.marionette, interval=1).until(
|
||||
lambda m: element.rect['x'] == 0 and element.is_displayed())
|
||||
|
||||
def type_phone_number(self, value):
|
||||
# tap on the parent element to activate editable
|
||||
self.marionette.find_element(*self._recipient_section_locator).tap()
|
||||
self.keyboard.send(value)
|
||||
|
||||
def type_message(self, value):
|
||||
# change the focus to the message field to enable the send button
|
||||
self.tap_message()
|
||||
self.keyboard.send(value)
|
||||
|
||||
def tap_message(self):
|
||||
message = Wait(self.marionette).until(
|
||||
expected.element_present(*self._message_field_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(message))
|
||||
message.tap()
|
||||
|
||||
def tap_image_attachment(self):
|
||||
self.marionette.find_element(*self._image_attachment_locator).tap()
|
||||
from gaiatest.apps.messages.regions.attachment_options import AttachmentOptions
|
||||
return AttachmentOptions(self.marionette)
|
||||
|
||||
def tap_send(self, timeout=120):
|
||||
send = Wait(self.marionette).until(
|
||||
expected.element_present(*self._send_message_button_locator))
|
||||
Wait(self.marionette).until(expected.element_enabled(send))
|
||||
send.tap()
|
||||
Wait(self.marionette, timeout=timeout).until(
|
||||
expected.element_not_present(*self._message_sending_locator))
|
||||
from gaiatest.apps.messages.regions.message_thread import MessageThread
|
||||
return MessageThread(self.marionette)
|
||||
|
||||
def tap_attachment(self):
|
||||
self.marionette.find_element(*self._attach_button_locator).tap()
|
||||
from gaiatest.apps.system.regions.activities import Activities
|
||||
return Activities(self.marionette)
|
||||
|
||||
def tap_add_recipient(self):
|
||||
self.marionette.find_element(*self._add_recipient_button_locator).tap()
|
||||
contacts_app = Contacts(self.marionette)
|
||||
contacts_app.switch_to_contacts_frame()
|
||||
return contacts_app
|
||||
|
||||
def tap_options(self):
|
||||
self.marionette.find_element(*self._options_button_locator).tap()
|
||||
from gaiatest.apps.messages.regions.activities import Activities
|
||||
return Activities(self.marionette)
|
||||
|
||||
def wait_for_recipients_displayed(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._receiver_input_locator))
|
||||
|
||||
def wait_for_resizing_to_finish(self):
|
||||
Wait(self.marionette).until(
|
||||
expected.element_not_displayed(*self._message_resize_notice_locator))
|
||||
|
||||
def wait_for_subject_input_displayed(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._subject_input_locator))
|
||||
|
||||
def wait_for_message_input_displayed(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._message_field_locator))
|
||||
|
||||
@property
|
||||
def first_recipient_name(self):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._receiver_input_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
return element.text
|
||||
|
||||
@property
|
||||
def number_of_recipients(self):
|
||||
# we need to subtract one as the last element is the current editable element
|
||||
return len(self.marionette.find_elements(*self._receiver_input_locator)) - 1
|
||||
|
||||
@property
|
||||
def recipient_css_class(self):
|
||||
return self.marionette.find_element(*self._receiver_input_locator).get_attribute('class')
|
||||
|
||||
@property
|
||||
def is_recipient_name_editable(self):
|
||||
return self.marionette.find_element(*self._receiver_input_locator).get_attribute('contenteditable')
|
||||
|
||||
@property
|
||||
def first_recipient_number_attribute(self):
|
||||
return self.marionette.find_element(*self._receiver_input_locator).get_attribute('data-number')
|
||||
|
||||
def tap_recipient_section(self):
|
||||
self.marionette.find_element(*self._recipient_section_locator).tap()
|
||||
from gaiatest.apps.keyboard.app import Keyboard
|
||||
return Keyboard(self.marionette)
|
||||
|
||||
@property
|
||||
def is_send_button_enabled(self):
|
||||
return self.marionette.find_element(*self._send_message_button_locator).is_enabled()
|
||||
|
||||
@property
|
||||
def message(self):
|
||||
return self.marionette.find_element(*self._message_field_locator).text
|
||||
|
||||
def tap_recipient_name(self):
|
||||
self.marionette.find_element(*self._receiver_input_locator).tap()
|
||||
|
||||
@property
|
||||
def recipients(self):
|
||||
return self.marionette.find_elements(*self._recipients_locator)
|
||||
|
||||
@property
|
||||
def has_attachment(self):
|
||||
return self.is_element_displayed(*self._image_attachment_locator)
|
||||
|
||||
def save_as_draft(self):
|
||||
draft_options = self.go_back()
|
||||
messages = draft_options.save()
|
||||
messages.wait_for_banner_to_hide()
|
||||
return messages
|
||||
|
||||
def go_back(self):
|
||||
GaiaHeader(self.marionette, self._header_locator).go_back()
|
||||
from gaiatest.apps.messages.regions.options import DraftOptions
|
||||
return DraftOptions(self.marionette)
|
||||
52
gaia/tests/python/gaia-ui-tests/gaiatest/apps/messages/regions/options.py
Executable file
52
gaia/tests/python/gaia-ui-tests/gaiatest/apps/messages/regions/options.py
Executable file
|
|
@ -0,0 +1,52 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
from gaiatest.apps.base import PageRegion
|
||||
|
||||
|
||||
class SmsOptions(PageRegion):
|
||||
|
||||
_root_locator = (By.CSS_SELECTOR, 'form.visible')
|
||||
|
||||
def __init__(self, marionette):
|
||||
root = marionette.find_element(*self._root_locator)
|
||||
PageRegion.__init__(self, marionette, root)
|
||||
self.wait_for_panel_to_appear()
|
||||
|
||||
def wait_for_panel_to_appear(self):
|
||||
Wait(self.marionette).until(lambda m: self.root_element.is_displayed() and self.root_element.rect['y'] == 0)
|
||||
|
||||
def wait_for_panel_to_hide(self):
|
||||
Wait(self.marionette).until(expected.element_not_displayed(self.root_element))
|
||||
|
||||
def _tap_and_wait_until_hidden(self, locator):
|
||||
self.root_element.find_element(*locator).tap()
|
||||
self.wait_for_panel_to_hide()
|
||||
from gaiatest.apps.messages.app import Messages
|
||||
return Messages(self.marionette)
|
||||
|
||||
|
||||
class ThreadOptions(SmsOptions):
|
||||
|
||||
_select_button_locator = (By.CSS_SELECTOR, 'button[data-l10n-id="selectThreads-label"]')
|
||||
|
||||
def select_threads(self):
|
||||
return self._tap_and_wait_until_hidden(self._select_button_locator)
|
||||
|
||||
|
||||
class DraftOptions(SmsOptions):
|
||||
|
||||
_save_button_locator = (By.CSS_SELECTOR, 'button[data-l10n-id="save-as-draft"]')
|
||||
|
||||
def save(self):
|
||||
return self._tap_and_wait_until_hidden(self._save_button_locator)
|
||||
|
||||
|
||||
class ConfirmDeletionOptions(SmsOptions):
|
||||
|
||||
_confirm_delete_button_locator = (By.CSS_SELECTOR, 'button[data-l10n-id="delete"]')
|
||||
|
||||
def confirm_delete(self):
|
||||
return self._tap_and_wait_until_hidden(self._confirm_delete_button_locator)
|
||||
43
gaia/tests/python/gaia-ui-tests/gaiatest/apps/messages/regions/report.py
Executable file
43
gaia/tests/python/gaia-ui-tests/gaiatest/apps/messages/regions/report.py
Executable file
|
|
@ -0,0 +1,43 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.form_controls.header import GaiaHeader
|
||||
|
||||
class Report(Base):
|
||||
|
||||
_text_type = (By.CSS_SELECTOR, 'p[data-l10n-id="message-type-sms"]')
|
||||
_time_sent_locator = (By.CSS_SELECTOR, 'span.sent-timestamp')
|
||||
_time_received_locator = (By.CSS_SELECTOR, 'span.received-timestamp')
|
||||
_header_locator = (By.ID, 'information-report-header')
|
||||
|
||||
_sender_locator = (By.CSS_SELECTOR, 'span[data-l10n-id="report-from-title"] ~ .contact-list .js-contact-info')
|
||||
_receiver_locator = (By.CSS_SELECTOR, 'span[data-l10n-id="report-to-title"] ~ .contact-list .js-contact-info')
|
||||
|
||||
def close(self):
|
||||
GaiaHeader(self.marionette, self._header_locator).go_back()
|
||||
from gaiatest.apps.messages.regions.message_thread import MessageThread
|
||||
return MessageThread(self.marionette)
|
||||
|
||||
def is_message_an_sms(self):
|
||||
return self.marionette.find_element(*self._text_type).get_attribute('data-l10n-id') == 'message-type-sms'
|
||||
|
||||
@property
|
||||
def sent_date(self):
|
||||
timestamp_in_milliseconds = self.marionette.find_element(*self._time_sent_locator).get_attribute('data-l10n-date')
|
||||
return ((int)(timestamp_in_milliseconds) // 1000)
|
||||
|
||||
@property
|
||||
def received_date(self):
|
||||
timestamp_in_milliseconds = self.marionette.find_element(*self._time_received_locator).get_attribute('data-l10n-date')
|
||||
return ((int)(timestamp_in_milliseconds) // 1000)
|
||||
|
||||
@property
|
||||
def sender(self):
|
||||
return self.marionette.find_element(*self._sender_locator).text
|
||||
|
||||
@property
|
||||
def receiver(self):
|
||||
return self.marionette.find_element(*self._receiver_locator).text
|
||||
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/music/__init__.py
Executable file
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/music/__init__.py
Executable file
93
gaia/tests/python/gaia-ui-tests/gaiatest/apps/music/app.py
Executable file
93
gaia/tests/python/gaia-ui-tests/gaiatest/apps/music/app.py
Executable file
|
|
@ -0,0 +1,93 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.music.regions.list_view import AlbumsView, ArtistsView, SongsView
|
||||
|
||||
|
||||
class Music(Base):
|
||||
|
||||
name = 'Music'
|
||||
manifest_url = '{}music{}/manifest.webapp'.format(Base.DEFAULT_PROTOCOL, Base.DEFAULT_APP_HOSTNAME)
|
||||
|
||||
_loading_spinner_locator = (By.ID, 'spinner-overlay')
|
||||
_active_view_locator = (By.CSS_SELECTOR, 'iframe.active[src*="/views/home/index.html"]')
|
||||
_music_tiles_locator = (By.ID, 'tiles')
|
||||
_views_locator = (By.ID, 'views')
|
||||
_tabs_locator = (By.ID, 'tabs')
|
||||
_empty_overlay_shadow_DOM_locator = (By.ID, 'empty-overlay')
|
||||
_empty_music_title_locator = (By.CSS_SELECTOR, '[data-l10n-id="empty-title"]')
|
||||
_empty_music_text_locator = (By.CSS_SELECTOR, '[data-l10n-id="empty-text"]')
|
||||
_albums_tab_locator = (By.CSS_SELECTOR, '[data-l10n-id="albums-tab"]')
|
||||
_songs_tab_locator = (By.CSS_SELECTOR, '[data-l10n-id="songs-tab"]')
|
||||
_artists_tab_locator = (By.CSS_SELECTOR, '[data-l10n-id="artists-tab"]')
|
||||
_title_locator = (By.ID, 'header-title')
|
||||
|
||||
def launch(self):
|
||||
Base.launch(self)
|
||||
Wait(self.marionette).until(expected.element_not_displayed(
|
||||
*self._loading_spinner_locator))
|
||||
|
||||
def wait_for_music_tiles_displayed(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._active_view_locator))
|
||||
self.marionette.switch_to_frame(self.marionette.find_element(*self._active_view_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._music_tiles_locator))
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def wait_for_empty_message_to_load(self):
|
||||
self.marionette.switch_to_shadow_root(self.marionette.find_element(*self._empty_overlay_shadow_DOM_locator))
|
||||
Wait(self.marionette).until(lambda m: self.empty_music_title != '')
|
||||
Wait(self.marionette).until(lambda m: self.empty_music_text != '')
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def wait_for_view_displayed(self, view_name):
|
||||
title = self.marionette.find_element(*self._title_locator)
|
||||
Wait(self.marionette).until(expected.element_displayed(title))
|
||||
Wait(self.marionette).until(lambda m: title.text == view_name)
|
||||
|
||||
@property
|
||||
def empty_music_title(self):
|
||||
return self.marionette.find_element(*self._empty_music_title_locator).text
|
||||
|
||||
@property
|
||||
def empty_music_text(self):
|
||||
return self.marionette.find_element(*self._empty_music_text_locator).text
|
||||
|
||||
@property
|
||||
def views(self):
|
||||
return self.marionette.find_element(*self._views_locator)
|
||||
|
||||
@property
|
||||
def tabs(self):
|
||||
return self.marionette.find_element(*self._tabs_locator)
|
||||
|
||||
def tap_albums_tab(self):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._albums_tab_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
element.tap()
|
||||
return AlbumsView(self.marionette)
|
||||
|
||||
def tap_songs_tab(self):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._songs_tab_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
element.tap()
|
||||
return SongsView(self.marionette)
|
||||
|
||||
def tap_artists_tab(self):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._artists_tab_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
element.tap()
|
||||
return ArtistsView(self.marionette)
|
||||
|
||||
def a11y_click_albums_tab(self):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._albums_tab_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
self.accessibility.click(element)
|
||||
return AlbumsView(self.marionette)
|
||||
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/music/regions/__init__.py
Executable file
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/music/regions/__init__.py
Executable file
80
gaia/tests/python/gaia-ui-tests/gaiatest/apps/music/regions/list_view.py
Executable file
80
gaia/tests/python/gaia-ui-tests/gaiatest/apps/music/regions/list_view.py
Executable file
|
|
@ -0,0 +1,80 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base, PageRegion
|
||||
from gaiatest.apps.music.regions.sublist_view import AlbumSublistView, ArtistSublistView
|
||||
from gaiatest.apps.music.regions.player_view import PlayerView
|
||||
|
||||
|
||||
class ListView(Base):
|
||||
|
||||
_list_item_locator = (By.CLASS_NAME, 'gfl-item')
|
||||
|
||||
def _set_active_view_locator(self, type):
|
||||
self._active_view_locator = (By.CSS_SELECTOR, 'iframe.active[src*="/views/{}/index.html"]'.format(type))
|
||||
|
||||
@property
|
||||
def media(self):
|
||||
self.marionette.switch_to_frame(self.marionette.find_element(*self._active_view_locator))
|
||||
elements = Wait(self.marionette).until(
|
||||
expected.elements_present(*self._list_item_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(elements[0]))
|
||||
self.apps.switch_to_displayed_app()
|
||||
return [Media(self.marionette, element, self._active_view_locator) for element in elements]
|
||||
|
||||
|
||||
class AlbumsView(ListView):
|
||||
def __init__(self, marionette):
|
||||
ListView.__init__(self, marionette)
|
||||
self._set_active_view_locator('albums')
|
||||
|
||||
|
||||
class ArtistsView(ListView):
|
||||
def __init__(self, marionette):
|
||||
ListView.__init__(self, marionette)
|
||||
self._set_active_view_locator('artists')
|
||||
|
||||
|
||||
class SongsView(ListView):
|
||||
def __init__(self, marionette):
|
||||
ListView.__init__(self, marionette)
|
||||
self._set_active_view_locator('songs')
|
||||
|
||||
|
||||
class Media(PageRegion):
|
||||
_first_media_link_locator = (By.CLASS_NAME, 'gfl-item first')
|
||||
|
||||
def __init__(self, marionette, element, _active_view_locator):
|
||||
PageRegion.__init__(self, marionette, element)
|
||||
self._active_view_locator = _active_view_locator
|
||||
|
||||
def switch_to_active_view(self):
|
||||
self.marionette.switch_to_frame(self.marionette.find_element(*self._active_view_locator))
|
||||
|
||||
def tap_first_album(self):
|
||||
self.switch_to_active_view()
|
||||
self.marionette.find_element(*self._first_media_link_locator).tap()
|
||||
self.apps.switch_to_displayed_app()
|
||||
return AlbumSublistView(self.marionette)
|
||||
|
||||
def tap_first_song(self):
|
||||
self.switch_to_active_view()
|
||||
self.marionette.find_element(*self._first_media_link_locator).tap()
|
||||
self.apps.switch_to_displayed_app()
|
||||
return PlayerView(self.marionette)
|
||||
|
||||
def tap_first_artist(self):
|
||||
self.switch_to_active_view()
|
||||
self.marionette.find_element(*self._first_media_link_locator).tap()
|
||||
self.apps.switch_to_displayed_app()
|
||||
return ArtistSublistView(self.marionette)
|
||||
|
||||
def a11y_click_first_album(self):
|
||||
self.switch_to_active_view()
|
||||
self.accessibility.click(
|
||||
self.marionette.find_element(*self._first_media_link_locator))
|
||||
self.apps.switch_to_displayed_app()
|
||||
return AlbumSublistView(self.marionette)
|
||||
109
gaia/tests/python/gaia-ui-tests/gaiatest/apps/music/regions/player_view.py
Executable file
109
gaia/tests/python/gaia-ui-tests/gaiatest/apps/music/regions/player_view.py
Executable file
|
|
@ -0,0 +1,109 @@
|
|||
# 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 gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class PlayerView(Base):
|
||||
_audio_locator = (By.ID, 'audio')
|
||||
_active_view_locator = (By.CSS_SELECTOR, 'iframe.active[src*="/views/player/index.html"]')
|
||||
_player_seek_elapsed_locator = (By.ID, 'elapsed-time')
|
||||
_player_controls_shadow_dom_locator = (By.ID, 'controls')
|
||||
_player_controls_play_locator = (By.ID, 'toggle')
|
||||
_player_controls_forward_locator = (By.ID, 'next')
|
||||
_cover_image_shadow_dom_locator = (By.ID, 'artwork')
|
||||
_seek_bar_shadow_dom_locator = (By.ID, 'seek-bar')
|
||||
_cover_share_locator = (By.CSS_SELECTOR, '[data-l10n-id="share-song"]')
|
||||
_rating_view_locator = (By.ID, 'rating')
|
||||
_stars_on_locator = (By.CSS_SELECTOR, '.rating-star.star-on')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
self.marionette.switch_to_frame(self.marionette.find_element(*self._active_view_locator))
|
||||
element = self.marionette.find_element(*self._cover_image_shadow_dom_locator)
|
||||
Wait(self.marionette).until(lambda m: element.rect['x'] == 0 and element.is_displayed())
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def tap_play(self):
|
||||
self.marionette.switch_to_frame(self.marionette.find_element(*self._active_view_locator))
|
||||
self.marionette.switch_to_shadow_root(self.marionette.find_element(*self._player_controls_shadow_dom_locator))
|
||||
self.marionette.find_element(*self._player_controls_play_locator).tap()
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def tap_forward(self):
|
||||
self.marionette.switch_to_frame(self.marionette.find_element(*self._active_view_locator))
|
||||
self.marionette.switch_to_shadow_root(self.marionette.find_element(*self._player_controls_shadow_dom_locator))
|
||||
self.marionette.find_element(*self._player_controls_forward_locator).tap()
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def tap_cover_in_player_view(self):
|
||||
self.marionette.switch_to_frame(self.marionette.find_element(*self._active_view_locator))
|
||||
self.marionette.switch_to_shadow_root(self.marionette.find_element(*self._cover_image_shadow_dom_locator))
|
||||
|
||||
#wait until the overlay disappears
|
||||
Wait(self.marionette).until(expected.element_not_displayed(*self._rating_view_locator))
|
||||
self.marionette.switch_to_shadow_root()
|
||||
|
||||
self.marionette.find_element(*self._cover_image_shadow_dom_locator).tap()
|
||||
self.marionette.switch_to_shadow_root(self.marionette.find_element(*self._cover_image_shadow_dom_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(*self._rating_view_locator))))
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def tap_share_button(self):
|
||||
self.marionette.switch_to_frame(self.marionette.find_element(*self._active_view_locator))
|
||||
self.marionette.switch_to_shadow_root(self.marionette.find_element(*self._cover_image_shadow_dom_locator))
|
||||
self.marionette.find_element(*self._cover_share_locator).tap()
|
||||
from gaiatest.apps.system.regions.activities import Activities
|
||||
return Activities(self.marionette)
|
||||
|
||||
def _get_star_locator(self, rating):
|
||||
return By.CSS_SELECTOR, 'button[value="%s"]' % rating
|
||||
|
||||
def tap_star(self, rate):
|
||||
"""
|
||||
give rating. (After tapping the cover to make the ratings overlay appear)
|
||||
"""
|
||||
self.tap_cover_in_player_view()
|
||||
self.marionette.switch_to_frame(self.marionette.find_element(*self._active_view_locator))
|
||||
self.marionette.switch_to_shadow_root(self.marionette.find_element(*self._cover_image_shadow_dom_locator))
|
||||
self.marionette.switch_to_shadow_root(self.marionette.find_element(*self._rating_view_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._get_star_locator(rate)))
|
||||
self.marionette.find_element(*self._get_star_locator(rate)).tap()
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
@property
|
||||
def star_rating(self):
|
||||
self.marionette.switch_to_frame(self.marionette.find_element(*self._active_view_locator))
|
||||
self.marionette.switch_to_shadow_root(self.marionette.find_element(*self._cover_image_shadow_dom_locator))
|
||||
rating = self.marionette.find_element(*self._rating_view_locator).get_attribute('value')
|
||||
self.apps.switch_to_displayed_app()
|
||||
return int(rating)
|
||||
|
||||
@property
|
||||
def player_elapsed_time(self):
|
||||
self.marionette.switch_to_frame(self.marionette.find_element(*self._active_view_locator))
|
||||
self.marionette.switch_to_shadow_root(self.marionette.find_element(*self._seek_bar_shadow_dom_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(*self._player_seek_elapsed_locator))))
|
||||
elapsed_time = time.strptime(self.marionette.find_element(*self._player_seek_elapsed_locator).text, '%M:%S')
|
||||
self.apps.switch_to_displayed_app()
|
||||
return elapsed_time
|
||||
|
||||
def is_player_playing(self):
|
||||
# get 4 timestamps during approx. 1 sec
|
||||
# ensure that newer timestamp has greater value than previous one
|
||||
timestamps = []
|
||||
for i in range(4):
|
||||
timestamps.append(self.player_current_timestamp)
|
||||
time.sleep(.25)
|
||||
return all([timestamps[i - 1] < timestamps[i] for i in range(1, 3)])
|
||||
|
||||
@property
|
||||
def player_current_timestamp(self):
|
||||
player = self.marionette.find_element(*self._audio_locator)
|
||||
return float(player.get_attribute('currentTime'))
|
||||
49
gaia/tests/python/gaia-ui-tests/gaiatest/apps/music/regions/sublist_view.py
Executable file
49
gaia/tests/python/gaia-ui-tests/gaiatest/apps/music/regions/sublist_view.py
Executable file
|
|
@ -0,0 +1,49 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.music.regions.player_view import PlayerView
|
||||
|
||||
|
||||
class SublistView(Base):
|
||||
|
||||
_list_locator = (By.ID, 'list')
|
||||
_first_song_locator = (By.CLASS_NAME, 'gfl-item first')
|
||||
|
||||
def _set_active_view(self, type):
|
||||
self._active_view_locator = (By.CSS_SELECTOR, 'iframe.active[src*="/views/{}-detail/index.html"]'.format(type))
|
||||
|
||||
def switch_to_active_view(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._active_view_locator))
|
||||
self.marionette.switch_to_frame(self.marionette.find_element(*self._active_view_locator))
|
||||
|
||||
def wait_sublist_view_draw(self):
|
||||
self.switch_to_active_view()
|
||||
element = self.marionette.find_element(*self._list_locator)
|
||||
Wait(self.marionette).until(lambda m: element.rect['x'] == 0 and element.is_displayed())
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def tap_first_song(self):
|
||||
self.switch_to_active_view()
|
||||
song = Wait(self.marionette).until(
|
||||
expected.element_present(*self._first_song_locator))
|
||||
song.tap()
|
||||
self.apps.switch_to_displayed_app()
|
||||
return PlayerView(self.marionette)
|
||||
|
||||
|
||||
class AlbumSublistView(SublistView):
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
self._set_active_view('album')
|
||||
self.wait_sublist_view_draw()
|
||||
|
||||
|
||||
class ArtistSublistView(SublistView):
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
self._set_active_view('artist')
|
||||
self.wait_sublist_view_draw()
|
||||
29
gaia/tests/python/gaia-ui-tests/gaiatest/apps/music/regions/tile_view.py
Executable file
29
gaia/tests/python/gaia-ui-tests/gaiatest/apps/music/regions/tile_view.py
Executable file
|
|
@ -0,0 +1,29 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.music.regions.player_view import PlayerView
|
||||
|
||||
|
||||
class TileView(Base):
|
||||
|
||||
_active_view_locator = (By.CSS_SELECTOR, 'iframe.active[src*="/views/home/index.html"]')
|
||||
_tile_group_locator = (By.ID, 'tiles')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
|
||||
# there are two type of tiles - main and sub. There should be at least one main tile
|
||||
self.marionette.switch_to_frame(self.marionette.find_element(*self._active_view_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._tile_group_locator))
|
||||
self.apps.switch_to_displayed_app()
|
||||
|
||||
def tap_song(self, filename):
|
||||
self.marionette.switch_to_frame(self.marionette.find_element(*self._active_view_locator))
|
||||
_pick_tile_locator = (By.CSS_SELECTOR, '.tile[data-file-path$="{}"]'.format(filename))
|
||||
self.marionette.find_element(*_pick_tile_locator).tap()
|
||||
self.apps.switch_to_displayed_app()
|
||||
return PlayerView(self.marionette)
|
||||
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/music_oga/__init__.py
Executable file
0
gaia/tests/python/gaia-ui-tests/gaiatest/apps/music_oga/__init__.py
Executable file
88
gaia/tests/python/gaia-ui-tests/gaiatest/apps/music_oga/app.py
Executable file
88
gaia/tests/python/gaia-ui-tests/gaiatest/apps/music_oga/app.py
Executable file
|
|
@ -0,0 +1,88 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.music_oga.regions.list_view import ListView
|
||||
|
||||
|
||||
class Music(Base):
|
||||
|
||||
name = 'Music OGA'
|
||||
manifest_url = '{}music-oga{}/manifest.webapp'.format(Base.DEFAULT_PROTOCOL, Base.DEFAULT_APP_HOSTNAME)
|
||||
|
||||
_loading_spinner_locator = (By.ID, 'spinner-overlay')
|
||||
_music_tiles_locator = (By.CSS_SELECTOR, '#views-tiles-anchor > div')
|
||||
_views_locator = (By.ID, 'views')
|
||||
_tabs_locator = (By.ID, 'tabs')
|
||||
_empty_music_title_locator = (By.ID, 'overlay-title')
|
||||
_empty_music_text_locator = (By.ID, 'overlay-text')
|
||||
_albums_tab_locator = (By.ID, 'tabs-albums')
|
||||
_songs_tab_locator = (By.ID, 'tabs-songs')
|
||||
_artists_tab_locator = (By.ID, 'tabs-artists')
|
||||
_title_locator = (By.ID, 'title-text')
|
||||
|
||||
def launch(self):
|
||||
Base.launch(self)
|
||||
Wait(self.marionette).until(expected.element_not_displayed(
|
||||
*self._loading_spinner_locator))
|
||||
|
||||
def wait_for_music_tiles_displayed(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
*self._music_tiles_locator))
|
||||
|
||||
def wait_for_empty_message_to_load(self):
|
||||
element = self.marionette.find_element(*self._empty_music_title_locator)
|
||||
Wait(self.marionette).until(lambda m: not element.text == '')
|
||||
|
||||
def wait_for_view_displayed(self, view_name):
|
||||
title = self.marionette.find_element(*self._title_locator)
|
||||
Wait(self.marionette).until(expected.element_displayed(title))
|
||||
Wait(self.marionette).until(lambda m: title.text == view_name)
|
||||
|
||||
@property
|
||||
def empty_music_title(self):
|
||||
return self.marionette.find_element(*self._empty_music_title_locator).text
|
||||
|
||||
@property
|
||||
def empty_music_text(self):
|
||||
return self.marionette.find_element(*self._empty_music_text_locator).text
|
||||
|
||||
@property
|
||||
def views(self):
|
||||
return self.marionette.find_element(*self._views_locator)
|
||||
|
||||
@property
|
||||
def tabs(self):
|
||||
return self.marionette.find_element(*self._tabs_locator)
|
||||
|
||||
def tap_albums_tab(self):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._albums_tab_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
element.tap()
|
||||
return ListView(self.marionette)
|
||||
|
||||
def tap_songs_tab(self):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._songs_tab_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
element.tap()
|
||||
return ListView(self.marionette)
|
||||
|
||||
def tap_artists_tab(self):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._artists_tab_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
element.tap()
|
||||
return ListView(self.marionette)
|
||||
|
||||
def a11y_click_albums_tab(self):
|
||||
element = Wait(self.marionette).until(
|
||||
expected.element_present(*self._albums_tab_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(element))
|
||||
self.accessibility.click(element)
|
||||
return ListView(self.marionette)
|
||||
|
||||
50
gaia/tests/python/gaia-ui-tests/gaiatest/apps/music_oga/regions/list_view.py
Executable file
50
gaia/tests/python/gaia-ui-tests/gaiatest/apps/music_oga/regions/list_view.py
Executable file
|
|
@ -0,0 +1,50 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
|
||||
from gaiatest.apps.base import Base, PageRegion
|
||||
from gaiatest.apps.music_oga.regions.sublist_view import SublistView
|
||||
from gaiatest.apps.music_oga.regions.player_view import PlayerView
|
||||
|
||||
|
||||
class ListView(Base):
|
||||
|
||||
_view_locator = (By.ID, 'views')
|
||||
_list_item_locator = (By.CSS_SELECTOR, '.list-item')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
|
||||
Wait(self.marionette).until(
|
||||
lambda m: self.marionette.find_element(*self._view_locator).get_attribute('class') != 'scrolling')
|
||||
|
||||
@property
|
||||
def media(self):
|
||||
elements = Wait(self.marionette).until(
|
||||
expected.elements_present(*self._list_item_locator))
|
||||
Wait(self.marionette).until(expected.element_displayed(elements[0]))
|
||||
return [Media(self.marionette, element) for element in elements]
|
||||
|
||||
class Media(PageRegion):
|
||||
|
||||
_media_link_locator = (By.TAG_NAME, 'a')
|
||||
|
||||
def tap_first_album(self):
|
||||
self.marionette.find_element(*self._media_link_locator).tap()
|
||||
return SublistView(self.marionette)
|
||||
|
||||
def tap_first_song(self):
|
||||
self.marionette.find_element(*self._media_link_locator).tap()
|
||||
return PlayerView(self.marionette)
|
||||
|
||||
def tap_first_artist(self):
|
||||
self.marionette.find_element(*self._media_link_locator).tap()
|
||||
return SublistView(self.marionette)
|
||||
|
||||
def a11y_click_first_album(self):
|
||||
self.accessibility.click(
|
||||
self.marionette.find_element(*self._media_link_locator))
|
||||
return SublistView(self.marionette)
|
||||
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
# 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.marionette import Actions
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
|
||||
|
||||
class PlayerView(Base):
|
||||
_audio_locator = (By.ID, 'player-audio')
|
||||
_player_seek_elapsed_locator = (By.ID, 'player-seek-elapsed')
|
||||
_player_controls_play_locator = (By.ID, 'player-controls-play')
|
||||
_cover_image_locator = (By.CSS_SELECTOR, '.cover-image.visible')
|
||||
_cover_share_locator = (By.ID, 'player-cover-share')
|
||||
_rating_view_locator = (By.ID, 'player-album-rating')
|
||||
_stars_on_locator = (By.CSS_SELECTOR, '.rating-star.star-on')
|
||||
|
||||
def tap_play(self):
|
||||
self.marionette.find_element(*self._player_controls_play_locator).tap()
|
||||
|
||||
def tap_cover_in_player_view(self):
|
||||
self.marionette.find_element(*self._cover_image_locator).tap()
|
||||
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(*self._rating_view_locator))))
|
||||
|
||||
def tap_share_button(self):
|
||||
self.tap_cover_in_player_view()
|
||||
self.marionette.find_element(*self._cover_share_locator).tap()
|
||||
from gaiatest.apps.system.regions.activities import Activities
|
||||
return Activities(self.marionette)
|
||||
|
||||
def _get_star_locator(self, rating):
|
||||
return By.CSS_SELECTOR, '.rating-star[data-rating="%s"]' % rating
|
||||
|
||||
def tap_star(self, rate):
|
||||
"""
|
||||
give rating. (After tapping the cover to make the ratings overlay appear)
|
||||
"""
|
||||
|
||||
self.tap_cover_in_player_view()
|
||||
Wait(self.marionette).until(expected.element_displayed(*self._get_star_locator(rate)))
|
||||
self.marionette.find_element(*self._get_star_locator(rate)).tap()
|
||||
|
||||
@property
|
||||
def star_rating(self):
|
||||
return len(self.marionette.find_elements(*self._stars_on_locator))
|
||||
|
||||
@property
|
||||
def player_elapsed_time(self):
|
||||
Wait(self.marionette).until(expected.element_displayed(
|
||||
Wait(self.marionette).until(expected.element_present(*self._player_seek_elapsed_locator))))
|
||||
return time.strptime(self.marionette.find_element(*self._player_seek_elapsed_locator).text, '%M:%S')
|
||||
|
||||
def is_player_playing(self):
|
||||
# get 4 timestamps during approx. 1 sec
|
||||
# ensure that newer timestamp has greater value than previous one
|
||||
timestamps = []
|
||||
for i in range(4):
|
||||
timestamps.append(self.player_current_timestamp)
|
||||
time.sleep(.25)
|
||||
return all([timestamps[i - 1] < timestamps[i] for i in range(1, 3)])
|
||||
|
||||
@property
|
||||
def player_current_timestamp(self):
|
||||
player = self.marionette.find_element(*self._audio_locator)
|
||||
return float(player.get_attribute('currentTime'))
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
# 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/.
|
||||
|
||||
from marionette_driver import expected, By, Wait
|
||||
from marionette_driver.marionette import Actions
|
||||
|
||||
from gaiatest.apps.base import Base
|
||||
from gaiatest.apps.music_oga.regions.player_view import PlayerView
|
||||
|
||||
|
||||
class SublistView(Base):
|
||||
|
||||
_song_number_locator = (By.CSS_SELECTOR, 'bdi.list-song-index')
|
||||
_play_control_locator = (By.ID, 'views-sublist-controls-play')
|
||||
|
||||
def __init__(self, marionette):
|
||||
Base.__init__(self, marionette)
|
||||
element = self.marionette.find_element(*self._song_number_locator)
|
||||
Wait(self.marionette).until(lambda m: element.location['x'] == 0)
|
||||
|
||||
def tap_play(self):
|
||||
play = Wait(self.marionette).until(
|
||||
expected.element_present(*self._play_control_locator))
|
||||
# TODO: Change this to a simple tap when bug 862156 is fixed
|
||||
Actions(self.marionette).tap(play).perform()
|
||||
return PlayerView(self.marionette)
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue