Skip to content

Commit 60d8ae8

Browse files
Hani YacoubHani Yacoub
authored andcommitted
Merge main
2 parents 59c0a0e + 575e758 commit 60d8ae8

29 files changed

+697
-422
lines changed

SELECTOR_INFO.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,6 +1151,13 @@ Description: The dropdown menu for default zoom selection
11511151
Location: about:preferences - Zoom settings
11521152
Path to .json: modules/data/about_prefs.components.json
11531153
```
1154+
```
1155+
Selector Name: unknown-content-type-dialog
1156+
Selector Data: unknownContentTypeWindo
1157+
Description: The unknown content type dialog
1158+
Location: about:preferences#general Applications subsection
1159+
Path to .json: modules/data/about_prefs.components.json
1160+
```
11541161
#### about_profiles
11551162
```
11561163
Selector Name: profile-container
@@ -1788,6 +1795,13 @@ Description: Open all bookmarks from the context menu option from a Toolbar book
17881795
Location: Context menu - Toolbar
17891796
Path to .json: modules/data/context_menu.components.json
17901797
```
1798+
```
1799+
Selector Name: context-menu-move-tab-to-start
1800+
Selector Data: menuitem[data-l10n-id='move-to-start']
1801+
Description: Context menu option to move a tab to the start of the tab bar.
1802+
Location: Context menu - Tab
1803+
Path to .json: modules/data/context_menu.components.json
1804+
```
17911805
#### credit_card_fill
17921806
```
17931807
Selector Name: form-field
@@ -2797,6 +2811,27 @@ Location: Download panel
27972811
Path to .json: modules/data/navigation.components.json
27982812
```
27992813
```
2814+
Selector name: download-target-element
2815+
Selector Data: downloadTarget
2816+
Description: Downloaded item in the download panel
2817+
Location: Download panel
2818+
Path to .json: modules/data/navigation.components.json
2819+
```
2820+
```
2821+
Selector name: download-progress-element
2822+
Selector Data: downloadProgress
2823+
Description: Download progress bar
2824+
Location: Download panel
2825+
Path to .json: modules/data/navigation.components.json
2826+
```
2827+
```
2828+
Selector name: ddownload-details-element
2829+
Selector Data: downloadDetailsNormal
2830+
Description: Download details element
2831+
Location: Download panel
2832+
Path to .json: modules/data/navigation.components.json
2833+
```
2834+
```
28002835
Selector name: remove-bookmark-button
28012836
Selector Data: editBookmarkPanelRemoveButton
28022837
Description: Remove bookmark button

modules/browser_object_navigation.py

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import logging
2+
import re
23
from typing import Literal
34

4-
from selenium.common.exceptions import TimeoutException
5+
from selenium.common.exceptions import StaleElementReferenceException, TimeoutException
56
from selenium.webdriver import ActionChains, Firefox
67
from selenium.webdriver.common.by import By
78
from selenium.webdriver.common.keys import Keys
@@ -246,13 +247,25 @@ def click_download_button(self) -> BasePage:
246247
return self
247248

248249
@BasePage.context_chrome
249-
def wait_for_download_animation_finish(
250-
self, downloads_button: WebElement
251-
) -> BasePage:
250+
def set_always_open_similar_files(self) -> BasePage:
252251
"""
253-
Waits for the download button to finish playing the animation for downloading to local computer
252+
From the downloads panel, right-click the most recent download and set 'Always Open Similar Files'.
254253
"""
254+
downloads_button = self.get_download_button()
255+
downloads_button.click()
256+
257+
# Locate the latest downloaded file in the panel, open context menu and choose 'Always Open Similar Files'
258+
download_item = self.get_element("download-panel-item")
259+
self.context_click(download_item)
260+
self.context_menu.get_element("context-menu-always-open-similar-files").click()
261+
262+
return self
263+
264+
@BasePage.context_chrome
265+
def wait_for_download_animation_finish(self) -> BasePage:
266+
"""Waits for the download button to finish playing the animation"""
255267
try:
268+
downloads_button = self.get_download_button()
256269
self.wait.until(
257270
lambda _: downloads_button.get_attribute("notification") == "finish"
258271
)
@@ -298,6 +311,34 @@ def wait_for_item_to_download(self, filename: str) -> BasePage:
298311
self.driver.implicitly_wait(original_timeout)
299312
return self
300313

314+
@BasePage.context_chrome
315+
def verify_download_name(self, expected_pattern: str) -> BasePage:
316+
"""
317+
Verify download name matches expected pattern.
318+
Argument:
319+
expected_pattern: Regex pattern to match against download name
320+
"""
321+
download_name = self.get_element("download-target-element")
322+
download_value = download_name.get_attribute("value")
323+
assert re.match(expected_pattern, download_value), (
324+
f"The download name is incorrect: {download_value}"
325+
)
326+
return self
327+
328+
@BasePage.context_chrome
329+
def wait_for_download_completion(self) -> BasePage:
330+
"""Wait until the most recent download reaches 100% progress."""
331+
332+
def _download_complete(_):
333+
try:
334+
element = self.get_element("download-progress-element")
335+
return element.get_attribute("value") == "100"
336+
except StaleElementReferenceException:
337+
return False
338+
339+
self.wait.until(_download_complete)
340+
return self
341+
301342
@BasePage.context_chrome
302343
def refresh_page(self) -> BasePage:
303344
"""

modules/browser_object_tabbar.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,3 +316,13 @@ def open_multiple_tabs_with_pages(self, pages: list) -> "TabBar":
316316
else:
317317
page.open()
318318
return self
319+
320+
@BasePage.context_chrome
321+
def verify_tab_focus_cycle(self, num_tabs: int):
322+
"""Go through all the tabs and ensure the focus changes correctly."""
323+
for i in range(1, num_tabs + 2):
324+
target_tab = self.get_tab(i)
325+
self.click_on(target_tab)
326+
self.custom_wait(timeout=3).until(
327+
lambda d: target_tab.get_attribute("visuallyselected") == ""
328+
)

modules/data/about_prefs.components.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,5 +541,13 @@
541541
"selectorData": "menuitem[data-l10n-id='preferences-default-zoom-value'][value='{.*}']",
542542
"strategy": "css",
543543
"groups": []
544-
}
544+
},
545+
546+
"unknown-content-type-dialog": {
547+
"selectorData": "unknownContentTypeWindow",
548+
"strategy": "id",
549+
"groups": [
550+
"doNotCache"
551+
]
552+
}
545553
}

modules/data/context_menu.components.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@
109109
"groups": []
110110
},
111111

112+
"context-menu-move-tab-to-start": {
113+
"selectorData": "menuitem[data-l10n-id='move-to-start']",
114+
"strategy": "css",
115+
"groups": []
116+
},
117+
112118
"context-menu-open-link-in-tab": {
113119
"selectorData": "context-openlinkintab",
114120
"strategy": "id",

modules/data/navigation.components.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,24 @@
405405
"groups": []
406406
},
407407

408+
"download-target-element": {
409+
"selectorData": "downloadTarget",
410+
"strategy": "class",
411+
"groups": []
412+
},
413+
414+
"download-progress-element": {
415+
"selectorData": "downloadProgress",
416+
"strategy": "class",
417+
"groups": []
418+
},
419+
420+
"download-details-element": {
421+
"selectorData": "downloadDetailsNormal",
422+
"strategy": "class",
423+
"groups": []
424+
},
425+
408426
"bookmark-in-bar": {
409427
"selectorData": "toolbarbutton.bookmark-item",
410428
"strategy": "css",

modules/page_object_prefs.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import datetime
2+
import json
23
import re
34
from time import sleep
45
from typing import List, Literal
@@ -638,6 +639,50 @@ def click_popup_panel_button(self, field: str) -> BasePage:
638639
self.get_element("panel-popup-button", labels=[field]).click()
639640
return self
640641

642+
@BasePage.context_content
643+
def get_app_name_for_mime_type(self, mime_type: str) -> str:
644+
"""
645+
Return the application name associated with a given MIME type in about:preferences.
646+
Argument:
647+
mime_type: the MIME type to look up (e.g., "application/msword").
648+
"""
649+
# Locate the row for the given MIME type
650+
mime_type_item = self.get_element("mime-type-item", labels=[mime_type])
651+
652+
# Find the description element that contains application info
653+
action_description = self.get_element(
654+
"mime-type-item-description", parent_element=mime_type_item
655+
)
656+
657+
# Parse the JSON data-l10n-args attribute and extract app name
658+
mime_type_data = json.loads(action_description.get_attribute("data-l10n-args"))
659+
return mime_type_data["app-name"]
660+
661+
def set_pdf_handling_to_always_ask(self) -> BasePage:
662+
"""
663+
Set PDF content type handling to "Always ask" in Applications settings.
664+
"""
665+
self.click_on("pdf-content-type")
666+
self.click_on("pdf-actions-menu")
667+
menu = self.get_element("pdf-actions-menu")
668+
menu.send_keys(Keys.DOWN)
669+
menu.send_keys(Keys.ENTER)
670+
return self
671+
672+
@BasePage.context_chrome
673+
def handle_unknown_content_dialog(self) -> BasePage:
674+
"""
675+
Wait for the unknown content type dialog to appear and close it with Escape.
676+
"""
677+
self.wait.until(lambda _: len(self.driver.window_handles) > 1)
678+
self.driver.switch_to.window(self.driver.window_handles[-1])
679+
self.wait.until(lambda _: self.get_element("unknown-content-type-dialog"))
680+
681+
# Close the dialog with Escape
682+
dialog = self.get_element("unknown-content-type-dialog")
683+
dialog.send_keys(Keys.ESCAPE)
684+
return self
685+
641686

642687
class AboutAddons(BasePage):
643688
"""
Lines changed: 23 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import json
21
import sys
32
from os import environ
43

54
import pytest
65
from selenium.webdriver import Firefox
76

8-
from modules.browser_object import ContextMenu, Navigation
7+
from modules.browser_object import Navigation
98
from modules.page_object import AboutPrefs, GenericPage
109

1110

@@ -15,7 +14,6 @@ def test_case():
1514

1615

1716
DOC_LINK = "https://sapphire-hendrika-5.tiiny.site/"
18-
1917
WIN_GHA = environ.get("GITHUB_ACTIONS") == "true" and sys.platform.startswith("win")
2018

2119

@@ -24,41 +22,35 @@ def delete_files_regex_string():
2422
return r"sample.*\.doc"
2523

2624

27-
@pytest.mark.skipif(WIN_GHA, reason="Test unstable in Windows Github Actions")
25+
def expected_app_name(sys_platform: str, opt_ci: bool) -> str:
26+
if sys_platform == "Darwin":
27+
return "TextEdit" if opt_ci else "Pages"
28+
return "LibreOffice Writer"
29+
30+
31+
@pytest.mark.skipif(
32+
WIN_GHA, reason="Most runners don’t have a .doc handler registered on Windows"
33+
)
2834
@pytest.mark.noxvfb
2935
def test_mime_type_doc(driver: Firefox, sys_platform: str, opt_ci: bool, delete_files):
3036
"""
31-
C1756748: Verify the user can add the .doc type
37+
C1756748 - Verify that downloading a .doc file adds a new MIME type entry
38+
and the correct default application is assigned.
3239
"""
33-
doc_page = GenericPage(driver, url=DOC_LINK).open()
40+
41+
# Instantiate objects
42+
page = GenericPage(driver, url=DOC_LINK)
3443
nav = Navigation(driver)
35-
context_menu = ContextMenu(driver)
3644
about_prefs = AboutPrefs(driver, category="general")
37-
doc_page.get_element("sample-doc-download").click()
3845

39-
downloads_button = nav.get_download_button()
46+
# Open the test page with the .doc download link
47+
page.open()
48+
page.click_on("sample-doc-download")
4049

41-
with driver.context(driver.CONTEXT_CHROME):
42-
downloads_button.click()
43-
download_item = nav.get_element("download-panel-item")
44-
nav.context_click(download_item)
45-
context_menu.get_element("context-menu-always-open-similar-files").click()
50+
# Download the file and set 'Always Open Similar Files'
51+
nav.set_always_open_similar_files()
4652

53+
# Verify the MIME type entry exists and default app matches expectation
4754
about_prefs.open()
48-
about_prefs.element_exists("mime-type-item", labels=["application/msword"])
49-
50-
mime_type_item = about_prefs.get_element(
51-
"mime-type-item", labels=["application/msword"]
52-
)
53-
action_description_item = about_prefs.get_element(
54-
"mime-type-item-description", parent_element=mime_type_item
55-
)
56-
57-
mime_type_data = json.loads(action_description_item.get_attribute("data-l10n-args"))
58-
if sys_platform == "Darwin":
59-
if opt_ci:
60-
assert mime_type_data["app-name"] == "TextEdit"
61-
else:
62-
assert mime_type_data["app-name"] == "Pages"
63-
else:
64-
assert mime_type_data["app-name"] == "LibreOffice Writer"
55+
app_name = about_prefs.get_app_name_for_mime_type("application/msword")
56+
assert app_name == expected_app_name(sys_platform, opt_ci)

tests/downloads/test_add_zip_type.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import pytest
55
from selenium.webdriver import Firefox
66

7-
from modules.browser_object_context_menu import ContextMenu
87
from modules.browser_object_navigation import Navigation
98
from modules.page_object_generics import GenericPage
109
from modules.page_object_prefs import AboutPrefs
@@ -27,7 +26,8 @@ def delete_files_regex_string():
2726
def temp_selectors():
2827
return {
2928
"github-code-button": {
30-
"selectorData": "/html/body/div[1]/div[4]/div/main/turbo-frame/div/div/div/div/div[1]/react-partial/div/div/div[2]/div[2]/button",
29+
"selectorData": "/html/body/div[1]/div[4]/div/main/turbo-frame/div/div/div/div/div["
30+
"1]/react-partial/div/div/div[2]/div[2]/button",
3131
"strategy": "xpath",
3232
"groups": [],
3333
},
@@ -50,28 +50,26 @@ def test_add_zip_type(
5050
"""
5151
C1756743: Verify that the user can add the .zip mime type to Firefox
5252
"""
53-
# instantiate object
54-
web_page = GenericPage(driver, url=ZIP_URL).open()
53+
# Instantiate objects
54+
web_page = GenericPage(driver, url=ZIP_URL)
5555
nav = Navigation(driver)
56-
context_menu = ContextMenu(driver)
5756
about_prefs = AboutPrefs(driver, category="general")
5857

5958
web_page.elements |= temp_selectors
6059

6160
# Click on the available zip
61+
web_page.open()
6262
web_page.click_on("github-code-button")
6363
web_page.click_on("github-download-button")
6464

6565
# In the download panel right-click on the download and click "Always Open Similar Files"
66-
with driver.context(driver.CONTEXT_CHROME):
67-
nav.context_click(nav.get_element("download-panel-item"))
68-
context_menu.get_element("context-menu-always-open-similar-files").click()
66+
nav.set_always_open_similar_files()
6967

7068
# Open about:preferences and check that zip mime type is present in the application list
7169
about_prefs.open()
72-
about_prefs.element_exists("mime-type-item", labels=["application/zip"])
70+
about_prefs.get_app_name_for_mime_type("application/zip")
7371

74-
# Remove the directory created as MacOS automatically unzips
72+
# Remove the directory created as macOS automatically unzips
7573
if sys_platform == "Darwin":
7674
dir_created = os.path.join(home_folder, "Downloads", "api-guidelines-vNext")
7775
shutil.rmtree(dir_created)

0 commit comments

Comments
 (0)