Skip to content

Commit ef4d17c

Browse files
Hani YacoubHani Yacoub
authored andcommitted
Merge branch 'main' into Hani/url-copy-contains-https
2 parents 5eab2a3 + 59beb97 commit ef4d17c

18 files changed

+180
-175
lines changed

modules/browser_object_tabbar.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,3 +379,43 @@ def select_multiple_tabs_by_indices(
379379
actions.key_up(Keys.CONTROL).perform()
380380

381381
return selected_tabs
382+
383+
@BasePage.context_chrome
384+
def reopen_tabs_with_shortcut(self, sys_platform: str, count: int) -> None:
385+
"""Reopen closed tabs using keyboard shortcut Ctrl/Cmd + Shift + T."""
386+
387+
# Press modifier keys
388+
if sys_platform == "Darwin":
389+
self.actions.key_down(Keys.COMMAND).key_down(Keys.SHIFT).perform()
390+
else:
391+
self.actions.key_down(Keys.CONTROL).key_down(Keys.SHIFT).perform()
392+
393+
# Press 'T' multiple times to reopen tabs
394+
for _ in range(count):
395+
self.actions.send_keys("t").perform()
396+
397+
# Release modifier keys
398+
if sys_platform == "Darwin":
399+
self.actions.key_up(Keys.SHIFT).key_up(Keys.COMMAND).perform()
400+
else:
401+
self.actions.key_up(Keys.SHIFT).key_up(Keys.CONTROL).perform()
402+
403+
@BasePage.context_chrome
404+
def reload_tab(self, nav, mod_key=None, extra_key=None):
405+
"""
406+
Reloads the current tab using a keyboard shortcut inside Chrome context.
407+
408+
Args:
409+
nav: Navigation object to click before sending keys.
410+
mod_key: Modifier key (e.g., Keys.CONTROL, Keys.COMMAND) for Ctrl/Cmd+R.
411+
extra_key: Extra key to press (e.g., 'r' for Ctrl/Cmd+R, or Keys.F5 for F5).
412+
"""
413+
nav.click_on("navigation-background-component")
414+
415+
# Determine which key combo to use
416+
if mod_key and extra_key:
417+
self.perform_key_combo(mod_key, extra_key)
418+
elif extra_key:
419+
self.perform_key_combo(extra_key)
420+
else:
421+
raise ValueError("You must provide extra_key to perform reload.")

modules/page_object_about_pages.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from selenium.webdriver.support import expected_conditions as EC
1313

1414
from modules.page_base import BasePage
15+
from modules.page_object_generics import GenericPage
1516
from modules.util import BrowserActions
1617

1718

@@ -199,6 +200,40 @@ def verify_csv_export(self, downloads_folder: str, filename: str):
199200
self.wait.until(lambda _: os.path.exists(csv_file))
200201
return csv_file
201202

203+
def add_login(self, origin: str, username: str, password: str):
204+
"""
205+
Adds a new saved login entry.
206+
207+
Args:
208+
origin (str): The site URL (e.g., https://example.com)
209+
username (str): The username to save
210+
password (str): The password to save
211+
"""
212+
self.click_add_login_button()
213+
self.create_new_login({
214+
"origin": origin,
215+
"username": username,
216+
"password": password,
217+
})
218+
219+
def export_passwords_csv(self, downloads_folder: str, filename: str):
220+
"""
221+
Export passwords to a CSV file and navigate the save dialog to the target location.
222+
223+
Args:
224+
downloads_folder (str): The folder where the CSV should be saved.
225+
filename (str): The name of the CSV file.
226+
"""
227+
# Open about:logins and click export buttons
228+
self.open()
229+
self.click_on("menu-button")
230+
self.click_on("export-passwords-button")
231+
self.click_on("continue-export-button")
232+
233+
# Wait for export dialog and navigate to folder
234+
page = GenericPage(self.driver)
235+
page.navigate_dialog_to_location(downloads_folder, filename)
236+
202237

203238
class AboutPrivatebrowsing(BasePage):
204239
"""

modules/page_object_generics.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from selenium.webdriver.common.by import By
55
from selenium.webdriver.common.keys import Keys
66
from selenium.webdriver.remote.webelement import WebElement
7+
from selenium.webdriver.support import expected_conditions as EC
78

89
from modules.page_base import BasePage
910

@@ -51,6 +52,53 @@ def navigate_dialog_to_location(
5152
sleep(1)
5253
keyboard.tap(Key.enter)
5354

55+
def wait_for_reload_and_verify_empty_field(self, old_field, field_id: str, wait_time: int = 10):
56+
"""
57+
Wait until the page reloads (staleness of old field) and verify that the
58+
new search field is visible and empty.
59+
60+
Args:
61+
old_field: WebElement before reload.
62+
field_id (str): ID of the field to locate.
63+
wait_time (int): Max wait time in seconds.
64+
65+
Returns:
66+
WebElement: The refreshed search field.
67+
"""
68+
69+
# Wait for the old element to be stale (page reload)
70+
self.wait.until(EC.staleness_of(old_field))
71+
72+
# Wait for the new one to appear and be visible
73+
new_field = self.wait.until(
74+
lambda d: (
75+
elem if (elem := d.find_element(By.ID, field_id)).is_displayed() else False
76+
)
77+
)
78+
79+
assert new_field.get_attribute("value") == "", "Search field should be empty after reload"
80+
return new_field
81+
82+
def fill_field_and_verify(self, field, text: str, clear_func, assert_nonempty: bool = True):
83+
"""
84+
Clicks the field, clears it, fills with text, and optionally asserts the value.
85+
86+
Args:
87+
field: WebElement to interact with.
88+
text: Text to enter.
89+
clear_func: Callable that clears and fills the field (e.g., ba.clear_and_fill).
90+
assert_nonempty: If True, asserts that field value matches `text`.
91+
92+
Returns:
93+
WebElement: The same field after filling.
94+
"""
95+
field.click()
96+
clear_func(field, text, press_enter=False)
97+
if assert_nonempty:
98+
actual = field.get_attribute("value")
99+
assert actual == text, f"Expected field value '{text}', but got '{actual}'"
100+
return field
101+
54102

55103
class GenericPdf(BasePage):
56104
"""

tests/password_manager/test_add_password_non_ascii_chars.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,9 @@ def test_add_password_non_ascii_chars(driver: Firefox):
2323
# Open about:logins and click on the "Add password" button
2424
about_logins.open()
2525
original_logins_amount = len(about_logins.get_elements("login-list-item"))
26-
about_logins.click_add_login_button()
2726

2827
# Complete all the fields with valid data and click the "Save" button.
29-
about_logins.create_new_login(
30-
{
31-
"origin": WEBSITE_ADDRESS,
32-
"username": USERNAME,
33-
"password": PASSWORD,
34-
}
35-
)
28+
about_logins.add_login(WEBSITE_ADDRESS, USERNAME, PASSWORD)
3629

3730
# Check password added in the listbox
3831
about_logins.wait.until(

tests/password_manager/test_add_password_save_valid_data.py

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,15 @@ def test_add_password_save_valid_data(driver: Firefox):
2121
"""
2222
C2241112 Verify that a password can be added and saved
2323
"""
24-
# instantiate object
24+
25+
# Instantiate object
2526
about_logins = AboutLogins(driver)
2627

2728
# Open about:logins and click on the "Add password" button
2829
about_logins.open()
29-
about_logins.click_add_login_button()
3030

3131
# Complete all the fields with valid data and click the "Save" button.
32-
about_logins.create_new_login(
33-
{
34-
"origin": WEBSITE_ADDRESS,
35-
"username": USERNAME,
36-
"password": PASSWORD,
37-
}
38-
)
32+
about_logins.add_login(WEBSITE_ADDRESS, USERNAME, PASSWORD)
3933

4034
# Check password added in the listbox
4135
logins = about_logins.get_elements("login-list-item")

tests/password_manager/test_auto_saved_generated_password_context_menu.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from time import sleep
2-
31
import pytest
42
from selenium.webdriver import Firefox
53

@@ -52,8 +50,9 @@ def test_auto_saved_generated_password_context_menu(driver: Firefox):
5250
)
5351

5452
# Verify the update doorhanger is displayed
55-
# with driver.context(driver.CONTEXT_CHROME):
56-
sleep(3)
53+
nav.expect(
54+
lambda _: nav.element_visible("password-notification-key")
55+
)
5756
nav.click_on("password-notification-key")
5857
autofill_popup_panel.expect(
5958
lambda _: UPDATE_DOORHANGER_TEXT

tests/password_manager/test_autocomplete_dropdown_is_toggled_for_focused_login_fields_on_page_load.py

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ def add_to_prefs_list():
2424
return [("signon.rememberSignons", True)]
2525

2626

27+
@pytest.mark.unstable(reason="Bug 1996241")
2728
def test_autocomplete_dropdown_is_toggled_for_focused_login_fields_on_page_load(
2829
driver: Firefox,
2930
):
@@ -43,22 +44,8 @@ def test_autocomplete_dropdown_is_toggled_for_focused_login_fields_on_page_load(
4344

4445
# Save 2 set of credentials for the visited site
4546
about_logins.open()
46-
about_logins.click_add_login_button()
47-
about_logins.create_new_login(
48-
{
49-
"origin": BSKY_URL,
50-
"username": USERNAME,
51-
"password": PASSWORD,
52-
}
53-
)
54-
about_logins.click_add_login_button()
55-
about_logins.create_new_login(
56-
{
57-
"origin": BSKY_URL,
58-
"username": USERNAME2,
59-
"password": PASSWORD2,
60-
}
61-
)
47+
about_logins.add_login(BSKY_URL, USERNAME, PASSWORD)
48+
about_logins.add_login(BSKY_URL, USERNAME2, PASSWORD2)
6249

6350
# Autocomplete dropdown is toggled for focused login fields on page load
6451
tabs.click_tab_by_index(1)

tests/password_manager/test_can_view_password_when_PP_enabled.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,9 @@ def test_password_can_be_shown(driver: Firefox):
2828

2929
# Open about:login and click on the "Add password" button
3030
about_logins.open()
31-
about_logins.click_add_login_button()
3231

3332
# Complete all the fields with valid data and click the "Save" button.
34-
about_logins.create_new_login(
35-
{
36-
"origin": URL_TO_TEST,
37-
"username": USERNAME,
38-
"password": PASSWORD,
39-
}
40-
)
33+
about_logins.add_login(URL_TO_TEST, USERNAME, PASSWORD)
4134

4235
# Select the "Use a primary password" check box to trigger the "Change Primary Password" window
4336
about_prefs.open()
@@ -56,7 +49,6 @@ def test_password_can_be_shown(driver: Firefox):
5649
about_prefs.click_on("submit-password")
5750

5851
# Check that the pop-up appears
59-
# with driver.context(driver.CONTEXT_CHROME):
6052
alert = about_prefs.get_alert()
6153
alert.accept()
6254

tests/password_manager/test_changes_made_in_edit_mode_are_saved.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,8 @@ def test_changes_made_in_edit_mode_are_saved(driver: Firefox):
2525

2626
# Open about:logins and add a new login
2727
about_logins.open()
28-
about_logins.click_add_login_button()
29-
about_logins.create_new_login(
30-
{
31-
"origin": URL_TO_TEST,
32-
"username": USERNAME,
33-
"password": PASSWORD,
34-
}
35-
)
28+
about_logins.add_login(URL_TO_TEST, USERNAME, PASSWORD)
29+
3630
# Click the "Edit" button
3731
about_logins.element_visible("edit-login")
3832
about_logins.click_on("edit-login")

tests/password_manager/test_multiple_saved_logins.py

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -47,32 +47,11 @@ def test_multiple_saved_logins(driver: Firefox, temp_selectors):
4747

4848
# Save 3 sets of credentials for facebook
4949
about_logins.open()
50-
about_logins.click_add_login_button()
51-
about_logins.create_new_login(
52-
{
53-
"origin": SAUCEDEMO_URL,
54-
"username": USERNAME,
55-
"password": PASSWORD,
56-
}
57-
)
50+
about_logins.add_login(SAUCEDEMO_URL, USERNAME, PASSWORD)
5851
time.sleep(0.8)
59-
about_logins.click_add_login_button()
60-
about_logins.create_new_login(
61-
{
62-
"origin": SAUCEDEMO_URL,
63-
"username": USERNAME2,
64-
"password": PASSWORD2,
65-
}
66-
)
52+
about_logins.add_login(SAUCEDEMO_URL, USERNAME2, PASSWORD2)
6753
time.sleep(0.8)
68-
about_logins.click_add_login_button()
69-
about_logins.create_new_login(
70-
{
71-
"origin": SAUCEDEMO_URL,
72-
"username": USERNAME3,
73-
"password": PASSWORD3,
74-
}
75-
)
54+
about_logins.add_login(SAUCEDEMO_URL, USERNAME3, PASSWORD3)
7655

7756
# Open saucedemo.com
7857
web_page = GenericPage(driver, url=SAUCEDEMO_URL).open()

0 commit comments

Comments
 (0)