Skip to content
Merged
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
102 changes: 70 additions & 32 deletions tests/theme_and_toolbar/test_customize_themes_and_redirect.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import pytest
from selenium.webdriver import Firefox

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

Expand All @@ -10,82 +9,121 @@ def test_case():
return "118173"


themes = {
"firefox-compact-dark_mozilla_org-heading": "rgb(43, 42, 51)",
"firefox-compact-light_mozilla_org-heading": "rgb(249, 249, 251)",
THEMES: dict[str, list[str]] = {
"firefox-compact-dark_mozilla_org-heading": [
"rgb(43, 42, 51)", # classic darker tone
"rgb(143, 143, 148)", # focused dark
"rgb(120, 119, 126)", # dark without focus
],
# Compact Light
"firefox-compact-light_mozilla_org-heading": [
"rgb(249, 249, 251)",
],
}

ALPENGLOW_MAP: dict[str, str] = {
"light": "rgba(255, 255, 255, 0.76)",
"dark": "rgba(40, 29, 78, 0.96)",
}

alpenglow_map = {"light": "rgba(255, 255, 255, 0.76)", "dark": "rgba(40, 29, 78, 0.96)"}

def colors_match(a: str, b: str, tolerance: float = 0.14) -> bool:
"""
Compare two CSS color strings and determine if they are close enough to be considered equal.

def colors_match(a, b):
"""Determine if two colors are close enough to be considered matches"""
tolerance = 0.14
a_colorstring = a.split("(")[1][:-1]
b_colorstring = b.split("(")[1][:-1]
a_colors = [float(n) for n in a_colorstring.split(",")]
b_colors = [float(n) for n in b_colorstring.split(",")]
for i in range(len(a_colors)):
diff = abs((a_colors[i] / b_colors[i]) - 1.0)
Args:
a (str): First CSS color string in 'rgb(r,g,b)' or 'rgba(r,g,b,a)' format.
b (str): Second CSS color string in 'rgb(r,g,b)' or 'rgba(r,g,b,a)' format.
tolerance (float, optional): Allowed relative difference between each color channel.
Defaults to 0.14. A higher value means colors can differ more and still match.

Returns:
bool: True if the two colors are considered a match within the given tolerance.
False if the color strings are invalid.
"""
try:
a_vals = a.split("(")[1][:-1]
b_vals = b.split("(")[1][:-1]
a_nums = [float(n.strip()) for n in a_vals.split(",")]
b_nums = [float(n.strip()) for n in b_vals.split(",")]
except (IndexError, ValueError):
# Raised if string doesn't contain expected format or non-numeric parts
return False

# Compare up to the shortest length (rgb vs rgba)
for i in range(min(len(a_nums), len(b_nums))):
base = b_nums[i] if b_nums[i] != 0 else 1.0
diff = abs((a_nums[i] / base) - 1.0)
if diff > tolerance:
return False

return True


@pytest.mark.ci
def test_redirect_to_addons(driver: Firefox):
def test_redirect_to_addons(driver: Firefox) -> None:
"""
C118173, ensures that the user is redirected to about:addons through the ui panel
C118173: Ensure the user is redirected to about:addons via the UI panel.
"""
panel_ui = PanelUi(driver)
panel_ui.open()
panel_ui.open_panel_menu()
panel_ui.navigate_to_about_addons()
windows = driver.window_handles
driver.switch_to.window(windows[2])

# remember original window, then switch to newly opened one
orig = driver.window_handles[0]
new = driver.window_handles[-1]
driver.switch_to.window(new)
assert driver.current_url == "about:addons"

# cleanup: close the tab we opened and restore focus
driver.close()
driver.switch_to.window(orig)


@pytest.mark.parametrize("theme_name", list(themes.keys()))
def test_open_addons(driver: Firefox, theme_name: str):
@pytest.mark.parametrize("theme_name", list(THEMES.keys()))
def test_activate_theme_background_matches_expected(driver: Firefox, theme_name: str) -> None:
"""
C118173, continuation ensures that all the themes are set correctly
C118173: Ensure that activating each theme in about:addons applies the expected background color.
Handles Developer Edition vs standard Firefox defaults.
"""

nav = Navigation(driver)
abt_addons = AboutAddons(driver).open()
abt_addons.choose_sidebar_option("theme")

# Dynamically detect if running Developer Edition
if abt_addons.is_devedition():
# Adjust expectations for Developer Edition
if theme_name == "firefox-compact-dark_mozilla_org-heading":
# Already default on Developer Edition; skip activation/assertion
pytest.skip("Compact Dark is default on DevEdition, skipping.")
else:
# Adjust expectations for standard Firefox
if theme_name == "firefox-compact-light_mozilla_org-heading":
# Already default on Firefox standard; skip activation/assertion
pytest.skip("Compact Light is default on Firefox, skipping.")

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

expected_list = THEMES[theme_name]
assert any(colors_match(current_bg, exp) for exp in expected_list), (
f"Got {current_bg} for {theme_name}; expected one of {expected_list}"
)
assert colors_match(current_bg, themes[theme_name])


def test_alpenglow_theme(driver: Firefox):
def test_alpenglow_theme(driver: Firefox) -> None:
"""
C118173, specifically for alpenglow theme because color can be two values for dark or light mode
C118173: Alpenglow theme can render two values depending on light / dark mode.
Accept either using the tolerance-based comparison.
"""

nav = Navigation(driver)
abt_addons = AboutAddons(driver).open()
abt_addons.choose_sidebar_option("theme")

current_bg = abt_addons.activate_theme(
nav, "firefox-alpenglow_mozilla_org-heading", "", perform_assert=False
)

# assert current_bg == alpenglow_map["light"] or current_bg == alpenglow_map["dark"]
assert colors_match(current_bg, alpenglow_map["light"]) or colors_match(
current_bg, alpenglow_map["dark"]
assert colors_match(current_bg, ALPENGLOW_MAP["light"]) or colors_match(
current_bg, ALPENGLOW_MAP["dark"]
)
35 changes: 21 additions & 14 deletions tests/theme_and_toolbar/test_installed_theme_enabled.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,39 +12,46 @@ def test_case():
return "118174"


MAC_GHA = environ.get("GITHUB_ACTIONS") == "true" and sys.platform.startswith("darwin")
MAC_GHA: bool = environ.get("GITHUB_ACTIONS") == "true" and sys.platform.startswith("darwin")

AMO_HOST: str = "addons.mozilla.org"
AMO_THEMES_PATH: str = "firefox/themes"


@pytest.mark.skipif(MAC_GHA, reason="Test unstable in MacOS Github Actions")
def test_find_more_themes(driver: Firefox):
def test_find_more_themes(driver: Firefox) -> None:
"""
C118174, first part
C118174 (part 1): From about:addons > Themes, 'Find more themes' opens AMO in a new tab.
Verify AMO host and themes path are present in the URL.
"""
about_addons = AboutAddons(driver).open()
about_addons.choose_sidebar_option("theme")
about_addons.get_element("find-more-themes-button").click()

driver.switch_to.window(driver.window_handles[-1])

# Continuing to call the object "about_addons" is confusing
base = about_addons
base.url_contains("addons.mozilla.org")
base.url_contains("firefox/themes")
base.url_contains(AMO_HOST)
base.url_contains(AMO_THEMES_PATH)


@pytest.mark.skipif(MAC_GHA, reason="Test unstable in MacOS Github Actions")
def test_installed_theme_enabled(driver: Firefox):
def test_installed_theme_enabled(driver: Firefox) -> None:
"""
C118174: install a theme and make sure it is set to enabled immediately
C118174 (part 2): Install a recommended theme from AMO and ensure it becomes enabled immediately.
"""
about_addons = AboutAddons(driver).open()
about_addons.choose_sidebar_option("theme")
starting_theme = about_addons.get_element("enabled-theme-title").get_attribute(
"innerText"
)
amo = AmoThemes(driver).open()
amo.install_recommended_theme()

# Capture currently enabled theme title
starting_theme = about_addons.get_element("enabled-theme-title").get_attribute("innerText")

# Go to AMO and install a recommended theme (POM encapsulates waits and flows)
AmoThemes(driver).open().install_recommended_theme()

# Return to about:addons > Themes and verify the enabled theme changed
about_addons = AboutAddons(driver).open()
about_addons.choose_sidebar_option("theme")

# NOTE: AMO does not enforce that the listed theme name remains the same after installation
# AMO may change display names; we only assert that the enabled theme is different
about_addons.check_theme_has_changed(starting_theme)