From 9c509b8feb28c1e76ad41e65bf9fd87ef672b00f Mon Sep 17 00:00:00 2001 From: Julian Descottes Date: Thu, 4 Jan 2024 15:14:30 +0000 Subject: [PATCH] Bug 1872245 - [devtools] Sort worker and extension targets alphabetically in about:debugging r=devtools-reviewers,ochameau The debug targets are currently displayed in the order from the server, which makes it hard to find specific targets. Differential Revision: https://phabricator.services.mozilla.com/D197521 --- .../src/actions/debug-targets.js | 19 ++- .../aboutdebugging/test/browser/browser.toml | 2 + ...ser_aboutdebugging_addons_debug_console.js | 2 +- .../browser_aboutdebugging_hidden_addons.js | 40 ------- .../browser_aboutdebugging_targets_sorted.js | 111 ++++++++++++++++++ .../aboutdebugging/test/browser/head.js | 21 ++++ .../test/browser/helper-mocks.js | 22 ++++ 7 files changed, 171 insertions(+), 46 deletions(-) create mode 100644 devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_targets_sorted.js diff --git a/devtools/client/aboutdebugging/src/actions/debug-targets.js b/devtools/client/aboutdebugging/src/actions/debug-targets.js index 33b2f1cbeac8..9ac3bee3b525 100644 --- a/devtools/client/aboutdebugging/src/actions/debug-targets.js +++ b/devtools/client/aboutdebugging/src/actions/debug-targets.js @@ -258,8 +258,8 @@ function requestExtensions() { dispatch({ type: REQUEST_EXTENSIONS_SUCCESS, - installedExtensions, - temporaryExtensions, + installedExtensions: sortTargetsByName(installedExtensions), + temporaryExtensions: sortTargetsByName(temporaryExtensions), }); } catch (e) { dispatch({ type: REQUEST_EXTENSIONS_FAILURE, error: e }); @@ -310,9 +310,9 @@ function requestWorkers() { dispatch({ type: REQUEST_WORKERS_SUCCESS, - otherWorkers, - serviceWorkers, - sharedWorkers, + otherWorkers: sortTargetsByName(otherWorkers), + serviceWorkers: sortTargetsByName(serviceWorkers), + sharedWorkers: sortTargetsByName(sharedWorkers), }); } catch (e) { dispatch({ type: REQUEST_WORKERS_FAILURE, error: e }); @@ -330,6 +330,15 @@ function startServiceWorker(registrationFront) { }; } +function sortTargetsByName(targets) { + return targets.sort((target1, target2) => { + // Fallback to empty string in case some targets don't have a valid name. + const name1 = target1.name || ""; + const name2 = target2.name || ""; + return name1.localeCompare(name2); + }); +} + function unregisterServiceWorker(registrationFront) { return async () => { try { diff --git a/devtools/client/aboutdebugging/test/browser/browser.toml b/devtools/client/aboutdebugging/test/browser/browser.toml index 0d34b92cf4b2..3ca2569b1c84 100644 --- a/devtools/client/aboutdebugging/test/browser/browser.toml +++ b/devtools/client/aboutdebugging/test/browser/browser.toml @@ -243,6 +243,8 @@ skip-if = ["a11y_checks"] # Bug 1849028 and 1849179 for causing crashes ["browser_aboutdebugging_tab_zombietab.js"] +["browser_aboutdebugging_targets_sorted.js"] + ["browser_aboutdebugging_telemetry_basic.js"] ["browser_aboutdebugging_telemetry_connection_attempt.js"] diff --git a/devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_addons_debug_console.js b/devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_addons_debug_console.js index 1ed16dd1b0af..1612cd545f84 100644 --- a/devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_addons_debug_console.js +++ b/devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_addons_debug_console.js @@ -16,7 +16,7 @@ PromiseTestUtils.allowMatchingRejectionsGlobally(/File closed/); requestLongerTimeout(2); const ADDON_ID = "test-devtools-webextension@mozilla.org"; -const ADDON_NAME = "test-devtools-webextension"; +const ADDON_NAME = "base-test-devtools-webextension"; const OTHER_ADDON_ID = "other-test-devtools-webextension@mozilla.org"; const OTHER_ADDON_NAME = "other-test-devtools-webextension"; diff --git a/devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_hidden_addons.js b/devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_hidden_addons.js index 69f75ef75e55..5d28752c9325 100644 --- a/devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_hidden_addons.js +++ b/devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_hidden_addons.js @@ -64,43 +64,3 @@ async function testAddonsDisplay(showHidden) { await removeTab(tab); } - -// Create a basic mock for this-firefox client, and setup a runtime-client-factory mock -// to return our mock client when needed. -function setupThisFirefoxMock() { - const runtimeClientFactoryMock = createRuntimeClientFactoryMock(); - const thisFirefoxClient = createThisFirefoxClientMock(); - runtimeClientFactoryMock.createClientForRuntime = runtime => { - const { - RUNTIMES, - } = require("resource://devtools/client/aboutdebugging/src/constants.js"); - if (runtime.id === RUNTIMES.THIS_FIREFOX) { - return thisFirefoxClient; - } - throw new Error("Unexpected runtime id " + runtime.id); - }; - - info("Enable mocks"); - enableRuntimeClientFactoryMock(runtimeClientFactoryMock); - registerCleanupFunction(() => { - disableRuntimeClientFactoryMock(); - }); - - return thisFirefoxClient; -} - -// Create basic addon data as the DevToolsClient would return it (debuggable and non -// temporary). -function createAddonData({ id, name, isSystem, hidden }) { - return { - actor: `actorid-${id}`, - hidden, - iconURL: `moz-extension://${id}/icon-url.png`, - id, - manifestURL: `moz-extension://${id}/manifest-url.json`, - name, - isSystem, - temporarilyInstalled: false, - debuggable: true, - }; -} diff --git a/devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_targets_sorted.js b/devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_targets_sorted.js new file mode 100644 index 000000000000..4fc9bb87c0a7 --- /dev/null +++ b/devtools/client/aboutdebugging/test/browser/browser_aboutdebugging_targets_sorted.js @@ -0,0 +1,111 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Check that all debug targets except tabs are sorted alphabetically. +add_task(async function () { + const thisFirefoxClient = setupThisFirefoxMock(); + + thisFirefoxClient.listAddons = () => [ + createAddonData({ id: "addon-b", name: "Addon B" }), + createAddonData({ id: "addon-c", name: "Addon C" }), + createAddonData({ id: "addon-a", name: "Addon A" }), + createAddonData({ id: "tmp-b", name: "Temporary B", temporary: true }), + createAddonData({ id: "tmp-c", name: "Temporary C", temporary: true }), + createAddonData({ id: "tmp-a", name: "Temporary A", temporary: true }), + ]; + + thisFirefoxClient.listWorkers = () => { + return { + otherWorkers: [ + { id: "worker-b", name: "Worker B" }, + { id: "worker-c", name: "Worker C" }, + { id: "worker-a", name: "Worker A" }, + ], + sharedWorkers: [ + { id: "shared-worker-b", name: "Shared Worker B" }, + { id: "shared-worker-c", name: "Shared Worker C" }, + { id: "shared-worker-a", name: "Shared Worker A" }, + ], + serviceWorkers: [ + { id: "service-worker-b", name: "Service Worker B" }, + { id: "service-worker-c", name: "Service Worker C" }, + { id: "service-worker-a", name: "Service Worker A" }, + ], + }; + }; + + thisFirefoxClient.listTabs = () => [ + { + browserId: 2, + title: "Tab B", + url: "https://www.b.com", + retrieveFavicon: () => {}, + }, + { + browserId: 3, + title: "Tab C", + url: "https://www.c.com", + retrieveFavicon: () => {}, + }, + { + browserId: 1, + title: "Tab A", + url: "https://www.a.com", + retrieveFavicon: () => {}, + }, + ]; + + const { document, tab, window } = await openAboutDebugging(); + await selectThisFirefoxPage(document, window.AboutDebugging.store); + + function findTargetIndex(name) { + const targets = [...document.querySelectorAll(".qa-debug-target-item")]; + return targets.findIndex(target => target.textContent.includes(name)); + } + + function assertTargetOrder(targetNames, message) { + let isSorted = true; + for (let i = 1; i < targetNames.length; i++) { + const index1 = findTargetIndex(targetNames[i - 1]); + const index2 = findTargetIndex(targetNames[i]); + if (index1 > index2) { + isSorted = false; + info( + `Targets ${targetNames[i - 1]} and ${targetNames[i]} ` + + `are not sorted as expected` + ); + } + } + + ok(isSorted, message); + } + + assertTargetOrder( + ["Tab B", "Tab C", "Tab A"], + "Tabs are sorted as returned by the back-end" + ); + assertTargetOrder( + ["Addon A", "Addon B", "Addon C"], + "Addons are sorted alphabetically" + ); + assertTargetOrder( + ["Temporary A", "Temporary B", "Temporary C"], + "Temporary addons are sorted alphabetically" + ); + assertTargetOrder( + ["Worker A", "Worker B", "Worker C"], + "Workers are sorted alphabetically" + ); + assertTargetOrder( + ["Shared Worker A", "Shared Worker B", "Shared Worker C"], + "Shared workers are sorted alphabetically" + ); + assertTargetOrder( + ["Service Worker A", "Service Worker B", "Service Worker C"], + "Service workers are sorted alphabetically" + ); + + await removeTab(tab); +}); diff --git a/devtools/client/aboutdebugging/test/browser/head.js b/devtools/client/aboutdebugging/test/browser/head.js index 3c32e0b87b9d..c1b509b97c22 100644 --- a/devtools/client/aboutdebugging/test/browser/head.js +++ b/devtools/client/aboutdebugging/test/browser/head.js @@ -503,3 +503,24 @@ function clickOnAddonWidget(addonId) { info("Show the web extension popup"); browserActionEl.firstElementChild.click(); } + +// Create basic addon data as the DevToolsClient would return it. +function createAddonData({ + id, + name, + isSystem = false, + hidden = false, + temporary = false, +}) { + return { + actor: `actorid-${id}`, + hidden, + iconURL: `moz-extension://${id}/icon-url.png`, + id, + manifestURL: `moz-extension://${id}/manifest-url.json`, + name, + isSystem, + temporarilyInstalled: temporary, + debuggable: true, + }; +} diff --git a/devtools/client/aboutdebugging/test/browser/helper-mocks.js b/devtools/client/aboutdebugging/test/browser/helper-mocks.js index 76fc414ae8e6..b1c9c910ff50 100644 --- a/devtools/client/aboutdebugging/test/browser/helper-mocks.js +++ b/devtools/client/aboutdebugging/test/browser/helper-mocks.js @@ -260,3 +260,25 @@ async function createLocalClientWrapper() { return new ClientWrapper(client); } /* exported createLocalClientWrapper */ + +// Create a basic mock for this-firefox client, and setup a runtime-client-factory mock +// to return our mock client when needed. +function setupThisFirefoxMock() { + const runtimeClientFactoryMock = createRuntimeClientFactoryMock(); + const thisFirefoxClient = createThisFirefoxClientMock(); + runtimeClientFactoryMock.createClientForRuntime = runtime => { + if (runtime.id === RUNTIMES.THIS_FIREFOX) { + return thisFirefoxClient; + } + throw new Error("Unexpected runtime id " + runtime.id); + }; + + info("Enable mocks"); + enableRuntimeClientFactoryMock(runtimeClientFactoryMock); + registerCleanupFunction(() => { + disableRuntimeClientFactoryMock(); + }); + + return thisFirefoxClient; +} +/* exported setupThisFirefoxMock */