Skip to content

Commit d7aaf5f

Browse files
committed
Merge branch 'main' of github.com:mozilla/fx-desktop-qa-automation
2 parents edd1dcd + 0f7afde commit d7aaf5f

28 files changed

+224
-192
lines changed

SELECTOR_INFO.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,6 +1389,13 @@ Location: Appears as part of the dropdown under the autofill panel, within any e
13891389
Path to .json: modules/data/autofill_popup.components.json
13901390
```
13911391
```
1392+
Selector Name: select-form-option-by-index
1393+
Selector Data: ".autocomplete-richlistbox .autocomplete-richlistitem:nth:child({index})"
1394+
Description: Select n individual entry within the autofill dropdown, using the index of the child.
1395+
Location: Appears as part of the dropdown under the autofill panel, within any eligible form field when suggestions are available.
1396+
Path to .json: modules/data/autofill_popup.components.json
1397+
```
1398+
```
13921399
Selector Name: clear-form-option
13931400
Selector Data: ".autocomplete-richlistbox .autocomplete-richlistitem[ac-value='Clear Autofill Form']"
13941401
Description: The "Clear Autofill Form" option in the dropdown that appears when interacting with an autofill-enabled input field

l10n_CM/Unified/test_demo_ad_email_phone_captured_in_doorhanger_and_stored.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,17 @@ def test_demo_ad_email_phone_captured_in_doorhanger_and_stored(
3838

3939
# containing phone field
4040
expected_phone = address_autofill_data.telephone
41-
actual_phone = autofill_popup.get_cc_doorhanger_data("address-doorhanger-phone")
42-
normalize_expected = util.normalize_regional_phone_numbers(expected_phone, region)
43-
normalized_actual = util.normalize_regional_phone_numbers(actual_phone, region)
44-
assert normalized_actual == normalize_expected, (
45-
f"Phone number mismatch for {region} | Expected: {normalize_expected}, Got: {normalized_actual}"
46-
)
41+
# Skip verification if phone number isn't provided
42+
if expected_phone:
43+
with driver.context(driver.CONTEXT_CHROME):
44+
actual_phone = autofill_popup.get_element("address-doorhanger-phone").text
45+
normalize_expected = util.normalize_regional_phone_numbers(
46+
expected_phone, region
47+
)
48+
normalized_actual = util.normalize_regional_phone_numbers(actual_phone, region)
49+
assert normalized_actual == normalize_expected, (
50+
f"Phone number mismatch for {region} | Expected: {normalize_expected}, Got: {normalized_actual}"
51+
)
4752

4853
# Click the "Save" button
4954
autofill_popup.click_doorhanger_button("save")

modules/browser_object_autofill_popup.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,20 @@ def get_nth_element(self, index: str | int) -> WebElement:
8080
)
8181
)
8282

83+
def select_nth_element(self, index: int):
84+
"""
85+
Select the nth element from the autocomplete list
86+
Arguments:
87+
index (int): The index of the element to retrieve (1-based)
88+
"""
89+
with self.driver.context(self.driver.CONTEXT_CHROME):
90+
self.expect(
91+
EC.visibility_of(
92+
self.get_element("select-form-option-by-index", labels=[str(index)])
93+
)
94+
)
95+
self.get_element("select-form-option-by-index", labels=[str(index)]).click()
96+
8397
def get_primary_value(self, element: WebElement) -> str:
8498
"""
8599
Get the primary value from the autocomplete element

modules/data/autofill_popup.components.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@
6161
"groups": []
6262
},
6363

64+
"select-form-option-by-index": {
65+
"selectorData": ".autocomplete-richlistbox .autocomplete-richlistitem:nth-child({index})",
66+
"strategy":"css",
67+
"groups": []
68+
},
69+
6470
"update-card-info-popup-button": {
6571
"selectorData": "button[label='Update existing card']",
6672
"strategy": "css",

modules/page_base.py

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import os
44
import platform
55
import re
6+
import sys
67
import time
78
from copy import deepcopy
89
from pathlib import Path
@@ -678,20 +679,55 @@ def wait_for_num_tabs(self, num_tabs: int) -> Page:
678679

679680
def switch_to_new_tab(self) -> Page:
680681
"""Get list of all window handles, switch to the newly opened tab"""
681-
self.driver.switch_to.window(self.driver.window_handles[-1])
682+
with self.driver.context(self.driver.CONTEXT_CONTENT):
683+
self.driver.switch_to.window(self.driver.window_handles[-1])
682684
return self
683685

684686
def switch_to_new_window(self) -> Page:
685687
"""Switch to the most recently opened window. Can be a standard or private window"""
686-
all_window_handles = self.driver.window_handles
687-
self.driver.switch_to.window(all_window_handles[-1])
688+
with self.driver.context(self.driver.CONTEXT_CONTENT):
689+
all_window_handles = self.driver.window_handles
690+
self.driver.switch_to.window(all_window_handles[-1])
688691
return self
689692

690693
def wait_for_num_windows(self, num: int) -> Page:
691694
"""Wait for the number of open tabs + windows to equal given int"""
692695
with self.driver.context(self.driver.CONTEXT_CONTENT):
693696
return self.wait_for_num_tabs(num)
694697

698+
def open_and_switch_to_new_window(self, browser_window: str) -> Page:
699+
"""
700+
Opens a new browser window of the given type, then switches to it.
701+
702+
Parameters:
703+
browser_window: Can be a standard 'window', 'tab' or 'private' browser window.
704+
"""
705+
if browser_window == "private":
706+
self.open_and_switch_to_private_window_via_keyboard()
707+
else:
708+
self.driver.switch_to.new_window(browser_window)
709+
return self
710+
711+
def open_and_switch_to_private_window_via_keyboard(self) -> Page:
712+
"""
713+
Opens a new private browsing window via keyboard shortcut and switch to it
714+
"""
715+
# Keep track of window count to ensure we get a new one to switch to
716+
window_count = len(self.driver.window_handles)
717+
718+
with self.driver.context(self.driver.CONTEXT_CHROME):
719+
os_name = sys.platform
720+
mod_key = Keys.COMMAND if os_name == "darwin" else Keys.CONTROL
721+
self.actions.key_down(mod_key)
722+
self.actions.key_down(Keys.SHIFT)
723+
self.actions.send_keys("p")
724+
self.actions.key_up(Keys.SHIFT)
725+
self.actions.key_up(mod_key).perform()
726+
expected_window_count = window_count + 1
727+
self.wait_for_num_windows(expected_window_count)
728+
self.switch_to_new_window()
729+
return self
730+
695731
def switch_to_frame(self, frame: str, labels=[]) -> Page:
696732
"""Switch to inline document frame"""
697733
with self.driver.context(self.driver.CONTEXT_CHROME):

modules/page_object_autofill.py

Lines changed: 46 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -145,35 +145,19 @@ def verify_autofill_dropdown_all_fields(self, ccp: AutofillPopup):
145145
self.double_click("form-field", labels=["cc-csc"])
146146
ccp.ensure_autofill_dropdown_not_visible()
147147

148-
def verify_four_fields(
149-
self, ccp: AutofillPopup, credit_card_sample_data: CreditCardBase
148+
def verify_credit_card_form_data(
149+
self, credit_card_sample_data: CreditCardBase
150150
) -> Autofill:
151151
"""
152-
Verifies that after clicking the autofill panel the information is filled correctly.
152+
Verifies that the information is filled correctly.
153153
154154
Attributes
155155
----------
156156
157-
ccp: CreditCardPopup
158-
The credit card popup object
159-
160157
credit_card_sample_data: CreditCardBase
161158
The object that contains all the relevant information about the credit card autofill
162159
"""
163-
self.double_click("form-field", labels=["cc-name"])
164160
info_list = self.extract_credit_card_obj_into_list(credit_card_sample_data)
165-
# Click on popup form value with name only
166-
if self.sys_platform() == "Linux":
167-
with self.driver.context(self.driver.CONTEXT_CHROME):
168-
ccp.custom_wait(timeout=30, poll_frequency=0.5).until(
169-
EC.element_to_be_clickable(
170-
ccp.get_selector(
171-
"select-form-option-by-value", labels=[info_list[0]]
172-
)
173-
)
174-
)
175-
ccp.click_on("select-form-option-by-value", labels=[info_list[0]])
176-
177161
for i in range(len(info_list)):
178162
self.element_attribute_contains(
179163
"form-field", "value", info_list[i], labels=[self.fields[i]]
@@ -225,13 +209,19 @@ def update_field(
225209
self.fill_input_element(ba, field, field_data)
226210
self.click_form_button("submit")
227211

228-
def press_autofill_panel(self, credit_card_popoup_obj: AutofillPopup):
212+
def press_autofill_panel(
213+
self, autofill_popup: AutofillPopup, field: str = "cc-name"
214+
):
229215
"""
230216
Presses the autofill panel that pops up after you double-click an input field
217+
218+
Argument:
219+
field: field to click to show autofill option.
231220
"""
232-
self.double_click("form-field", labels=["cc-name"])
221+
self.double_click("form-field", labels=[field])
222+
autofill_popup.ensure_autofill_dropdown_visible()
233223
with self.driver.context(self.driver.CONTEXT_CHROME):
234-
credit_card_popoup_obj.get_element("select-form-option").click()
224+
autofill_popup.get_element("select-form-option").click()
235225

236226
def update_credit_card_information(
237227
self,
@@ -244,7 +234,6 @@ def update_credit_card_information(
244234
Updates the credit card based on field that is to be changed by first autofilling everything then updating
245235
the field of choice then pressing submit and handling the popup.
246236
"""
247-
self.press_autofill_panel(autofill_popup_obj)
248237
self.update_field(field_name, field_data, autofill_popup_obj)
249238
self.click_form_button("submit")
250239

@@ -302,67 +291,39 @@ def verify_updated_information(
302291
# updating the profile accordingly
303292
self.update_credit_card_information(autofill_popup_obj, field_name, new_data)
304293

305-
# verifying the correct data
306-
self.verify_four_fields(autofill_popup_obj, credit_card_sample_data)
307-
return self
308-
309-
def update_cc_name(
310-
self,
311-
util: Utilities,
312-
credit_card_sample_data: CreditCardBase,
313-
autofill_popup_obj: AutofillPopup,
314-
) -> Autofill:
315-
"""
316-
Generates a new name, updates the credit card information in the form.
317-
"""
318-
new_cc_name = util.fake_credit_card_data().name
319-
credit_card_sample_data.name = new_cc_name
320-
321-
self.verify_updated_information(
322-
autofill_popup_obj,
323-
credit_card_sample_data,
324-
"cc-name",
325-
credit_card_sample_data.name,
326-
)
327-
return self
328-
329-
def update_cc_exp_month(
330-
self,
331-
util: Utilities,
332-
credit_card_sample_data: CreditCardBase,
333-
autofill_popup_obj: AutofillPopup,
334-
) -> Autofill:
335-
"""
336-
Generates a new expiry month, updates the credit card information in the form.
337-
"""
338-
new_cc_exp_month = util.fake_credit_card_data().expiration_month
339-
credit_card_sample_data.expiration_month = new_cc_exp_month
294+
# autofill data
295+
self.press_autofill_panel(autofill_popup_obj)
340296

341-
self.verify_updated_information(
342-
autofill_popup_obj,
343-
credit_card_sample_data,
344-
"cc-exp-month",
345-
credit_card_sample_data.expiration_month,
346-
)
297+
# verifying the correct data
298+
self.verify_credit_card_form_data(credit_card_sample_data)
347299
return self
348300

349-
def update_cc_exp_year(
301+
def update_cc(
350302
self,
351303
util: Utilities,
352304
credit_card_sample_data: CreditCardBase,
353305
autofill_popup_obj: AutofillPopup,
306+
field: str,
354307
) -> Autofill:
355308
"""
356-
Generates a new expiry year, updates the credit card information in the form.
309+
Generates a new data for credit card according to field given, updates the credit card information in the form.
357310
"""
358-
new_cc_exp_year = util.fake_credit_card_data().expiration_year
359-
credit_card_sample_data.expiration_year = new_cc_exp_year
311+
cc_mapping = {
312+
"cc-name": "name",
313+
"cc-exp-month": "expiration_month",
314+
"cc-exp-year": "expiration_year",
315+
"cc-number": "card_number",
316+
}
317+
new_cc_data = getattr(util.fake_credit_card_data(), cc_mapping[field])
318+
while new_cc_data == getattr(credit_card_sample_data, cc_mapping[field]):
319+
new_cc_data = getattr(util.fake_credit_card_data(), cc_mapping[field])
320+
setattr(credit_card_sample_data, cc_mapping[field], new_cc_data)
360321

361322
self.verify_updated_information(
362323
autofill_popup_obj,
363324
credit_card_sample_data,
364-
"cc-exp-year",
365-
credit_card_sample_data.expiration_year,
325+
field,
326+
new_cc_data,
366327
)
367328
return self
368329

@@ -383,6 +344,21 @@ def verify_clear_form_all_fields(self, autofill_popup_obj: AutofillPopup):
383344
self.double_click("form-field", labels=["cc-csc"])
384345
autofill_popup_obj.ensure_autofill_dropdown_not_visible()
385346

347+
def autofill_and_clear_all_fields(
348+
self, autofill_popup: AutofillPopup, credit_card_data: CreditCardBase
349+
):
350+
"""
351+
For each field select autofill option and clear.
352+
"""
353+
for field in self.fields:
354+
# press autofill panel for a field.
355+
self.press_autofill_panel(autofill_popup, field)
356+
# verify cc data in form.
357+
self.verify_credit_card_form_data(credit_card_data)
358+
# Clear the fields after verification
359+
self.click_on("form-field", labels=[field])
360+
autofill_popup.click_clear_form_option()
361+
386362
def verify_field_yellow_highlights(self, expected_highlighted_fields=None):
387363
"""
388364
Reuses the common highlight-check method from the base class.

modules/util.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ def __init__(self):
100100
"Nunavut": "NU",
101101
"Yukon": "YT",
102102
}
103+
self.fake = None
104+
self.locale = None
103105

104106
def remove_file(self, path: str):
105107
try:
@@ -215,8 +217,13 @@ def create_localized_faker(self, country_code: str):
215217

216218
try:
217219
# seed to get consistent data
218-
Faker.seed(locale)
219-
faker = Faker(locale)
220+
if self.fake is None:
221+
if locale != self.locale:
222+
Faker.seed(locale)
223+
self.locale = locale
224+
self.fake = Faker(locale)
225+
faker = self.fake
226+
self.fake = faker
220227
faker.add_provider(internet)
221228
faker.add_provider(misc)
222229
return faker, True

tests/bookmarks_and_history/test_clear_all_history.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ def test_clear_all_history(driver: Firefox):
2020
"""
2121
C172045: Verify that the user can Clear all the History
2222
"""
23-
panel_ui = PanelUi(driver).open()
23+
panel_ui = PanelUi(driver)
24+
panel_ui.open()
2425
gen_page = GenericPage(driver)
2526
panel_ui.open_history_menu()
2627
ba = BrowserActions(driver)

tests/bookmarks_and_history/test_clear_recent_history_displayed.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ def test_clear_recent_history_displayed(driver: Firefox):
1313
"""
1414
C172043: Clear recent history panel displayed
1515
"""
16-
panel_ui = PanelUi(driver).open()
16+
panel_ui = PanelUi(driver)
17+
panel_ui.open()
1718

1819
panel_ui.open_panel_menu()
1920
with driver.context(driver.CONTEXT_CHROME):

tests/bookmarks_and_history/test_open_websites_from_history.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ def test_open_websites_from_history(driver: Firefox):
2929
"""
3030
C118807: Verify that the user can open websites from the Toolbar History submenu
3131
"""
32-
panel_ui = PanelUi(driver).open()
32+
panel_ui = PanelUi(driver)
33+
panel_ui.open()
3334

3435
panel_ui.open_history_menu()
3536

0 commit comments

Comments
 (0)