Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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)
50 changes: 9 additions & 41 deletions tests/downloads/test_mixed_content_download_via_https.py
Original file line number Diff line number Diff line change
@@ -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


Expand All @@ -31,42 +25,16 @@ 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"))
)

# 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}"
)
web_page.wait.until(lambda _: web_page.title_contains("File Examples"))

# 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()
26 changes: 11 additions & 15 deletions tests/downloads/test_set_always_ask_file_type.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -27,21 +23,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()
11 changes: 6 additions & 5 deletions tests/theme_and_toolbar/test_customize_themes_and_redirect.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pytest
from selenium.webdriver import Firefox

from modules.browser_object import Navigation, PanelUi
from modules.page_object import AboutAddons

Expand All @@ -11,7 +12,7 @@ def test_case():

THEMES: dict[str, list[str]] = {
"firefox-compact-dark_mozilla_org-heading": [
"rgb(43, 42, 51)", # classic darker tone
"rgb(43, 42, 51)", # classic darker tone
"rgb(143, 143, 148)", # focused dark
"rgb(120, 119, 126)", # dark without focus
],
Expand Down Expand Up @@ -82,7 +83,9 @@ def test_redirect_to_addons(driver: Firefox) -> None:


@pytest.mark.parametrize("theme_name", list(THEMES.keys()))
def test_activate_theme_background_matches_expected(driver: Firefox, theme_name: str) -> None:
def test_activate_theme_background_matches_expected(
driver: Firefox, theme_name: str
) -> None:
"""
C118173: Ensure that activating each theme in about:addons applies the expected background color.
Handles Developer Edition vs standard Firefox defaults.
Expand All @@ -100,9 +103,7 @@ def test_activate_theme_background_matches_expected(driver: Firefox, theme_name:
if theme_name == "firefox-compact-light_mozilla_org-heading":
pytest.skip("Compact Light is default on Firefox, skipping.")

current_bg = abt_addons.activate_theme(
nav, theme_name, "", perform_assert=False
)
current_bg = abt_addons.activate_theme(nav, theme_name, "", perform_assert=False)

expected_list = THEMES[theme_name]
assert any(colors_match(current_bg, exp) for exp in expected_list), (
Expand Down
Loading
Loading