Bug 1959716 - Support groupId in tabs.onUpdated (desktop only) r=zombie,dao

Note: only implemented in desktop Firefox. On mobile, the tab groups
feature does not exist, so tabs.onUpdated would never fire. The
mobile-specific tabs.json schema does not declare "properties" filter
either, so there is no place to list the "groupId" filter either.

Differential Revision: https://phabricator.services.mozilla.com/D245264
This commit is contained in:
Rob Wu
2025-04-11 23:07:16 +00:00
parent 3e9aa82468
commit d1ae025d4a
4 changed files with 126 additions and 0 deletions

View File

@@ -160,6 +160,7 @@ const allProperties = new Set([
"autoDiscardable",
"discarded",
"favIconUrl",
"groupId",
"hidden",
"isArticle",
"mutedInfo",
@@ -465,6 +466,15 @@ this.tabs = class extends ExtensionAPIPersistent {
needed.push("discarded");
} else if (event.type == "TabBrowserDiscarded") {
needed.push("discarded");
} else if (event.type === "TabGrouped") {
needed.push("groupId");
} else if (event.type === "TabUngrouped") {
if (event.originalTarget.group) {
// If there is still a group, that means that the group changed,
// so TabGrouped will also fire. Ignore to avoid duplicate events.
return;
}
needed.push("groupId");
} else if (event.type == "TabShow") {
needed.push("hidden");
} else if (event.type == "TabHide") {
@@ -531,6 +541,10 @@ this.tabs = class extends ExtensionAPIPersistent {
listeners.set("TabBrowserInserted", listener);
listeners.set("TabBrowserDiscarded", listener);
}
if (filter.properties.has("groupId")) {
listeners.set("TabGrouped", listener);
listeners.set("TabUngrouped", listener);
}
if (filter.properties.has("hidden")) {
listeners.set("TabShow", listener);
listeners.set("TabHide", listener);

View File

@@ -435,6 +435,7 @@
"autoDiscardable",
"discarded",
"favIconUrl",
"groupId",
"hidden",
"isArticle",
"mutedInfo",

View File

@@ -583,6 +583,8 @@ skip-if = [
["browser_ext_tabs_onUpdated_filter.js"]
["browser_ext_tabs_onUpdated_groupId.js"]
["browser_ext_tabs_opener.js"]
["browser_ext_tabs_printPreview.js"]

View File

@@ -0,0 +1,109 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
add_task(async function onUpdated_when_grouping_and_ungrouping() {
const extension = ExtensionTestUtils.loadExtension({
async background() {
const changes = [];
browser.tabs.onUpdated.addListener(
(tabId, changeInfo, tab) => {
browser.test.assertEq(
changeInfo.groupId,
tab.groupId,
"changeInfo.groupId matches tab.groupId"
);
changes.push(changeInfo);
},
{ properties: ["groupId"] }
);
const { id: tabId } = await browser.tabs.create({});
const groupId1 = await browser.tabs.group({ tabIds: [tabId] });
await browser.tabs.ungroup(tabId);
const groupId2 = await browser.tabs.group({ tabIds: [tabId] });
await browser.tabs.remove(tabId);
browser.test.assertDeepEq(
[{ groupId: groupId1 }, { groupId: -1 }, { groupId: groupId2 }],
changes,
"Observed tabs.onUpdated events after group(), ungroup() and group()"
);
browser.test.sendMessage("done");
},
});
await extension.startup();
await extension.awaitMessage("done");
await extension.unload();
});
add_task(async function onUpdated_when_grouping_and_regrouping() {
const extension = ExtensionTestUtils.loadExtension({
async background() {
const changes = [];
browser.tabs.onUpdated.addListener(
(tabId, changeInfo, tab) => {
browser.test.assertEq(
changeInfo.groupId,
tab.groupId,
"changeInfo.groupId matches tab.groupId"
);
changes.push(changeInfo);
},
{ properties: ["groupId"] }
);
const { id: tabId } = await browser.tabs.create({});
const groupId1 = await browser.tabs.group({ tabIds: [tabId] });
const groupId2 = await browser.tabs.group({ tabIds: [tabId] });
const groupId3 = await browser.tabs.group({ tabIds: [tabId] });
await browser.tabs.remove(tabId);
browser.test.assertDeepEq(
[{ groupId: groupId1 }, { groupId: groupId2 }, { groupId: groupId3 }],
changes,
"Observed tabs.onUpdated events after group() and regrouping repeatedly"
);
browser.test.sendMessage("done");
},
});
await extension.startup();
await extension.awaitMessage("done");
await extension.unload();
});
add_task(async function onUpdated_when_grouping_pinned_tab() {
const extension = ExtensionTestUtils.loadExtension({
async background() {
const changes = [];
browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.groupId) {
browser.test.assertEq(
changeInfo.groupId,
tab.groupId,
"changeInfo.groupId matches tab.groupId"
);
changes.push(changeInfo);
} else if (changeInfo.pinned != null) {
changes.push(changeInfo);
}
});
const { id: tabId } = await browser.tabs.create({ pinned: true });
const groupId = await browser.tabs.group({ tabIds: [tabId] });
await browser.tabs.remove(tabId);
browser.test.assertDeepEq(
[{ pinned: true }, { pinned: false }, { groupId: groupId }],
changes,
"Observed tabs.onUpdated events after group() of pinned tab"
);
browser.test.sendMessage("done");
},
});
await extension.startup();
await extension.awaitMessage("done");
await extension.unload();
});