diff --git a/SELECTOR_INFO.md b/SELECTOR_INFO.md index 8c1a0aeeb..f6584ad49 100644 --- a/SELECTOR_INFO.md +++ b/SELECTOR_INFO.md @@ -1902,6 +1902,20 @@ Location: Context menu - Tab Path to .json: modules/data/context_menu.components.json ``` ``` +Selector Name: context-menu-move-tab-to-end +Selector Data: menuitem[data-l10n-id='move-to-end'] +Description: Context menu option to move a tab to the end of the tab bar. +Location: Context menu - Tab +Path to .json: modules/data/context_menu.components.json +``` +``` +Selector Name: context-menu-move-to-new-window +Selector Data: menuitem[data-l10n-id='move-to-new-window'] +Description: Context menu option to move a tab to a new window. +Location: Context menu - Tab +Path to .json: modules/data/context_menu.components.json +``` +``` Selector Name: context-menu-bookmark-link Selector Data: context-bookmarklink Description: Context menu option to bookmark a link @@ -1913,7 +1927,6 @@ Selector Name: context-menu-search-select Selector Data: coontext-searchselect Description: Context menu option to search selected text with the engine set as default Location: Context menu - topsite context menu -Path to .json: modules/data/context_menu.components.json ``` ``` Selector Name: context-menu-open-link-in-new_container_tab @@ -3284,14 +3297,14 @@ Path to .json: modules/data/navigation.components.json Selector Name: selected_searchbar-search-engine Selector Data: button.searchbar-engine-one-off-item[tooltiptext='{engine}'][selected] Description: Searchbar-search-engine -Location: Selected search bar search engine +Location: Selected search bar search engine Path to .json: modules/data/navigation.components.json ``` ``` Selector Name: searchbar-suggestions Selector Data: hbox.search-one-offs Description: Searchbar suggestions -Location: Searchbar results +Location: Searchbar results Path to .json: modules/data/navigation.components.json ``` ``` diff --git a/manifests/key.yaml b/manifests/key.yaml index 74e033fc6..f8fd83a2f 100644 --- a/manifests/key.yaml +++ b/manifests/key.yaml @@ -36,14 +36,14 @@ address_bar_and_search: result: pass splits: - functional1 - test_copied_url_contains_https: + test_clipboard_pref_flip: result: pass splits: - functional1 - test_clipboard_pref_flip: + test_copied_url_contains_https: result: pass splits: - - functional1 + - functional1 test_ctrl_enter_completes_link_and_can_refresh: result: pass splits: @@ -1084,6 +1084,10 @@ tabs: result: pass splits: - smoke + test_move_multi_selected_tabs: + result: pass + splits: + - functional1 test_mute_tabs: result: linux: pass diff --git a/modules/data/context_menu.components.json b/modules/data/context_menu.components.json index 74c2b05ce..cd4a94bdb 100644 --- a/modules/data/context_menu.components.json +++ b/modules/data/context_menu.components.json @@ -115,6 +115,19 @@ "groups": [] }, + "context-menu-move-tab-to-end": { + "selectorData": "menuitem[data-l10n-id='move-to-end']", + "strategy": "css", + "groups": [] + }, + + "context-menu-move-to-new-window": { + "selectorData": "menuitem[data-l10n-id='move-to-new-window']", + "strategy": "css", + "groups": [] + }, + + "context-menu-open-link-in-tab": { "selectorData": "context-openlinkintab", "strategy": "id", diff --git a/tests/password_manager/test_auto_saved_generated_password_context_menu.py b/tests/password_manager/test_auto_saved_generated_password_context_menu.py index f1a6a17b7..09ce358ff 100644 --- a/tests/password_manager/test_auto_saved_generated_password_context_menu.py +++ b/tests/password_manager/test_auto_saved_generated_password_context_menu.py @@ -19,6 +19,7 @@ def add_to_prefs_list(): return [("signon.rememberSignons", True)] +@pytest.mark.unstable(reason="Bug 1996838") def test_auto_saved_generated_password_context_menu(driver: Firefox): """ C2248176 - Securely Generated Password is auto-saved when generated from password field context menu diff --git a/tests/tabs/test_move_multi_selected_tabs.py b/tests/tabs/test_move_multi_selected_tabs.py new file mode 100644 index 000000000..e26f5d733 --- /dev/null +++ b/tests/tabs/test_move_multi_selected_tabs.py @@ -0,0 +1,117 @@ +import pytest +from selenium.webdriver import Firefox + +from modules.browser_object import ContextMenu, TabBar + +# Title Constants +EXPECTED_ROBOT_TITLE = "Gort!" +EXPECTED_WELCOME_TITLE = "Welcome" + +# Move options +MOVE_TO_END = "context-menu-move-tab-to-end" +MOVE_TO_START = "context-menu-move-tab-to-start" +MOVE_TO_NEW_WINDOW = "context-menu-move-to-new-window" + +# Tab Positions (4 tabs in total) +FIRST_TAB_POSITION = 0 +SECOND_TAB_POSITION = 1 +THIRD_TAB_POSITION = 2 +LAST_TAB_POSITION = 3 + + +@pytest.fixture() +def test_case(): + return "246989" + + +@pytest.mark.parametrize( + "move_option,expected_titles,expected_positions", + [ + ( + MOVE_TO_END, + (EXPECTED_ROBOT_TITLE, EXPECTED_WELCOME_TITLE), + (THIRD_TAB_POSITION, LAST_TAB_POSITION), + ), + ( + MOVE_TO_START, + (EXPECTED_ROBOT_TITLE, EXPECTED_WELCOME_TITLE), + (FIRST_TAB_POSITION, SECOND_TAB_POSITION), + ), + ( + MOVE_TO_NEW_WINDOW, + None, + None, + ), + ], +) +def test_move_multi_selected_tabs( + driver: Firefox, sys_platform: str, move_option, expected_titles, expected_positions +): + """Test all tab movement operations in separate test runs""" + tab_movements( + driver, sys_platform, move_option, expected_titles, expected_positions + ) + + +def tab_movements( + driver: Firefox, sys_platform: str, move_option, expected_titles, expected_positions +): + tabs = TabBar(driver) + tab_context_menu = ContextMenu(driver) + + tab_titles = [] + url_list = ["about:logo", "about:robots", "about:welcome", "https://mozilla.org"] + + # Open 4 tabs + driver.get(url_list[0]) + tab_titles.append(driver.title) + + for i in range(1, len(url_list)): + tabs.new_tab_by_button() + driver.switch_to.window(driver.window_handles[-1]) + driver.get(url_list[i]) + tab_titles.append(driver.title) + + # Specific tabs we want to move + selected_tab_indices = [2, 3] # Here indices start from 1 + selected_tabs = tabs.select_multiple_tabs_by_indices( + selected_tab_indices, sys_platform + ) + + if move_option == MOVE_TO_NEW_WINDOW: + tabs.context_click(selected_tabs[1]) + tab_context_menu.click_and_hide_menu(move_option) + tabs.hide_popup("tabContextMenu") + + driver.switch_to.window(driver.window_handles[-1]) + new_window_tab_title = driver.title + + assert EXPECTED_ROBOT_TITLE in new_window_tab_title, ( + "Robot should now be a new window" + ) + + elif move_option in (MOVE_TO_END, MOVE_TO_START): + assert expected_positions is not None + assert expected_titles is not None + + # Move-to-end/start + tabs.context_click(selected_tabs[1]) + tab_context_menu.click_and_hide_menu(move_option) + tabs.hide_popup("tabContextMenu") + + # Verify for move-to-end/move-to-start + + for expected_title, expected_position in zip( + expected_titles, expected_positions + ): + # Switch to the window handle at the expected index + # NOTE: driver.window_handles are the HANDLES, the index is the order they APPEAR + driver.switch_to.window(driver.window_handles[expected_position]) + + actual_title = driver.title + + # Assert the title is correct + assert expected_title in actual_title, ( + f"Verification failed for tab at index {expected_position}: " + f"Expected title '{expected_title}' but found '{actual_title}'." + )