Skip to content

Commit 9b31bd7

Browse files
committed
Add 3 refactored download tests
1 parent 700444c commit 9b31bd7

13 files changed

+179
-91
lines changed

SELECTOR_INFO.md

Lines changed: 28 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
@@ -2804,6 +2811,27 @@ Location: Download panel
28042811
Path to .json: modules/data/navigation.components.json
28052812
```
28062813
```
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+
```
28072835
Selector name: remove-bookmark-button
28082836
Selector Data: editBookmarkPanelRemoveButton
28092837
Description: Remove bookmark button

modules/browser_object_navigation.py

Lines changed: 49 additions & 20 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
@@ -245,6 +246,21 @@ def click_download_button(self) -> BasePage:
245246
self.get_download_button().click()
246247
return self
247248

249+
@BasePage.context_chrome
250+
def set_always_open_similar_files(self) -> BasePage:
251+
"""
252+
From the downloads panel, right-click the most recent download and set 'Always Open Similar Files'.
253+
"""
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+
248264
@BasePage.context_chrome
249265
def wait_for_download_animation_finish(
250266
self, downloads_button: WebElement
@@ -275,27 +291,40 @@ def click_file_download_warning_panel(self) -> BasePage:
275291
self.click_on("file-download-warning-button")
276292
return self
277293

278-
def wait_for_item_to_download(self, filename: str) -> BasePage:
294+
def wait_for_item_to_download(self) -> BasePage:
279295
"""
280-
Check the downloads tool in the toolbar to wait for a given file to download
296+
Wait for download elements to be present.
297+
281298
"""
282-
original_timeout = self.driver.timeouts.implicit_wait
283-
try:
284-
# Whatever our timeout, we want to lengthen it because downloads
285-
self.driver.implicitly_wait(original_timeout * 2)
286-
self.element_visible("downloads-item-by-file", labels=[filename])
287-
self.expect_not(
288-
EC.element_attribute_to_include(
289-
self.get_selector("downloads-button"), "animate"
290-
)
291-
)
292-
with self.driver.context(self.context_id):
293-
self.driver.execute_script(
294-
"arguments[0].setAttribute('hidden', true)",
295-
self.get_element("downloads-button"),
296-
)
297-
finally:
298-
self.driver.implicitly_wait(original_timeout)
299+
self.element_visible("download-target-element")
300+
return self
301+
302+
@BasePage.context_chrome
303+
def verify_download_name(self, expected_pattern: str) -> BasePage:
304+
"""
305+
Verify download name matches expected pattern.
306+
Argument:
307+
expected_pattern: Regex pattern to match against download name
308+
"""
309+
download_name = self.get_element("download-target-element")
310+
download_value = download_name.get_attribute("value")
311+
assert re.match(expected_pattern, download_value), (
312+
f"The download name is incorrect: {download_value}"
313+
)
314+
return self
315+
316+
@BasePage.context_chrome
317+
def wait_for_download_completion(self) -> BasePage:
318+
"""Wait until the most recent download reaches 100% progress."""
319+
320+
def _download_complete(_):
321+
try:
322+
element = self.get_element("download-progress-element")
323+
return element.get_attribute("value") == "100"
324+
except StaleElementReferenceException:
325+
return False
326+
327+
self.wait.until(_download_complete)
299328
return self
300329

301330
@BasePage.context_chrome

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/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: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from time import sleep
44
from typing import List, Literal
55

6+
from rich import json
67
from selenium.webdriver import Firefox
78
from selenium.webdriver.common.by import By
89
from selenium.webdriver.common.keys import Keys
@@ -638,6 +639,49 @@ def click_popup_panel_button(self, field: str) -> BasePage:
638639
self.get_element("panel-popup-button", labels=[field]).click()
639640
return self
640641

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

642686
class AboutAddons(BasePage):
643687
"""

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)
Lines changed: 9 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
1-
import re
2-
from time import sleep
3-
41
import pytest
5-
from selenium.common.exceptions import StaleElementReferenceException
62
from selenium.webdriver import Firefox
7-
from selenium.webdriver.common.by import By
8-
from selenium.webdriver.support import expected_conditions as EC
9-
from selenium.webdriver.support.wait import WebDriverWait
103

4+
from modules.browser_object import Navigation
115
from modules.page_object import GenericPage
126

137

@@ -31,42 +25,16 @@ def test_mixed_content_download_via_https(driver: Firefox, delete_files):
3125
"""
3226
C1756722: Verify that the user can download mixed content via HTTPS
3327
"""
34-
28+
# Initialize objects
3529
web_page = GenericPage(driver, url=MIXED_CONTENT_DOWNLOAD_URL)
30+
nav = Navigation(driver)
3631

37-
# Wait up to 30 seconds for test website to wake up and download the content
32+
# Wait for the test website to wake up and download the content
3833
web_page.open()
39-
with driver.context(driver.CONTEXT_CHROME):
40-
WebDriverWait(driver, 30).until(EC.title_contains("File Examples"))
41-
42-
with driver.context(driver.CONTEXT_CHROME):
43-
download_name = WebDriverWait(driver, 10).until(
44-
EC.presence_of_element_located((By.CLASS_NAME, "downloadTarget"))
45-
)
46-
47-
download_status = WebDriverWait(driver, 10).until(
48-
EC.presence_of_element_located((By.CLASS_NAME, "downloadProgress"))
49-
)
50-
51-
# Verify that the desired download target element is present directly, no extra steps needed.
52-
download_value = download_name.get_attribute("value")
53-
assert re.match(r"file-sample_100kB(\(\d+\)).odt$", download_value), (
54-
f"The download name is incorrect: {download_value}"
55-
)
34+
web_page.wait.until(lambda _: web_page.title_contains("File Examples"))
5635

57-
# Verify that the download progress has reached 100%, which indicates that the download is complete.
58-
i = 1
59-
while True:
60-
try:
61-
download_value = download_status.get_attribute("value")
62-
if download_value == "100":
63-
break
64-
except StaleElementReferenceException:
65-
pass
36+
# Verify download name matches expected pattern
37+
nav.verify_download_name(r"file-sample_100kB(\(\d+\))?.odt$")
6638

67-
if i > MAX_CHECKS:
68-
raise TimeoutError(
69-
"Download progress did not reach 100% within reasonable time."
70-
)
71-
sleep(1)
72-
i = +1
39+
# Wait for download completion
40+
nav.wait_for_download_completion()

tests/downloads/test_set_always_ask_file_type.py

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
1-
from time import sleep
2-
31
import pytest
42
from selenium.webdriver import Firefox
5-
from selenium.webdriver.common.by import By
6-
from selenium.webdriver.common.keys import Keys
73

84
from modules.browser_object import Navigation
95
from modules.page_object import AboutPrefs
@@ -27,21 +23,21 @@ def delete_files_regex_string():
2723
@pytest.mark.ci
2824
def test_set_always_ask_file_type(driver: Firefox, delete_files):
2925
"""
30-
C1756752: Ensure that the Always ask option in Firefox Applications settings
26+
C1756752 - Ensure that the Always ask option in Firefox Applications settings
3127
leads to a dialog asking "What should Firefox do with this file?" when the file type
3228
is downloaded.
3329
"""
30+
31+
# Initialize page objects
3432
nav = Navigation(driver)
35-
about_prefs = AboutPrefs(driver, category="general").open()
33+
about_prefs = AboutPrefs(driver, category="general")
3634

37-
about_prefs.click_on("pdf-content-type")
38-
about_prefs.click_on("pdf-actions-menu")
39-
menu = about_prefs.get_element("pdf-actions-menu")
40-
menu.send_keys(Keys.DOWN)
41-
menu.send_keys(Keys.ENTER)
35+
# Set PDF handling to "Always ask"
36+
about_prefs.open()
37+
about_prefs.set_pdf_handling_to_always_ask()
4238

39+
# Navigate to download URL and verify dialog appears
4340
nav.search(CONTENT_DISPOSITION_ATTACHMENT_URL)
44-
sleep(2)
45-
with driver.context(driver.CONTEXT_CHROME):
46-
driver.switch_to.window(driver.window_handles[-1])
47-
driver.find_element(By.ID, "unknownContentTypeWindow").send_keys(Keys.ESCAPE)
41+
42+
# Wait for and handle the unknown content type dialog
43+
about_prefs.handle_unknown_content_dialog()

0 commit comments

Comments
 (0)