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
This commit is contained in:
Julian Descottes 2024-01-04 15:14:30 +00:00
parent 16fab22608
commit 9c509b8feb
7 changed files with 171 additions and 46 deletions

View file

@ -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 {

View file

@ -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"]

View file

@ -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";

View file

@ -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,
};
}

View file

@ -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);
});

View file

@ -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,
};
}

View file

@ -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 */