From 58d6e35c7789579d2e4ac1e550587096a8911a4f Mon Sep 17 00:00:00 2001 From: soncuteanca Date: Tue, 30 Sep 2025 15:51:25 +0300 Subject: [PATCH 01/14] Add refactored test 1756748 --- modules/browser_object_navigation.py | 14 ++++++ modules/page_object_prefs.py | 19 ++++++++ tests/downloads/test_add_mime_type_doc.py | 54 ++++++++++------------- 3 files changed, 57 insertions(+), 30 deletions(-) diff --git a/modules/browser_object_navigation.py b/modules/browser_object_navigation.py index ad0c64467..36449c324 100644 --- a/modules/browser_object_navigation.py +++ b/modules/browser_object_navigation.py @@ -243,6 +243,20 @@ def get_download_button(self) -> WebElement: def click_download_button(self) -> BasePage: self.get_download_button().click() return self + @BasePage.context_chrome + def set_always_open_similar_files(self) -> BasePage: + """ + From the downloads panel, right-click the most recent download and set 'Always Open Similar Files'. + """ + downloads_button = self.get_download_button() + downloads_button.click() + + # Locate the latest downloaded file in the panel, open context menu and choose 'Always Open Similar Files' + download_item = self.get_element("download-panel-item") + self.context_click(download_item) + self.context_menu.get_element("context-menu-always-open-similar-files").click() + + return self @BasePage.context_chrome def wait_for_download_animation_finish( diff --git a/modules/page_object_prefs.py b/modules/page_object_prefs.py index 465d76b04..3e324716a 100644 --- a/modules/page_object_prefs.py +++ b/modules/page_object_prefs.py @@ -1,4 +1,5 @@ import datetime +import json import re from time import sleep from typing import List @@ -612,6 +613,24 @@ def click_popup_panel_button(self, field: str) -> BasePage: self.get_element("panel-popup-button", labels=[field]).click() return self + def get_app_name_for_mime_type(self, mime_type: str) -> str: + """ + Return the application name associated with a given MIME type in about:preferences. + Argument: + mime_type: the MIME type to look up (e.g., "application/msword"). + """ + # Locate the row for the given MIME type + mime_type_item = self.get_element("mime-type-item", labels=[mime_type]) + + # Find the description element that contains application info + action_description = self.get_element( + "mime-type-item-description", parent_element=mime_type_item + ) + + # Parse the JSON data-l10n-args attribute and extract app name + mime_type_data = json.loads(action_description.get_attribute("data-l10n-args")) + return mime_type_data["app-name"] + class AboutAddons(BasePage): """ diff --git a/tests/downloads/test_add_mime_type_doc.py b/tests/downloads/test_add_mime_type_doc.py index 4b30e5a49..99094dfb2 100644 --- a/tests/downloads/test_add_mime_type_doc.py +++ b/tests/downloads/test_add_mime_type_doc.py @@ -1,11 +1,10 @@ -import json import sys from os import environ import pytest from selenium.webdriver import Firefox -from modules.browser_object import ContextMenu, Navigation +from modules.browser_object import Navigation from modules.page_object import AboutPrefs, GenericPage @@ -14,8 +13,8 @@ def test_case(): return "1756748" +# Constants DOC_LINK = "https://sapphire-hendrika-5.tiiny.site/" - WIN_GHA = environ.get("GITHUB_ACTIONS") == "true" and sys.platform.startswith("win") @@ -24,41 +23,36 @@ def delete_files_regex_string(): return r"sample.*\.doc" +def expected_app_name(sys_platform: str, opt_ci: bool) -> str: + """ + Decide which default application should be used to open .doc files, based on OS and CI environment + """ + if sys_platform == "Darwin": + return "TextEdit" if opt_ci else "Pages" + # Linux/Windows use LibreOffice + return "LibreOffice Writer" + + @pytest.mark.skipif(WIN_GHA, reason="Test unstable in Windows Github Actions") @pytest.mark.noxvfb def test_mime_type_doc(driver: Firefox, sys_platform: str, opt_ci: bool, delete_files): """ - C1756748: Verify the user can add the .doc type + C1756748 - Verify that downloading a .doc file adds a new MIME type entry + and the correct default application is assigned. """ - doc_page = GenericPage(driver, url=DOC_LINK).open() + # Instantiate objects + page = GenericPage(driver, url=DOC_LINK) nav = Navigation(driver) - context_menu = ContextMenu(driver) about_prefs = AboutPrefs(driver, category="general") - doc_page.get_element("sample-doc-download").click() - downloads_button = nav.get_download_button() + # Open the test page with the .doc download link + page.open() + page.click_on("sample-doc-download") - with driver.context(driver.CONTEXT_CHROME): - downloads_button.click() - download_item = nav.get_element("download-panel-item") - nav.context_click(download_item) - context_menu.get_element("context-menu-always-open-similar-files").click() + # Download the file and set 'Always Open Similar Files' + nav.set_always_open_similar_files() + # Verify the MIME type entry exists and default app matches expectation about_prefs.open() - about_prefs.element_exists("mime-type-item", labels=["application/msword"]) - - mime_type_item = about_prefs.get_element( - "mime-type-item", labels=["application/msword"] - ) - action_description_item = about_prefs.get_element( - "mime-type-item-description", parent_element=mime_type_item - ) - - mime_type_data = json.loads(action_description_item.get_attribute("data-l10n-args")) - if sys_platform == "Darwin": - if opt_ci: - assert mime_type_data["app-name"] == "TextEdit" - else: - assert mime_type_data["app-name"] == "Pages" - else: - assert mime_type_data["app-name"] == "LibreOffice Writer" + app_name = about_prefs.get_app_name_for_mime_type("application/msword") + assert app_name == expected_app_name(sys_platform, opt_ci) From eed6f3d870557cd3f30e21adbf2276baa34d4ae9 Mon Sep 17 00:00:00 2001 From: soncuteanca Date: Wed, 1 Oct 2025 18:42:22 +0300 Subject: [PATCH 02/14] Add test 1756743 --- tests/downloads/test_add_zip_type.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/tests/downloads/test_add_zip_type.py b/tests/downloads/test_add_zip_type.py index 850de5d29..e68c84f3d 100644 --- a/tests/downloads/test_add_zip_type.py +++ b/tests/downloads/test_add_zip_type.py @@ -4,7 +4,6 @@ import pytest from selenium.webdriver import Firefox -from modules.browser_object_context_menu import ContextMenu from modules.browser_object_navigation import Navigation from modules.page_object_generics import GenericPage from modules.page_object_prefs import AboutPrefs @@ -50,26 +49,24 @@ def test_add_zip_type( """ C1756743: Verify that the user can add the .zip mime type to Firefox """ - # instantiate object - web_page = GenericPage(driver, url=ZIP_URL).open() + # Instantiate objects + web_page = GenericPage(driver, url=ZIP_URL) nav = Navigation(driver) - context_menu = ContextMenu(driver) about_prefs = AboutPrefs(driver, category="general") web_page.elements |= temp_selectors # Click on the available zip + web_page.open() web_page.click_on("github-code-button") web_page.click_on("github-download-button") # In the download panel right-click on the download and click "Always Open Similar Files" - with driver.context(driver.CONTEXT_CHROME): - nav.context_click(nav.get_element("download-panel-item")) - context_menu.get_element("context-menu-always-open-similar-files").click() + nav.set_always_open_similar_files() # Open about:preferences and check that zip mime type is present in the application list about_prefs.open() - about_prefs.element_exists("mime-type-item", labels=["application/zip"]) + about_prefs.get_app_name_for_mime_type("application/zip") # Remove the directory created as MacOS automatically unzips if sys_platform == "Darwin": From 032fb8f076d05065cec9ec3eac4df6390d68d3b1 Mon Sep 17 00:00:00 2001 From: soncuteanca Date: Wed, 1 Oct 2025 19:41:48 +0300 Subject: [PATCH 03/14] Add test 1756752 --- SELECTOR_INFO.md | 7 ++++++ modules/data/about_prefs.components.json | 10 +++++++- modules/page_object_prefs.py | 25 +++++++++++++++++++ .../test_set_always_ask_file_type.py | 22 ++++++++-------- 4 files changed, 52 insertions(+), 12 deletions(-) diff --git a/SELECTOR_INFO.md b/SELECTOR_INFO.md index 9f9e744d2..2d36aeebe 100644 --- a/SELECTOR_INFO.md +++ b/SELECTOR_INFO.md @@ -1151,6 +1151,13 @@ Description: The dropdown menu for default zoom selection Location: about:preferences - Zoom settings Path to .json: modules/data/about_prefs.components.json ``` +``` +Selector Name: unknown-content-type-dialog +Selector Data: unknownContentTypeWindo +Description: The unknown content type dialog +Location: about:preferences#general Applications subsection +Path to .json: modules/data/about_prefs.components.json +``` #### about_profiles ``` Selector Name: profile-container diff --git a/modules/data/about_prefs.components.json b/modules/data/about_prefs.components.json index 63628bc54..2b2d50092 100644 --- a/modules/data/about_prefs.components.json +++ b/modules/data/about_prefs.components.json @@ -541,5 +541,13 @@ "selectorData": "menuitem[data-l10n-id='preferences-default-zoom-value'][value='{.*}']", "strategy": "css", "groups": [] - } + }, + + "unknown-content-type-dialog": { + "selectorData": "unknownContentTypeWindow", + "strategy": "id", + "groups": [ + "doNotCache" + ] + } } diff --git a/modules/page_object_prefs.py b/modules/page_object_prefs.py index 2ae5a48e5..8f870b236 100644 --- a/modules/page_object_prefs.py +++ b/modules/page_object_prefs.py @@ -657,6 +657,31 @@ def get_app_name_for_mime_type(self, mime_type: str) -> str: mime_type_data = json.loads(action_description.get_attribute("data-l10n-args")) return mime_type_data["app-name"] + def set_pdf_handling_to_always_ask(self) -> BasePage: + """ + Set PDF content type handling to "Always ask" in Applications settings. + """ + self.click_on("pdf-content-type") + self.click_on("pdf-actions-menu") + menu = self.get_element("pdf-actions-menu") + menu.send_keys(Keys.DOWN) + menu.send_keys(Keys.ENTER) + return self + + @BasePage.context_chrome + def handle_unknown_content_dialog(self) -> BasePage: + """ + Wait for the unknown content type dialog to appear and close it with Escape. + """ + self.wait.until(lambda _: len(self.driver.window_handles) > 1) + self.driver.switch_to.window(self.driver.window_handles[-1]) + self.wait.until(lambda _: self.get_element("unknown-content-type-dialog")) + + # Close the dialog with Escape + dialog = self.get_element("unknown-content-type-dialog") + dialog.send_keys(Keys.ESCAPE) + return self + class AboutAddons(BasePage): """ diff --git a/tests/downloads/test_set_always_ask_file_type.py b/tests/downloads/test_set_always_ask_file_type.py index de3eb88ea..7a03335bd 100644 --- a/tests/downloads/test_set_always_ask_file_type.py +++ b/tests/downloads/test_set_always_ask_file_type.py @@ -27,21 +27,21 @@ def delete_files_regex_string(): @pytest.mark.ci def test_set_always_ask_file_type(driver: Firefox, delete_files): """ - C1756752: Ensure that the Always ask option in Firefox Applications settings + C1756752 - Ensure that the Always ask option in Firefox Applications settings leads to a dialog asking "What should Firefox do with this file?" when the file type is downloaded. """ + + # Initialize page objects nav = Navigation(driver) - about_prefs = AboutPrefs(driver, category="general").open() + about_prefs = AboutPrefs(driver, category="general") - about_prefs.click_on("pdf-content-type") - about_prefs.click_on("pdf-actions-menu") - menu = about_prefs.get_element("pdf-actions-menu") - menu.send_keys(Keys.DOWN) - menu.send_keys(Keys.ENTER) + # Set PDF handling to "Always ask" + about_prefs.open() + about_prefs.set_pdf_handling_to_always_ask() + # Navigate to download URL and verify dialog appears nav.search(CONTENT_DISPOSITION_ATTACHMENT_URL) - sleep(2) - with driver.context(driver.CONTEXT_CHROME): - driver.switch_to.window(driver.window_handles[-1]) - driver.find_element(By.ID, "unknownContentTypeWindow").send_keys(Keys.ESCAPE) + + # Wait for and handle the unknown content type dialog + about_prefs.handle_unknown_content_dialog() From ecd51cd48256b8ba50c28928951c2ebc94b776f3 Mon Sep 17 00:00:00 2001 From: soncuteanca Date: Wed, 1 Oct 2025 19:58:32 +0300 Subject: [PATCH 04/14] Remove unused imports --- tests/downloads/test_set_always_ask_file_type.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/downloads/test_set_always_ask_file_type.py b/tests/downloads/test_set_always_ask_file_type.py index 7a03335bd..b9abd7244 100644 --- a/tests/downloads/test_set_always_ask_file_type.py +++ b/tests/downloads/test_set_always_ask_file_type.py @@ -1,9 +1,5 @@ -from time import sleep - import pytest from selenium.webdriver import Firefox -from selenium.webdriver.common.by import By -from selenium.webdriver.common.keys import Keys from modules.browser_object import Navigation from modules.page_object import AboutPrefs From 1109a6169b6519c8b12b39bbde468baaa8e634d9 Mon Sep 17 00:00:00 2001 From: soncuteanca Date: Thu, 2 Oct 2025 14:51:41 +0300 Subject: [PATCH 05/14] Add refactored test 1756769 --- tests/downloads/test_download_pdf.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/downloads/test_download_pdf.py b/tests/downloads/test_download_pdf.py index 6bb1896fe..7c8eed69f 100644 --- a/tests/downloads/test_download_pdf.py +++ b/tests/downloads/test_download_pdf.py @@ -27,12 +27,22 @@ def test_download_pdf( delete_files, ): """ - C1756769: Verify that the user can Download a PDF + C1756769 - Verify that the user can Download a PDF + + Notes: + - Firefox is launched with a **new profile** that has default download settings. + - This means the OS-level "Save File" dialog will appear for every download. + - Selenium cannot interact with this native dialog directly, so the test + must rely on fixed waits to give the OS time to render the dialog and to + finish writing the file. """ - pdf = GenericPdf(driver, pdf_url=fillable_pdf_url).open() + + # Initialize objects + pdf = GenericPdf(driver, pdf_url=fillable_pdf_url) keyboard = Controller() # Click the download button + pdf.open() download_button = pdf.get_element("download-button") download_button.click() From 9b7ee076cb8f9b5d146efdfee480853b01d5fec9 Mon Sep 17 00:00:00 2001 From: soncuteanca Date: Thu, 2 Oct 2025 18:51:19 +0300 Subject: [PATCH 06/14] Method and docstring changes --- tests/downloads/test_add_mime_type_doc.py | 2 +- tests/downloads/test_download_pdf.py | 5 ++--- .../test_download_pdf_from_context_menu.py | 21 +++++++++++++------ 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/tests/downloads/test_add_mime_type_doc.py b/tests/downloads/test_add_mime_type_doc.py index 99094dfb2..c4d498a97 100644 --- a/tests/downloads/test_add_mime_type_doc.py +++ b/tests/downloads/test_add_mime_type_doc.py @@ -25,7 +25,7 @@ def delete_files_regex_string(): def expected_app_name(sys_platform: str, opt_ci: bool) -> str: """ - Decide which default application should be used to open .doc files, based on OS and CI environment + Decide which default application should be used to open .doc files, based on OS """ if sys_platform == "Darwin": return "TextEdit" if opt_ci else "Pages" diff --git a/tests/downloads/test_download_pdf.py b/tests/downloads/test_download_pdf.py index 7c8eed69f..382cdfc35 100644 --- a/tests/downloads/test_download_pdf.py +++ b/tests/downloads/test_download_pdf.py @@ -30,7 +30,7 @@ def test_download_pdf( C1756769 - Verify that the user can Download a PDF Notes: - - Firefox is launched with a **new profile** that has default download settings. + - Firefox is launched with a new profile (also a test case precondition) that has default download settings. - This means the OS-level "Save File" dialog will appear for every download. - Selenium cannot interact with this native dialog directly, so the test must rely on fixed waits to give the OS time to render the dialog and to @@ -43,8 +43,7 @@ def test_download_pdf( # Click the download button pdf.open() - download_button = pdf.get_element("download-button") - download_button.click() + pdf.click_download_button() # Allow time for the download dialog to appear and pressing handle the prompt time.sleep(2) diff --git a/tests/downloads/test_download_pdf_from_context_menu.py b/tests/downloads/test_download_pdf_from_context_menu.py index c2ebabab9..a7815bd9e 100644 --- a/tests/downloads/test_download_pdf_from_context_menu.py +++ b/tests/downloads/test_download_pdf_from_context_menu.py @@ -28,18 +28,27 @@ def test_download_pdf_from_context_menu( ): """ C1756790: Verify that Telemetry is Recorded when Saving a PDF from the Context menu + + Notes: + - Firefox is launched with a new profile (also a test case precondition) that has default download settings. + - This means the OS-level "Save File" dialog will appear for every download. + - Selenium cannot interact with this native dialog directly, so the test + must rely on fixed waits to give the OS time to render the dialog and to + finish writing the file. """ from pynput.keyboard import Controller + # Initialize objects pdf = GenericPdf(driver, pdf_url=fillable_pdf_url) - pdf.open() keyboard = Controller() - body = pdf.get_element("pdf-body") + context_menu = ContextMenu(driver) + about_telemetry = AboutTelemetry(driver) - # Right-click on the body of the file and select Save page as + # Open the PDF file, right-click on the body of the file and select "Save page as" + pdf.open() + body = pdf.get_element("pdf-body") pdf.context_click(body) - context_menu = ContextMenu(driver) context_menu.click_and_hide_menu("context-menu-save-page-as") # Allow time for the save dialog to appear and handle prompt @@ -51,8 +60,8 @@ def test_download_pdf_from_context_menu( sleep(3) # Open about:telemetry and go to events tab - about_telemetry = AboutTelemetry(driver).open() - about_telemetry.get_element("events-tab").click() + about_telemetry.open() + about_telemetry.click_on("events-tab") # Verify that Telemetry is recorded pdf_telemetry_data = ["downloads", "added", "fileExtension", "pdf"] From 5f23fc65294103fde0f5430a82b095df923cb93e Mon Sep 17 00:00:00 2001 From: soncuteanca Date: Thu, 2 Oct 2025 20:26:52 +0300 Subject: [PATCH 07/14] Add refactored test 1756722 --- modules/browser_object_navigation.py | 54 ++++++++++++------- modules/data/navigation.components.json | 18 +++++++ .../test_mixed_content_download_via_https.py | 51 ++++-------------- 3 files changed, 63 insertions(+), 60 deletions(-) diff --git a/modules/browser_object_navigation.py b/modules/browser_object_navigation.py index 6dbf735ee..32f31d37b 100644 --- a/modules/browser_object_navigation.py +++ b/modules/browser_object_navigation.py @@ -1,7 +1,8 @@ import logging +import re from typing import Literal -from selenium.common.exceptions import TimeoutException +from selenium.common.exceptions import StaleElementReferenceException, TimeoutException from selenium.webdriver import ActionChains, Firefox from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys @@ -290,27 +291,40 @@ def click_file_download_warning_panel(self) -> BasePage: self.click_on("file-download-warning-button") return self - def wait_for_item_to_download(self, filename: str) -> BasePage: + @BasePage.context_chrome + def wait_for_download_elements(self) -> BasePage: """ - Check the downloads tool in the toolbar to wait for a given file to download + Wait for download elements to be present. """ - original_timeout = self.driver.timeouts.implicit_wait - try: - # Whatever our timeout, we want to lengthen it because downloads - self.driver.implicitly_wait(original_timeout * 2) - self.element_visible("downloads-item-by-file", labels=[filename]) - self.expect_not( - EC.element_attribute_to_include( - self.get_selector("downloads-button"), "animate" - ) - ) - with self.driver.context(self.context_id): - self.driver.execute_script( - "arguments[0].setAttribute('hidden', true)", - self.get_element("downloads-button"), - ) - finally: - self.driver.implicitly_wait(original_timeout) + self.element_visible("download-target-element") + return self + + @BasePage.context_chrome + def verify_download_name(self, expected_pattern: str) -> BasePage: + """ + Verify download name matches expected pattern. + Argument: + expected_pattern: Regex pattern to match against download name + """ + download_name = self.get_element("download-target-element") + download_value = download_name.get_attribute("value") + assert re.match(expected_pattern, download_value), ( + f"The download name is incorrect: {download_value}" + ) + return self + + @BasePage.context_chrome + def wait_for_download_completion(self) -> BasePage: + """Wait until the most recent download reaches 100% progress.""" + + def _download_complete(_): + try: + element = self.get_element("download-progress-element") + return element.get_attribute("value") == "100" + except StaleElementReferenceException: + return False + + self.wait.until(_download_complete) return self @BasePage.context_chrome diff --git a/modules/data/navigation.components.json b/modules/data/navigation.components.json index 33108ce28..61c18f3c9 100644 --- a/modules/data/navigation.components.json +++ b/modules/data/navigation.components.json @@ -405,6 +405,24 @@ "groups": [] }, + "download-target-element": { + "selectorData": "downloadTarget", + "strategy": "class", + "groups": [] + }, + + "download-progress-element": { + "selectorData": "downloadProgress", + "strategy": "class", + "groups": [] + }, + + "download-details-element": { + "selectorData": "downloadDetailsNormal", + "strategy": "class", + "groups": [] + }, + "bookmark-in-bar": { "selectorData": "toolbarbutton.bookmark-item", "strategy": "css", diff --git a/tests/downloads/test_mixed_content_download_via_https.py b/tests/downloads/test_mixed_content_download_via_https.py index b75bcb2d4..bc86d38d6 100644 --- a/tests/downloads/test_mixed_content_download_via_https.py +++ b/tests/downloads/test_mixed_content_download_via_https.py @@ -1,13 +1,7 @@ -import re -from time import sleep - import pytest -from selenium.common.exceptions import StaleElementReferenceException from selenium.webdriver import Firefox -from selenium.webdriver.common.by import By -from selenium.webdriver.support import expected_conditions as EC -from selenium.webdriver.support.wait import WebDriverWait +from modules.browser_object import Navigation from modules.page_object import GenericPage @@ -31,42 +25,19 @@ def test_mixed_content_download_via_https(driver: Firefox, delete_files): """ C1756722: Verify that the user can download mixed content via HTTPS """ - + # Initialize objects web_page = GenericPage(driver, url=MIXED_CONTENT_DOWNLOAD_URL) + nav = Navigation(driver) - # Wait up to 30 seconds for test website to wake up and download the content + # Wait for the test website to wake up and download the content web_page.open() - with driver.context(driver.CONTEXT_CHROME): - WebDriverWait(driver, 30).until(EC.title_contains("File Examples")) - - with driver.context(driver.CONTEXT_CHROME): - download_name = WebDriverWait(driver, 10).until( - EC.presence_of_element_located((By.CLASS_NAME, "downloadTarget")) - ) - - download_status = WebDriverWait(driver, 10).until( - EC.presence_of_element_located((By.CLASS_NAME, "downloadProgress")) - ) + web_page.wait.until(lambda _: web_page.title_contains("File Examples")) - # Verify that the desired download target element is present directly, no extra steps needed. - download_value = download_name.get_attribute("value") - assert re.match(r"file-sample_100kB(\(\d+\)).odt$", download_value), ( - f"The download name is incorrect: {download_value}" - ) + # Wait for download elements to appear + nav.wait_for_download_elements() - # Verify that the download progress has reached 100%, which indicates that the download is complete. - i = 1 - while True: - try: - download_value = download_status.get_attribute("value") - if download_value == "100": - break - except StaleElementReferenceException: - pass + # Verify download name matches expected pattern + nav.verify_download_name(r"file-sample_100kB(\(\d+\))?.odt$") - if i > MAX_CHECKS: - raise TimeoutError( - "Download progress did not reach 100% within reasonable time." - ) - sleep(1) - i = +1 + # Wait for download completion + nav.wait_for_download_completion() From 51df1d705a9d9d3a6ee204e80e14138c5ecd126e Mon Sep 17 00:00:00 2001 From: soncuteanca Date: Thu, 2 Oct 2025 21:01:35 +0300 Subject: [PATCH 08/14] Add removed method by mistake --- modules/browser_object_navigation.py | 31 ++++++++++++++++--- .../test_mixed_content_download_via_https.py | 3 -- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/modules/browser_object_navigation.py b/modules/browser_object_navigation.py index 32f31d37b..60db5ebc2 100644 --- a/modules/browser_object_navigation.py +++ b/modules/browser_object_navigation.py @@ -291,12 +291,35 @@ def click_file_download_warning_panel(self) -> BasePage: self.click_on("file-download-warning-button") return self - @BasePage.context_chrome - def wait_for_download_elements(self) -> BasePage: + # @BasePage.context_chrome + # def wait_for_download_elements(self) -> BasePage: + # """ + # Wait for download elements to be present. + # """ + # self.element_visible("download-target-element") + # return self + + def wait_for_item_to_download(self, filename: str) -> BasePage: """ - Wait for download elements to be present. + Check the downloads tool in the toolbar to wait for a given file to download """ - self.element_visible("download-target-element") + original_timeout = self.driver.timeouts.implicit_wait + try: + # Whatever our timeout, we want to lengthen it because downloads + self.driver.implicitly_wait(original_timeout * 2) + self.element_visible("downloads-item-by-file", labels=[filename]) + self.expect_not( + EC.element_attribute_to_include( + self.get_selector("downloads-button"), "animate" + ) + ) + with self.driver.context(self.context_id): + self.driver.execute_script( + "arguments[0].setAttribute('hidden', true)", + self.get_element("downloads-button"), + ) + finally: + self.driver.implicitly_wait(original_timeout) return self @BasePage.context_chrome diff --git a/tests/downloads/test_mixed_content_download_via_https.py b/tests/downloads/test_mixed_content_download_via_https.py index bc86d38d6..a43219129 100644 --- a/tests/downloads/test_mixed_content_download_via_https.py +++ b/tests/downloads/test_mixed_content_download_via_https.py @@ -33,9 +33,6 @@ def test_mixed_content_download_via_https(driver: Firefox, delete_files): web_page.open() web_page.wait.until(lambda _: web_page.title_contains("File Examples")) - # Wait for download elements to appear - nav.wait_for_download_elements() - # Verify download name matches expected pattern nav.verify_download_name(r"file-sample_100kB(\(\d+\))?.odt$") From 940514d070ec150a05341b3d5b10a320a9b8cef6 Mon Sep 17 00:00:00 2001 From: soncuteanca Date: Fri, 3 Oct 2025 10:25:06 +0300 Subject: [PATCH 09/14] Test theory for CI flakiness --- tests/downloads/test_download_pdf_from_context_menu.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/downloads/test_download_pdf_from_context_menu.py b/tests/downloads/test_download_pdf_from_context_menu.py index a7815bd9e..49f511e4c 100644 --- a/tests/downloads/test_download_pdf_from_context_menu.py +++ b/tests/downloads/test_download_pdf_from_context_menu.py @@ -61,7 +61,7 @@ def test_download_pdf_from_context_menu( # Open about:telemetry and go to events tab about_telemetry.open() - about_telemetry.click_on("events-tab") + about_telemetry.get_element("events-tab").click() # Verify that Telemetry is recorded pdf_telemetry_data = ["downloads", "added", "fileExtension", "pdf"] From ba22be7cbef5ec71122c156ad5afb5176b7e2254 Mon Sep 17 00:00:00 2001 From: soncuteanca Date: Fri, 3 Oct 2025 11:09:57 +0300 Subject: [PATCH 10/14] Revert test to initial state --- .../test_download_pdf_from_context_menu.py | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/tests/downloads/test_download_pdf_from_context_menu.py b/tests/downloads/test_download_pdf_from_context_menu.py index 49f511e4c..c2ebabab9 100644 --- a/tests/downloads/test_download_pdf_from_context_menu.py +++ b/tests/downloads/test_download_pdf_from_context_menu.py @@ -28,27 +28,18 @@ def test_download_pdf_from_context_menu( ): """ C1756790: Verify that Telemetry is Recorded when Saving a PDF from the Context menu - - Notes: - - Firefox is launched with a new profile (also a test case precondition) that has default download settings. - - This means the OS-level "Save File" dialog will appear for every download. - - Selenium cannot interact with this native dialog directly, so the test - must rely on fixed waits to give the OS time to render the dialog and to - finish writing the file. """ from pynput.keyboard import Controller - # Initialize objects pdf = GenericPdf(driver, pdf_url=fillable_pdf_url) - keyboard = Controller() - context_menu = ContextMenu(driver) - about_telemetry = AboutTelemetry(driver) - - # Open the PDF file, right-click on the body of the file and select "Save page as" pdf.open() + keyboard = Controller() body = pdf.get_element("pdf-body") + + # Right-click on the body of the file and select Save page as pdf.context_click(body) + context_menu = ContextMenu(driver) context_menu.click_and_hide_menu("context-menu-save-page-as") # Allow time for the save dialog to appear and handle prompt @@ -60,7 +51,7 @@ def test_download_pdf_from_context_menu( sleep(3) # Open about:telemetry and go to events tab - about_telemetry.open() + about_telemetry = AboutTelemetry(driver).open() about_telemetry.get_element("events-tab").click() # Verify that Telemetry is recorded From ed42c36045a34ec8ed0d4f0731b54e12f88cbe3c Mon Sep 17 00:00:00 2001 From: soncuteanca Date: Fri, 3 Oct 2025 15:53:30 +0300 Subject: [PATCH 11/14] Test CI --- tests/downloads/test_add_mime_type_doc.py | 2 +- .../test_download_pdf_from_context_menu.py | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/tests/downloads/test_add_mime_type_doc.py b/tests/downloads/test_add_mime_type_doc.py index c4d498a97..0231cfae9 100644 --- a/tests/downloads/test_add_mime_type_doc.py +++ b/tests/downloads/test_add_mime_type_doc.py @@ -33,7 +33,7 @@ def expected_app_name(sys_platform: str, opt_ci: bool) -> str: return "LibreOffice Writer" -@pytest.mark.skipif(WIN_GHA, reason="Test unstable in Windows Github Actions") +# @pytest.mark.skipif(WIN_GHA, reason="Test unstable in Windows Github Actions") @pytest.mark.noxvfb def test_mime_type_doc(driver: Firefox, sys_platform: str, opt_ci: bool, delete_files): """ diff --git a/tests/downloads/test_download_pdf_from_context_menu.py b/tests/downloads/test_download_pdf_from_context_menu.py index c2ebabab9..3c5ee7a43 100644 --- a/tests/downloads/test_download_pdf_from_context_menu.py +++ b/tests/downloads/test_download_pdf_from_context_menu.py @@ -28,18 +28,26 @@ def test_download_pdf_from_context_menu( ): """ C1756790: Verify that Telemetry is Recorded when Saving a PDF from the Context menu + + Notes: + - Firefox is launched with a new profile (also a test case precondition) that has default download settings. + - This means the OS-level "Save File" dialog will appear for every download. + - Selenium cannot interact with this native dialog directly, so the test + must rely on fixed waits to give the OS time to render the dialog and to + finish writing the file. """ from pynput.keyboard import Controller + # Initialize objects pdf = GenericPdf(driver, pdf_url=fillable_pdf_url) - pdf.open() keyboard = Controller() - body = pdf.get_element("pdf-body") + context_menu = ContextMenu(driver) - # Right-click on the body of the file and select Save page as + # Open the PDF file, right-click on the body of the file and select Save page as + pdf.open() + body = pdf.get_element("pdf-body") pdf.context_click(body) - context_menu = ContextMenu(driver) context_menu.click_and_hide_menu("context-menu-save-page-as") # Allow time for the save dialog to appear and handle prompt @@ -51,7 +59,8 @@ def test_download_pdf_from_context_menu( sleep(3) # Open about:telemetry and go to events tab - about_telemetry = AboutTelemetry(driver).open() + about_telemetry = AboutTelemetry(driver) + about_telemetry.open() about_telemetry.get_element("events-tab").click() # Verify that Telemetry is recorded From 1aab88b89d98c754e73dcfce379ebcd0d0f39910 Mon Sep 17 00:00:00 2001 From: soncuteanca Date: Fri, 3 Oct 2025 16:52:13 +0300 Subject: [PATCH 12/14] Revert, modify --- tests/downloads/test_add_mime_type_doc.py | 2 -- tests/downloads/test_add_zip_type.py | 2 +- .../downloads/test_download_pdf_from_context_menu.py | 12 ++++++------ 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/tests/downloads/test_add_mime_type_doc.py b/tests/downloads/test_add_mime_type_doc.py index 0231cfae9..8b170fbdb 100644 --- a/tests/downloads/test_add_mime_type_doc.py +++ b/tests/downloads/test_add_mime_type_doc.py @@ -15,7 +15,6 @@ def test_case(): # Constants DOC_LINK = "https://sapphire-hendrika-5.tiiny.site/" -WIN_GHA = environ.get("GITHUB_ACTIONS") == "true" and sys.platform.startswith("win") @pytest.fixture() @@ -33,7 +32,6 @@ def expected_app_name(sys_platform: str, opt_ci: bool) -> str: return "LibreOffice Writer" -# @pytest.mark.skipif(WIN_GHA, reason="Test unstable in Windows Github Actions") @pytest.mark.noxvfb def test_mime_type_doc(driver: Firefox, sys_platform: str, opt_ci: bool, delete_files): """ diff --git a/tests/downloads/test_add_zip_type.py b/tests/downloads/test_add_zip_type.py index e68c84f3d..426e30769 100644 --- a/tests/downloads/test_add_zip_type.py +++ b/tests/downloads/test_add_zip_type.py @@ -68,7 +68,7 @@ def test_add_zip_type( about_prefs.open() about_prefs.get_app_name_for_mime_type("application/zip") - # Remove the directory created as MacOS automatically unzips + # Remove the directory created as macOS automatically unzips if sys_platform == "Darwin": dir_created = os.path.join(home_folder, "Downloads", "api-guidelines-vNext") shutil.rmtree(dir_created) diff --git a/tests/downloads/test_download_pdf_from_context_menu.py b/tests/downloads/test_download_pdf_from_context_menu.py index 3c5ee7a43..8b3280c1e 100644 --- a/tests/downloads/test_download_pdf_from_context_menu.py +++ b/tests/downloads/test_download_pdf_from_context_menu.py @@ -36,18 +36,19 @@ def test_download_pdf_from_context_menu( must rely on fixed waits to give the OS time to render the dialog and to finish writing the file. """ + # Any attempt to refactor this test make the test fail in CI, if time, it can be revised later. from pynput.keyboard import Controller # Initialize objects pdf = GenericPdf(driver, pdf_url=fillable_pdf_url) - keyboard = Controller() - context_menu = ContextMenu(driver) - - # Open the PDF file, right-click on the body of the file and select Save page as pdf.open() + keyboard = Controller() body = pdf.get_element("pdf-body") + + # Right-click on the body of the file and select Save page as pdf.context_click(body) + context_menu = ContextMenu(driver) context_menu.click_and_hide_menu("context-menu-save-page-as") # Allow time for the save dialog to appear and handle prompt @@ -59,8 +60,7 @@ def test_download_pdf_from_context_menu( sleep(3) # Open about:telemetry and go to events tab - about_telemetry = AboutTelemetry(driver) - about_telemetry.open() + about_telemetry = AboutTelemetry(driver).open() about_telemetry.get_element("events-tab").click() # Verify that Telemetry is recorded From 51980201243ef2333166f52fa6db9a3356ba7434 Mon Sep 17 00:00:00 2001 From: soncuteanca Date: Fri, 3 Oct 2025 17:01:58 +0300 Subject: [PATCH 13/14] remove unused import --- tests/downloads/test_add_mime_type_doc.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/downloads/test_add_mime_type_doc.py b/tests/downloads/test_add_mime_type_doc.py index 8b170fbdb..8d72c7e3e 100644 --- a/tests/downloads/test_add_mime_type_doc.py +++ b/tests/downloads/test_add_mime_type_doc.py @@ -1,6 +1,3 @@ -import sys -from os import environ - import pytest from selenium.webdriver import Firefox From f3e887dcd073939ea9e360ccc85ab575991ea56a Mon Sep 17 00:00:00 2001 From: soncuteanca Date: Mon, 6 Oct 2025 15:25:37 +0300 Subject: [PATCH 14/14] Revert 3 CI unstable tests to initial state --- tests/downloads/test_add_mime_type_doc.py | 59 +++++++++++-------- tests/downloads/test_download_pdf.py | 17 ++---- .../test_download_pdf_from_context_menu.py | 9 --- 3 files changed, 39 insertions(+), 46 deletions(-) diff --git a/tests/downloads/test_add_mime_type_doc.py b/tests/downloads/test_add_mime_type_doc.py index 8d72c7e3e..4b30e5a49 100644 --- a/tests/downloads/test_add_mime_type_doc.py +++ b/tests/downloads/test_add_mime_type_doc.py @@ -1,7 +1,11 @@ +import json +import sys +from os import environ + import pytest from selenium.webdriver import Firefox -from modules.browser_object import Navigation +from modules.browser_object import ContextMenu, Navigation from modules.page_object import AboutPrefs, GenericPage @@ -10,44 +14,51 @@ def test_case(): return "1756748" -# Constants DOC_LINK = "https://sapphire-hendrika-5.tiiny.site/" +WIN_GHA = environ.get("GITHUB_ACTIONS") == "true" and sys.platform.startswith("win") + @pytest.fixture() def delete_files_regex_string(): return r"sample.*\.doc" -def expected_app_name(sys_platform: str, opt_ci: bool) -> str: - """ - Decide which default application should be used to open .doc files, based on OS - """ - if sys_platform == "Darwin": - return "TextEdit" if opt_ci else "Pages" - # Linux/Windows use LibreOffice - return "LibreOffice Writer" - - +@pytest.mark.skipif(WIN_GHA, reason="Test unstable in Windows Github Actions") @pytest.mark.noxvfb def test_mime_type_doc(driver: Firefox, sys_platform: str, opt_ci: bool, delete_files): """ - C1756748 - Verify that downloading a .doc file adds a new MIME type entry - and the correct default application is assigned. + C1756748: Verify the user can add the .doc type """ - # Instantiate objects - page = GenericPage(driver, url=DOC_LINK) + doc_page = GenericPage(driver, url=DOC_LINK).open() nav = Navigation(driver) + context_menu = ContextMenu(driver) about_prefs = AboutPrefs(driver, category="general") + doc_page.get_element("sample-doc-download").click() - # Open the test page with the .doc download link - page.open() - page.click_on("sample-doc-download") + downloads_button = nav.get_download_button() - # Download the file and set 'Always Open Similar Files' - nav.set_always_open_similar_files() + with driver.context(driver.CONTEXT_CHROME): + downloads_button.click() + download_item = nav.get_element("download-panel-item") + nav.context_click(download_item) + context_menu.get_element("context-menu-always-open-similar-files").click() - # Verify the MIME type entry exists and default app matches expectation about_prefs.open() - app_name = about_prefs.get_app_name_for_mime_type("application/msword") - assert app_name == expected_app_name(sys_platform, opt_ci) + about_prefs.element_exists("mime-type-item", labels=["application/msword"]) + + mime_type_item = about_prefs.get_element( + "mime-type-item", labels=["application/msword"] + ) + action_description_item = about_prefs.get_element( + "mime-type-item-description", parent_element=mime_type_item + ) + + mime_type_data = json.loads(action_description_item.get_attribute("data-l10n-args")) + if sys_platform == "Darwin": + if opt_ci: + assert mime_type_data["app-name"] == "TextEdit" + else: + assert mime_type_data["app-name"] == "Pages" + else: + assert mime_type_data["app-name"] == "LibreOffice Writer" diff --git a/tests/downloads/test_download_pdf.py b/tests/downloads/test_download_pdf.py index 382cdfc35..6bb1896fe 100644 --- a/tests/downloads/test_download_pdf.py +++ b/tests/downloads/test_download_pdf.py @@ -27,23 +27,14 @@ def test_download_pdf( delete_files, ): """ - C1756769 - Verify that the user can Download a PDF - - Notes: - - Firefox is launched with a new profile (also a test case precondition) that has default download settings. - - This means the OS-level "Save File" dialog will appear for every download. - - Selenium cannot interact with this native dialog directly, so the test - must rely on fixed waits to give the OS time to render the dialog and to - finish writing the file. + C1756769: Verify that the user can Download a PDF """ - - # Initialize objects - pdf = GenericPdf(driver, pdf_url=fillable_pdf_url) + pdf = GenericPdf(driver, pdf_url=fillable_pdf_url).open() keyboard = Controller() # Click the download button - pdf.open() - pdf.click_download_button() + download_button = pdf.get_element("download-button") + download_button.click() # Allow time for the download dialog to appear and pressing handle the prompt time.sleep(2) diff --git a/tests/downloads/test_download_pdf_from_context_menu.py b/tests/downloads/test_download_pdf_from_context_menu.py index 8b3280c1e..c2ebabab9 100644 --- a/tests/downloads/test_download_pdf_from_context_menu.py +++ b/tests/downloads/test_download_pdf_from_context_menu.py @@ -28,19 +28,10 @@ def test_download_pdf_from_context_menu( ): """ C1756790: Verify that Telemetry is Recorded when Saving a PDF from the Context menu - - Notes: - - Firefox is launched with a new profile (also a test case precondition) that has default download settings. - - This means the OS-level "Save File" dialog will appear for every download. - - Selenium cannot interact with this native dialog directly, so the test - must rely on fixed waits to give the OS time to render the dialog and to - finish writing the file. """ - # Any attempt to refactor this test make the test fail in CI, if time, it can be revised later. from pynput.keyboard import Controller - # Initialize objects pdf = GenericPdf(driver, pdf_url=fillable_pdf_url) pdf.open() keyboard = Controller()