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:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

View 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)