Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

/* Any copyright is dedicated to the Public Domain.
"use strict";
// Tests that parent navigation buttons stay selected when on sub-panes,
// enabling keyboard navigation from sub-panes (Bug 2038759).
/**
* Helper to get a nav button by its view attribute.
*/
function getNavButton(doc, viewName) {
return doc.querySelector(`moz-page-nav-button[view="${viewName}"]`);
}
/**
* Helper to assert that a nav button is selected and focusable.
*/
function assertNavButtonSelected(button, message) {
ok(button, "Nav button exists");
ok(button.selected, `${message} - button has selected attribute`);
is(
button.buttonEl.getAttribute("tabindex"),
"0",
`${message} - button is focusable`
);
}
// Test that parent nav buttons stay selected for various sub-pane scenarios.
add_task(async function test_parent_nav_selected_for_subpanes() {
// Test single-level sub-pane: etp parent is privacy
await openPreferencesViaOpenPreferencesAPI("etp", { leaveOpen: true });
let doc = gBrowser.contentDocument;
let categories = doc.getElementById("categories");
let privacyButton = getNavButton(doc, "panePrivacy");
is(
categories.currentView,
"panePrivacy",
"Privacy nav button selected when on ETP sub-pane"
);
assertNavButtonSelected(privacyButton, "ETP sub-pane");
// Test nested sub-pane: etpCustomize → etp → privacy (should select privacy root)
let paneChangePromise = waitForPaneChange("etpCustomize");
doc.location.hash = "etpCustomize";
await paneChangePromise;
is(
categories.currentView,
"panePrivacy",
"Privacy nav button selected for nested sub-pane (etpCustomize)"
);
assertNavButtonSelected(privacyButton, "Nested sub-pane");
// Test different sub-pane: customHomepage parent is home
let homeButton = getNavButton(doc, "paneHome");
let win = gBrowser.contentWindow;
paneChangePromise = waitForPaneChange("home");
EventUtils.synthesizeMouseAtCenter(homeButton.buttonEl, {}, win);
await paneChangePromise;
is(
categories.currentView,
"paneHome",
"Home nav button selected for customHomepage sub-pane"
);
assertNavButtonSelected(homeButton, "customHomepage sub-pane");
// Test top-level pane without parent (regression test)
paneChangePromise = waitForPaneChange("privacy");
EventUtils.synthesizeMouseAtCenter(privacyButton.buttonEl, {}, win);
await paneChangePromise;
is(
categories.currentView,
"panePrivacy",
"Privacy nav button selected for privacy pane itself"
);
assertNavButtonSelected(privacyButton, "Top-level pane");
BrowserTestUtils.removeTab(gBrowser.selectedTab);
});
// Test that direct URL navigation to a sub-pane selects the parent button.
add_task(async function test_direct_url_navigation_to_subpane() {
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
"about:preferences#etp"
);
let doc = tab.linkedBrowser.contentDocument;
await BrowserTestUtils.waitForMutationCondition(
doc.body,
{ childList: true, subtree: true },
() => doc.getElementById("categories")
);
let categories = doc.getElementById("categories");
let privacyButton = getNavButton(doc, "panePrivacy");
is(
categories.currentView,
"panePrivacy",
"Privacy nav button selected with direct #etp URL navigation"
);
assertNavButtonSelected(privacyButton, "Direct URL navigation");
BrowserTestUtils.removeTab(tab);
});
// Test that arrow key navigation works when focused on parent nav button while viewing sub-pane.
add_task(async function test_arrow_key_navigation_from_subpane() {
await openPreferencesViaOpenPreferencesAPI("etp", { leaveOpen: true });
let doc = gBrowser.contentDocument;
let win = gBrowser.contentWindow;
let privacyButton = getNavButton(doc, "panePrivacy");
let searchButton = getNavButton(doc, "paneSearch");
// Focus the selected Privacy button (currently selected because we're on ETP sub-pane)
privacyButton.buttonEl.focus();
is(doc.activeElement, privacyButton, "Privacy nav button is focused");
// Press ArrowUp to navigate to Search pane
let paneChangePromise = waitForPaneChange("search");
EventUtils.synthesizeKey("KEY_ArrowUp", {}, win);
await paneChangePromise;
// Verify Search button is now selected and we navigated to Search pane
ok(searchButton.selected, "Search button selected after arrow up");
is(win.history.state, "paneSearch", "Navigated to Search pane");
BrowserTestUtils.removeTab(gBrowser.selectedTab);
});
// Test that back button from sub-pane maintains correct parent selection.
add_task(async function test_back_button_from_subpane() {
// Start on privacy (top-level pane)
await openPreferencesViaOpenPreferencesAPI("privacy", { leaveOpen: true });
let doc = gBrowser.contentDocument;
let win = gBrowser.contentWindow;
let categories = doc.getElementById("categories");
is(
categories.currentView,
"panePrivacy",
"Privacy selected for privacy pane"
);
// Navigate to ETP sub-pane
let paneChangePromise = waitForPaneChange("etp");
win.gotoPref("paneEtp");
await paneChangePromise;
// Privacy button should still be selected
is(
categories.currentView,
"panePrivacy",
"Privacy selected when navigating to ETP"
);
// Wait for ETP pane to fully load
await BrowserTestUtils.waitForMutationCondition(
doc.getElementById("mainPrefPane"),
{ childList: true, subtree: true },
() => doc.querySelector('setting-pane[data-category="paneEtp"]')
);
let etpPane = doc.querySelector('setting-pane[data-category="paneEtp"]');
await etpPane.updateComplete;
// Click back button
let backButton = etpPane.pageHeaderEl.backButtonEl;
ok(backButton, "Back button exists on ETP pane");
ok(BrowserTestUtils.isVisible(backButton), "Back button is visible");
paneChangePromise = waitForPaneChange("privacy");
EventUtils.synthesizeMouseAtCenter(backButton, {}, win);
await paneChangePromise;
// Verify we're back on main privacy pane and it's still selected
is(
categories.currentView,
"panePrivacy",
"Privacy still selected after clicking back button"
);
is(win.history.state, "panePrivacy", "Navigated back to privacy pane");
BrowserTestUtils.removeTab(gBrowser.selectedTab);
});