Skip to content
Draft
7 changes: 7 additions & 0 deletions SELECTOR_INFO.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
54 changes: 53 additions & 1 deletion modules/browser_object_navigation.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -245,6 +246,21 @@ 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(
self, downloads_button: WebElement
Expand Down Expand Up @@ -275,6 +291,14 @@ 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:
# """
# 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:
"""
Check the downloads tool in the toolbar to wait for a given file to download
Expand All @@ -298,6 +322,34 @@ def wait_for_item_to_download(self, filename: str) -> BasePage:
self.driver.implicitly_wait(original_timeout)
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
def refresh_page(self) -> BasePage:
"""
Expand Down
10 changes: 9 additions & 1 deletion modules/data/about_prefs.components.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
]
}
}
18 changes: 18 additions & 0 deletions modules/data/navigation.components.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
44 changes: 44 additions & 0 deletions modules/page_object_prefs.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import datetime
import json
import re
from time import sleep
from typing import List, Literal
Expand Down Expand Up @@ -638,6 +639,49 @@ 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"]

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):
"""
Expand Down
59 changes: 24 additions & 35 deletions tests/downloads/test_add_mime_type_doc.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
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


Expand All @@ -14,51 +10,44 @@ 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"


@pytest.mark.skipif(WIN_GHA, reason="Test unstable in Windows Github Actions")
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.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)
15 changes: 6 additions & 9 deletions tests/downloads/test_add_zip_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -50,28 +49,26 @@ 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
# 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)
17 changes: 13 additions & 4 deletions tests/downloads/test_download_pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,23 @@ 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 (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.
"""
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
download_button = pdf.get_element("download-button")
download_button.click()
pdf.open()
pdf.click_download_button()

# Allow time for the download dialog to appear and pressing handle the prompt
time.sleep(2)
Expand Down
9 changes: 9 additions & 0 deletions tests/downloads/test_download_pdf_from_context_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,19 @@ 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()
Expand Down
Loading
Loading