Skip to content

Commit ae4b6e5

Browse files
authored
Anca/ Add Topsites context menu (#853)
* Add 3029116 * method changes, added dynamic elements * Removed unnecessary code, provide selector info * Fix typo
1 parent 3b86cf0 commit ae4b6e5

File tree

8 files changed

+198
-6
lines changed

8 files changed

+198
-6
lines changed

SELECTOR_INFO.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,14 @@ Description: The Firefox logo
443443
Location: The about:newtab page
444444
Path to .json: modules/data/about_newtab.components.json
445445
```
446+
```
447+
Selector Name: top-site-by-title
448+
Selector Data: "//li[@class='top-site-outer']//span[@class='title-label' and text()='{title}']/.."
449+
Description: Topsite tile by title
450+
Location: The about:newtab page (middle section)
451+
Path to .json: modules/data/about_newtab.components.json
452+
```
453+
446454
#### about_prefs
447455
```
448456
Selector Name: search-engine-dropdown-root
@@ -1837,6 +1845,20 @@ Description: Context menu option to move a tab to the start of the tab bar.
18371845
Location: Context menu - Tab
18381846
Path to .json: modules/data/context_menu.components.json
18391847
```
1848+
```
1849+
Selector Name: context-menu-bookmark-link
1850+
Selector Data: context-bookmarklink
1851+
Description: Context menu option to bookmark a link
1852+
Location: Context menu - topsite context menu
1853+
Path to .json: modules/data/context_menu.components.json
1854+
```
1855+
```
1856+
Selector Name: context-menu-search-select
1857+
Selector Data: coontext-searchselect
1858+
Description: Context menu option to search selected text with the engine set as default
1859+
Location: Context menu - topsite context menu
1860+
Path to .json: modules/data/context_menu.components.json
1861+
```
18401862
#### credit_card_fill
18411863
```
18421864
Selector Name: form-field
@@ -3139,6 +3161,13 @@ Description: Developer tool icon
31393161
Location: Navigation bar
31403162
Path to .json: modules/data/navigation.components.json
31413163
```
3164+
```
3165+
Selector Name: status-panel-label
3166+
Selector Data: statuspanel-label
3167+
Description: Status panel URL label
3168+
Location: newtab page bottom left corner on link hover
3169+
Path to .json: modules/data/navigation.components.json
3170+
```
31423171
#### panel_ui
31433172
```
31443173
Selector name: panel-ui-button
@@ -3516,7 +3545,7 @@ Description: Edit bookmark panel
35163545
Location: Bookmark panel
35173546
Path to .json: modules/data/pane_ui.components.json
35183547
```
3519-
```
3548+
35203549
#### print_preview
35213550
```
35223551
Selector name: print-preview-browser

modules/browser_object_context_menu.py

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import logging
2-
from typing import Union
2+
from typing import Dict, List, Union
33

44
from selenium.webdriver.remote.webelement import WebElement
55

@@ -13,15 +13,51 @@ class ContextMenu(BasePage):
1313

1414
URL_TEMPLATE = ""
1515

16+
@BasePage.context_chrome
1617
def click_context_item(
1718
self, reference: Union[str, tuple, WebElement], labels=[]
1819
) -> BasePage:
1920
"""
2021
Clicks the context item.
2122
"""
22-
with self.driver.context(self.driver.CONTEXT_CHROME):
23-
self.fetch(reference, labels=labels).click()
24-
return self
23+
24+
self.fetch(reference, labels=labels).click()
25+
return self
26+
27+
@BasePage.context_chrome
28+
def verify_topsites_tile_context_menu_options(
29+
self,
30+
static_items: Dict[str, str],
31+
dynamic_items: List[str],
32+
tile_title: str,
33+
):
34+
"""
35+
Verifies expected context menu options are present upon right clicking a topsite tile.
36+
Arguments:
37+
static_items: Dict mapping of selector name to expected label text.
38+
dynamic_items: List of selector names for items with dynamic labels.
39+
tile_title: Optional, required if dynamic label validation is needed (e.g., Wikipedia, YouTube).
40+
"""
41+
# --- Static items ---
42+
for selector, expected_label in static_items.items():
43+
option = self.get_element(selector)
44+
label = (option.get_attribute("label") or option.text or "").strip()
45+
assert expected_label in label, (
46+
f'Expected label "{expected_label}" not found. Got: "{label}"'
47+
)
48+
49+
# --- Dynamic items ---
50+
for selector in dynamic_items:
51+
option = self.get_element(selector)
52+
label = (option.get_attribute("label") or option.text or "").strip()
53+
normalized = label.lower()
54+
assert normalized.startswith("search"), (
55+
f'Label does not start with "Search": "{label}"'
56+
)
57+
assert "for" in normalized, f'"for" not found in label: "{label}"'
58+
assert tile_title.lower() in normalized, (
59+
f'Search term "{tile_title}" not found in label: "{label}"'
60+
)
2561

2662

2763
class AboutDownloadsContextMenu(ContextMenu):

modules/browser_object_navigation.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,3 +805,24 @@ def verify_autoplay_state(self, expected: Literal["allow", "block"]) -> None:
805805
else:
806806
self.element_visible("permission-popup-audio-video-blocked")
807807
self.element_visible("autoplay-icon-blocked")
808+
809+
@BasePage.context_chrome
810+
def get_status_panel_url(self) -> str:
811+
"""
812+
Gets the URL displayed in the status panel at the bottom left of the browser.
813+
"""
814+
self.element_visible("status-panel-label")
815+
status_label = self.get_element("status-panel-label")
816+
url = status_label.get_attribute("value")
817+
return url
818+
819+
def verify_status_panel_url(self, expected_url: str):
820+
"""
821+
Verify that the browser status panel (browser's bottom-left) contains the expected URL.
822+
Argument:
823+
expected_url: The expected URL substring to be found in the status panel
824+
"""
825+
actual_url = self.get_status_panel_url()
826+
assert expected_url in actual_url, (
827+
f"Expected '{expected_url}' in status panel URL, got '{actual_url}'"
828+
)

modules/data/about_newtab.components.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,5 +89,11 @@
8989
"selectorData": "logo",
9090
"strategy": "class",
9191
"groups": []
92-
}
92+
},
93+
94+
"top-site-by-title": {
95+
"selectorData": "//li[@class='top-site-outer']//span[@class='title-label' and text()='{title}']/..",
96+
"strategy": "xpath",
97+
"groups": []
98+
}
9399
}

modules/data/context_menu.components.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,5 +221,18 @@
221221
"selectorData": "placesContext_openBookmarkContainer:tabs",
222222
"strategy": "id",
223223
"groups": []
224+
},
225+
226+
"context-menu-bookmark-link": {
227+
"selectorData": "context-bookmarklink",
228+
"strategy": "id",
229+
"groups": []
230+
},
231+
232+
"context-menu-search-select": {
233+
"selectorData": "context-searchselect",
234+
"strategy": "id",
235+
"groups": []
224236
}
237+
225238
}

modules/data/navigation.components.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,5 +603,11 @@
603603
"selectorData": "developer-button",
604604
"strategy": "id",
605605
"groups": []
606+
},
607+
608+
"status-panel-label": {
609+
"selectorData": "statuspanel-label",
610+
"strategy": "id",
611+
"groups": []
606612
}
607613
}

modules/page_object_newtab.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,20 @@ def check_layout(self) -> BasePage:
132132
logging.info(f"Found {self.count_top_sites()} top sites")
133133
# ODD: Sometimes we get 7 top sites, not 8
134134
assert self.count_top_sites() in self.TOP_SITES_TOTAL
135+
136+
@BasePage.context_content
137+
def get_topsite_element(self, tile_title: str):
138+
"""Get a topsite tile element by title."""
139+
return self.get_element("top-site-by-title", labels=[tile_title])
140+
141+
@BasePage.context_content
142+
def open_topsite_context_menu_by_title(self, tile_title: str):
143+
"""
144+
Opens the context menu for a topsite tile by its title.
145+
Argument:
146+
tile_title: The title text of the tile (eg. "Wikipedia")
147+
"""
148+
# Get the tile by title and right-click on it to open context menu
149+
tile = self.get_topsite_element(tile_title)
150+
self.context_click(tile)
151+
return self
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import pytest
2+
from selenium.webdriver import Firefox
3+
4+
from modules.browser_object_context_menu import ContextMenu
5+
from modules.browser_object_navigation import Navigation
6+
from modules.browser_object_tabbar import TabBar
7+
from modules.page_object_generics import GenericPage
8+
from modules.page_object_newtab import AboutNewtab
9+
10+
11+
@pytest.fixture()
12+
def test_case():
13+
return "3029116"
14+
15+
16+
STATIC_CONTEXT_MENU_OPTIONS = {
17+
"context-menu-open-link-in-tab": "Open Link in New Tab",
18+
"context-menu-open-link-in-new-window": "Open Link in New Window",
19+
"context-menu-open-link-in-new-private-window": "Open Link in New Private Window",
20+
"context-menu-bookmark-link": "Bookmark Link",
21+
"context-menu-save-link": "Save Link As",
22+
"context-menu-copy-link": "Copy Link",
23+
"context-menu-inspect": "Inspect",
24+
}
25+
26+
DYNAMIC_CONTEXT_MENU_ITEMS = ["context-menu-search-select"]
27+
28+
TOPSITE_TITLE = "Wikipedia"
29+
TOPSITE_URL = "www.wikipedia.org"
30+
31+
32+
def test_non_sponsored_topsite_context_menu_option(driver: Firefox) -> None:
33+
"""
34+
C3029116 - Verifies that the browser's context menu displays the expected options
35+
when right-clicking a top site tile, and that the opened link matches the
36+
status panel URL shown on hover.
37+
"""
38+
tabs = TabBar(driver)
39+
newtab = AboutNewtab(driver)
40+
context_menu = ContextMenu(driver)
41+
nav = Navigation(driver)
42+
page = GenericPage(driver, url="about:newtab")
43+
44+
# Open about:newtab and hover over the desired TOPSITE_TITLE tile and verify status panel URL (bottom-left)
45+
page.open()
46+
title_element = newtab.get_topsite_element(TOPSITE_TITLE)
47+
newtab.hover(title_element)
48+
nav.verify_status_panel_url(TOPSITE_URL)
49+
status_panel_url = nav.get_status_panel_url()
50+
51+
# Right-click to open context menu
52+
newtab.open_topsite_context_menu_by_title(TOPSITE_TITLE)
53+
54+
# Verify context menu options
55+
context_menu.verify_topsites_tile_context_menu_options(
56+
STATIC_CONTEXT_MENU_OPTIONS,
57+
DYNAMIC_CONTEXT_MENU_ITEMS,
58+
TOPSITE_TITLE,
59+
)
60+
61+
# Click first option and verify link opens in new tab
62+
context_menu.click_context_item("context-menu-open-link-in-tab")
63+
tabs.switch_to_new_tab()
64+
nav.url_contains(status_panel_url)

0 commit comments

Comments
 (0)