Skip to content

Hani/ Test etp panel correctly displayed blocked trackers detected - #1419

Open
sv-hyacoub wants to merge 15 commits into
mainfrom
Hani/test-etp-panel-correctly-displayed-blocked-trackers-detected
Open

Hani/ Test etp panel correctly displayed blocked trackers detected#1419
sv-hyacoub wants to merge 15 commits into
mainfrom
Hani/test-etp-panel-correctly-displayed-blocked-trackers-detected

Conversation

@sv-hyacoub

Copy link
Copy Markdown
Collaborator

Relevant Links

Bugzilla: 2025830
TestRail: 3054905

Description of Code / Doc Changes

  • Add test to verify that ETP panel is correctly displayed when the blocked trackers are detected

Process Changes Required

Mark the relevant boxes, delete irrelevant lines.

  • Adds a dependency (rerun pipenv install)
  • Modifies a git hook (rerun ./devsetup.sh)
  • Changes the BasePage
  • Changes or creates a BOM/POM (name the object model): _
  • Changes CI flow
  • Changes scheduled Beta / DevEdition / RC
  • Changes Autofill L10n harness

Screenshots or Explanations

N/A

Comments or Future Work

N/A

Workflow Checklist

  • Reviewers have been requested.
  • Code has been linted and formatted.
  • If this is an unblocker, a message has been posted to #dte-automation in Slack.

Thank you!

@github-actions

Copy link
Copy Markdown
Contributor

Overall the test is well-structured and the new BOM/POM additions follow the existing patterns. A few minor issues to address:

  1. Missing return selfopen_etp_advanced_settings and select_etp_level in page_object_prefs.py don't return self, breaking the fluent interface convention used throughout the codebase.
  2. JSON indentation inconsistencyetp-strict-radio and etp-custom-radio entries in about_prefs.components.json use 6-space indentation instead of the file's standard 4-space.
  3. Trailing slash on TRACKING_URL — the URL ends with a trailing / while TEST_URL does not. This may or may not matter depending on the server, but it's inconsistent and worth normalising.
  4. No input validation in select_etp_level — if an invalid level string is passed (e.g. a typo), click_on will silently fail to find the element. Compare with trustpanel_status which validates its input against a mapping and raises ValueError.

Comment thread modules/page_object_prefs.py
Comment thread modules/data/about_prefs.components.json Outdated
Comment thread tests/security_and_privacy/test_etp_panel_displayed_when_trackers_detected.py Outdated
@github-actions

Copy link
Copy Markdown
Contributor

Overall the test is well-structured and clear. A few issues worth addressing:

Duplicate logic in TrustPanel: detected_category_visible and open_detected_category both compute the same canonical / locator inline. Consider extracting a small private helper (e.g. _category_locator(category)) to keep them DRY.

Missing input validation in select_etp_level: Unlike trustpanel_status (which raises ValueError on bad input), select_etp_level will silently attempt to click a non-existent element like etp-foobar-radio and produce an obscure timeout error. A guard like 'if level not in (standard, strict, custom): raise ValueError(...)' would make failures clearer.

Test appears incomplete for the second page: The test ends at line 78 with trust_panel.detected_category_visible(tracking cookies) with no further assertions. If additional checks were planned for the tracking page (e.g. confirming tracking content is NOT shown as blocked), they appear to be missing.

Comment thread modules/browser_object_trust_panel.py
Comment thread modules/page_object_prefs.py
@github-actions

Copy link
Copy Markdown
Contributor

PR Review: ETP Panel Trackers Detected Test

Overall this is a clean and well-structured test. A few things to address:

Code duplication in browser_object_trust_panel.py

The new detected_category_visible method duplicates the same canonical transformation and locator construction already in open_detected_category. Both methods perform the identical canonical = category.strip().lower().replace(SPACE_DASH) normalization and build the same locator tuple. This logic should be extracted into a private helper method shared by both.

No input validation in select_etp_level

select_etp_level constructs the key etp-{level}-radio dynamically with no guard against invalid inputs. Passing an invalid level silently produces a confusing NoSuchElementException rather than a meaningful ValueError. The docstring already documents the three valid values (standard, strict, custom), so a simple validation guard would greatly improve debuggability.

Missing return type annotation on detected_category_visible

The method returns self but unlike every other method in the class it lacks a return type annotation of BasePage — minor consistency issue.

Comment thread modules/browser_object_trust_panel.py
Comment thread modules/page_object_prefs.py
Comment thread modules/browser_object_trust_panel.py
Comment thread modules/browser_object_trust_panel.py
Comment thread modules/page_object_prefs.py
Comment on lines +4 to +8
from modules.browser_object import TrustPanel
from modules.browser_object_tabbar import TabBar
from modules.page_object import GenericPage
from modules.page_object_prefs import AboutPrefs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent imports: TabBar and AboutPrefs are imported from their direct modules instead of the aggregate modules. Per project convention (CLAUDE.md), imports should come from modules.browser_object and modules.page_object:

Suggested change
from modules.browser_object import TrustPanel
from modules.browser_object_tabbar import TabBar
from modules.page_object import GenericPage
from modules.page_object_prefs import AboutPrefs
from modules.browser_object import TrustPanel, TabBar
from modules.page_object import GenericPage, AboutPrefs


# Tracking content is not blocked and is shown separately under the section "Firefox allowed these things so sites
# don't break:", which includes: "Tracking content"
trust_panel.detected_category_visible("tracking content")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says "Tracking content" is shown under the "allowed" section, but detected_category_visible uses the same detected-category selector as open_detected_category. Since the detected-category JSON selector is moz-button.moz-button-subviewbutton-nav[data-l10n-id='{}'], it's worth confirming this selector targets items in both the blocked and allowed sections — otherwise this assertion may silently pass or fail for the wrong reason.

Comment on lines +298 to +302
canonical = category.strip().lower().replace(" ", "-")
locator = (
"detected-category",
[f"trustpanel-list-label-{canonical}"],
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The normalization and locator-building logic here is identical to what's in open_detected_category (lines ~163-167). Consider extracting a private helper to avoid duplication:

def _category_locator(self, category: str):
    canonical = category.strip().lower().replace(" ", "-")
    return ("detected-category", [f"trustpanel-list-label-{canonical}"])

Then both methods call self._category_locator(category).

def select_etp_level(self, level: str):
"""Clicks the ETP level radio button, accepts 'standard', 'strict' or 'custom'"""
self.click_on(f"etp-{level}-radio")
return self

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No validation on level — an invalid string silently constructs a nonexistent element key (e.g. "etp-typo-radio") and fails with a cryptic element-not-found error. A simple guard helps:

VALID_LEVELS = {"standard", "strict", "custom"}
if level not in VALID_LEVELS:
    raise ValueError(f"Invalid ETP level '{level}'; expected one of {VALID_LEVELS}")

@github-actions

Copy link
Copy Markdown
Contributor

Review Summary

Good addition overall - the test is well-structured and the step comments clearly mirror the TestRail case. A few things to address:

Bugs / Correctness

  • detected_category_visible uses the same detected-category JSON selector for both blocked and allowed items (tracking content). Confirm the underlying selector (moz-button.moz-button-subviewbutton-nav[data-l10n-id]) actually covers the allowed section, otherwise this check may not be testing what it claims.

Code quality

  • select_etp_level has no input validation - a bad level string silently tries to click a nonexistent element. Adding a guard at the top of the method makes failures much clearer. (See inline comment.)
  • The category normalization + locator construction in detected_category_visible is copy-pasted verbatim from open_detected_category. Extracting a _category_locator helper keeps both in sync. (See inline comment.)

Convention

  • TabBar and AboutPrefs are imported from their concrete modules rather than the aggregate modules (browser_object / page_object) as required by project conventions. (See inline comment with suggestion.)

@github-actions

Copy link
Copy Markdown
Contributor

Overall this is a clean, well-structured test addition. A few things to address:

Code duplication in browser_object_trust_panel.py
The new detected_category_visible method duplicates the locator-construction logic already present in open_detected_category. Both methods build the same ("detected-category", [f"trustpanel-list-label-{canonical}"]) tuple. Consider extracting a private _detected_category_locator(category) helper so there's a single source of truth.

Missing input validation in select_etp_level
select_etp_level silently accepts any string; an invalid level like "stric" would fail with an obscure NoSuchElementException. A quick guard at the top (VALID_LEVELS = {"standard", "strict", "custom"}) would make failures obvious and the docstring honest.

Unrelated SELECTOR_INFO.md changes
The diff removes doorhanger-secondary-split-button / doorhanger-more-actions-chevron and adds doorhanger-more-actions-button. These are unrelated to ETP panel tracking and look like a merge artefact — they should either live in a dedicated PR or be confirmed as intentional here.

[f"trustpanel-list-label-{canonical}"],
)

self.element_visible(*locator)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The locator construction here is identical to what's already in open_detected_category. Consider extracting a small helper:

def _detected_category_locator(self, category: str):
    canonical = category.strip().lower().replace(" ", "-")
    return ("detected-category", [f"trustpanel-list-label-{canonical}"])

Then both methods can call self._detected_category_locator(category), eliminating the duplication.

self.click_on("etp-advanced-settings-button")
return self

def select_etp_level(self, level: str):

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No guard against invalid levels. An invalid input will hit the BOM with a nonsense selector and produce an unhelpful NoSuchElementException. Consider:

Suggested change
def select_etp_level(self, level: str):
def select_etp_level(self, level: str):
"""Clicks the ETP level radio button, accepts 'standard', 'strict' or 'custom'"""
valid = {"standard", "strict", "custom"}
if level not in valid:
raise ValueError(f"level must be one of {valid}, got {level!r}")
self.click_on(f"etp-{level}-radio")
return self

@github-actions

Copy link
Copy Markdown
Contributor

Review

The test is well-structured and readable. One critical bug and a few minor issues below.

Critical: component key mismatch in page_object_prefs.py

open_etp_advanced_settings calls click_on("etp-advanced-settings-button") and select_etp_level calls click_on(f"etp-{level}-radio"), but neither of these keys exist in about_prefs.components.json. The file has:

  • "etp-advanced-button" (not etp-advanced-settings-button)
  • "etp-level-standard", "etp-level-strict", "etp-level-custom" (not etp-{level}-radio)

These methods will raise a KeyError or element-not-found at runtime. Either the component JSON needs new entries for these keys, or the method implementations need to use the existing key names.

Minor: code duplication in browser_object_trust_panel.py

detected_category_visible duplicates the exact same canonical normalisation and locator construction already in open_detected_category (lines 224–227). Extract a small helper (e.g. _category_locator) shared by both.

Minor: incomplete second-page assertions

The test ends at line 78 with trust_panel.detected_category_visible("tracking cookies") on the tracking page with no further checks. If additional assertions were planned (e.g. confirming tracking content is absent from the blocked list), they appear to be missing.

Minor: missing return type annotations

detected_category_visible, open_etp_advanced_settings, and select_etp_level all return self but lack the -> BasePage annotation used consistently across the codebase.


def open_etp_advanced_settings(self):
"""Opens the ETP advanced settings in Privacy & Security preferences"""
self.click_on("etp-advanced-settings-button")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: key "etp-advanced-settings-button" does not exist in about_prefs.components.json.

The file only has "etp-advanced-button". This will fail at runtime. Use the correct key or add a new entry to the JSON manifest.

Suggested change
self.click_on("etp-advanced-settings-button")
self.click_on("etp-advanced-button")


def select_etp_level(self, level: str):
"""Clicks the ETP level radio button, accepts 'standard', 'strict' or 'custom'"""
self.click_on(f"etp-{level}-radio")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: keys like "etp-standard-radio" do not exist in about_prefs.components.json.

The existing keys are "etp-level-standard", "etp-level-strict", "etp-level-custom". Use the correct key pattern or add new JSON entries.

Suggested change
self.click_on(f"etp-{level}-radio")
self.click_on(f"etp-level-{level}")


Canonical input format: hyphenated singular (e.g. "tracking-content")
"""
canonical = category.strip().lower().replace(" ", "-")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This canonical normalisation + locator construction is identical to open_detected_category (lines 224–227). Consider extracting a private helper:

def _category_locator(self, category: str) -> tuple:
    canonical = category.strip().lower().replace(" ", "-")
    return ("detected-category", [f"trustpanel-list-label-{canonical}"])

Then both methods call self._category_locator(category) instead of duplicating this logic.

@github-actions

Copy link
Copy Markdown
Contributor

Review Notes

There are two bugs in the AboutPrefs additions that will cause runtime failures, plus a method name collision.

Bug 1: Non-existent element key in open_etp_advanced_settings()

self.click_on("etp-advanced-settings-button") — this key does not exist in about_prefs.components.json. The correct existing key is "etp-advanced-button".

Bug 2: Non-existent element keys in select_etp_level()

self.click_on(f"etp-{level}-radio") generates keys like "etp-standard-radio", "etp-strict-radio", "etp-custom-radio" — none of which are in the JSON manifest. The existing keys are "etp-level-standard", "etp-level-strict", "etp-level-custom".

Bug 3: Method name collision — select_etp_level() is defined twice on AboutPrefs

There is already a select_etp_level(self, level) at line 473 that correctly calls open_etp_settings() then set_etp_level(level) (using the validated ETP_LEVEL_RADIOS dict). The new definition at line 1552 silently overrides it in Python, breaking all existing callers (e.g. test_etp_panel_displayed_when_no_trackers_detected.py, test_trackers_cryptominers_fingerprinters_blocked.py, etc.) that relied on the original behaviour.

The intent of the new methods appears to be handled already by select_etp_level() at line 473 (which itself calls open_etp_settings() to navigate). The new test should either reuse the existing method or the new methods need distinct names and correct element keys.


def open_etp_advanced_settings(self):
"""Opens the ETP advanced settings in Privacy & Security preferences"""
self.click_on("etp-advanced-settings-button")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This key does not exist in about_prefs.components.json. The correct existing key is "etp-advanced-button". As written, this will raise an element-not-found error at runtime.


def select_etp_level(self, level: str):
"""Clicks the ETP level radio button, accepts 'standard', 'strict' or 'custom'"""
self.click_on(f"etp-{level}-radio")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This generates keys like "etp-standard-radio" / "etp-strict-radio" / "etp-custom-radio", none of which exist in about_prefs.components.json. The actual keys are "etp-level-standard", "etp-level-strict", "etp-level-custom". Also, select_etp_level is already defined at line 473 on this same class — Python will silently use this definition and discard the earlier one, breaking all existing callers of that method.

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Review Summary

The test logic and structure look solid. However, the two new helper methods in page_object_prefs.py reference element names that don't match the existing component JSON entries, which will cause runtime failures.

Bug 1 — open_etp_advanced_settings() calls click_on('etp-advanced-settings-button'), but about_prefs.components.json defines the key as etp-advanced-button.

Bug 2 — select_etp_level(level) constructs keys like etp-standard-radio, but the JSON has etp-level-standard, etp-level-strict, etp-level-custom.

Both will raise an element-not-found error before the test exercises any ETP UI.

Minor: The detected_category_visible docstring says canonical input is hyphenated (e.g. tracking-content), but the test passes space-separated strings (tracking cookies). The normalization handles both; the docstring example should just match actual usage.


def open_etp_advanced_settings(self):
"""Opens the ETP advanced settings in Privacy & Security preferences"""
self.click_on("etp-advanced-settings-button")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The element key "etp-advanced-settings-button" does not exist in about_prefs.components.json. The correct key is "etp-advanced-button".

Suggested change
self.click_on("etp-advanced-settings-button")
self.click_on("etp-advanced-button")


def select_etp_level(self, level: str):
"""Clicks the ETP level radio button, accepts 'standard', 'strict' or 'custom'"""
self.click_on(f"etp-{level}-radio")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The constructed keys (etp-standard-radio, etp-strict-radio, etp-custom-radio) don't exist in about_prefs.components.json. The JSON entries follow the pattern etp-level-{level}.

Suggested change
self.click_on(f"etp-{level}-radio")
self.click_on(f"etp-level-{level}")

@BasePage.context_chrome
def detected_category_visible(self, category: str):
"""
Verify a detected tracker category is visible in the protections panel.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docstring example shows hyphenated input ("tracking-content"), but the call sites pass space-separated strings ("tracking cookies", "tracking content"). Consider updating the example to match actual usage, e.g. "tracking cookies".


def open_etp_advanced_settings(self):
"""Opens the ETP advanced settings in Privacy & Security preferences"""
self.click_on("etp-advanced-settings-button")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: the component key "etp-advanced-settings-button" doesn't exist in about_prefs.components.json. The registered key is "etp-advanced-button".

Suggested change
self.click_on("etp-advanced-settings-button")
self.click_on("etp-advanced-button")


def select_etp_level(self, level: str):
"""Clicks the ETP level radio button, accepts 'standard', 'strict' or 'custom'"""
self.click_on(f"etp-{level}-radio")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: f"etp-{level}-radio" generates keys like "etp-standard-radio" which don't exist. The component JSON keys follow the pattern "etp-level-{level}" (e.g. "etp-level-standard", "etp-level-strict", "etp-level-custom").

Suggested change
self.click_on(f"etp-{level}-radio")
self.click_on(f"etp-level-{level}")

from modules.browser_object_tabbar import TabBar
from modules.page_object import GenericPage
from modules.page_object_prefs import AboutPrefs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per project convention (CLAUDE.md), imports should come from the aggregate module, not individual files. TabBar is already exported by modules.browser_object.

Suggested change
from modules.browser_object import TabBar, TrustPanel

(and remove the TrustPanel import on line 7)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant