commit 22e501aa0ae6f19b439861b27355afc2349ab72e
parent 8ac9b654258da137a48005f179a897c15b5e8a24
Author: Henrik Skupin <mail@hskupin.info>
Date: Thu, 6 Nov 2025 07:25:11 +0000
Bug 1996845 - [dom] Fix the replacement detection for the browsing-context-discarded notification. r=nika
Differential Revision: https://phabricator.services.mozilla.com/D271416
Diffstat:
2 files changed, 74 insertions(+), 21 deletions(-)
diff --git a/docshell/base/BrowsingContext.cpp b/docshell/base/BrowsingContext.cpp
@@ -1115,7 +1115,7 @@ void BrowsingContext::Detach(bool aFromIPC) {
// content process, but may be "replace" if it's known the context being
// replaced in the parent process.
const char16_t* why = u"discard";
- if (XRE_IsParentProcess() && IsTop() && !Canonical()->GetWebProgress()) {
+ if (XRE_IsParentProcess() && Canonical()->IsReplaced()) {
why = u"replace";
}
obs->NotifyObservers(ToSupports(this), "browsing-context-discarded", why);
diff --git a/docshell/test/browser/browser_browsing_context_discarded.js b/docshell/test/browser/browser_browsing_context_discarded.js
@@ -3,13 +3,13 @@
const TOPIC = "browsing-context-discarded";
async function observeDiscarded(browsingContexts, callback) {
- let discarded = [];
+ let discarded = new Map();
- let promise = BrowserUtils.promiseObserved(TOPIC, subject => {
+ let promise = BrowserUtils.promiseObserved(TOPIC, (subject, why) => {
ok(BrowsingContext.isInstance(subject), "subject to be a BrowsingContext");
- discarded.push(subject);
+ discarded.set(subject, why);
- return browsingContexts.every(item => discarded.includes(item));
+ return browsingContexts.every(item => discarded.has(item));
});
await callback();
await promise;
@@ -17,39 +17,64 @@ async function observeDiscarded(browsingContexts, callback) {
return discarded;
}
+function check_reason(discardedContexts, expected) {
+ discardedContexts.forEach((why, browsingContext) => {
+ if (expected.has(browsingContext)) {
+ is(why, expected.get(browsingContext));
+ }
+ });
+}
+
add_task(async function toplevelForNewWindow() {
- let win = await BrowserTestUtils.openNewBrowserWindow();
- let browsingContext = win.gBrowser.selectedBrowser.browsingContext;
+ const win = await BrowserTestUtils.openNewBrowserWindow();
+ const browsingContext = win.gBrowser.selectedBrowser.browsingContext;
+
+ const expected = new Map([
+ [win.browsingContext, "discard"],
+ [browsingContext, "discard"],
+ ]);
- await observeDiscarded([win.browsingContext, browsingContext], async () => {
+ const discarded = await observeDiscarded([...expected.keys()], async () => {
await BrowserTestUtils.closeWindow(win);
});
+
+ check_reason(discarded, expected);
});
add_task(async function toplevelForNewTab() {
- let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
- let browsingContext = tab.linkedBrowser.browsingContext;
+ const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
+ const browsingContext = tab.linkedBrowser.browsingContext;
+
+ const expected = new Map([[browsingContext, "discard"]]);
- let discarded = await observeDiscarded([browsingContext], () => {
+ const discarded = await observeDiscarded([...expected.keys()], () => {
BrowserTestUtils.removeTab(tab);
});
ok(
- !discarded.includes(window.browsingContext),
+ !discarded.has(window.browsingContext),
"no notification for the current window's chrome browsing context"
);
+
+ check_reason(discarded, expected);
});
add_task(async function subframe() {
- let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
- let browsingContext = await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
- let iframe = content.document.createElement("iframe");
- content.document.body.appendChild(iframe);
- iframe.contentWindow.location = "https://example.com/";
- return iframe.browsingContext;
- });
+ const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
+ const frameBrowsingContext = await SpecialPowers.spawn(
+ tab.linkedBrowser,
+ [],
+ () => {
+ const iframe = content.document.createElement("iframe");
+ content.document.body.appendChild(iframe);
+ iframe.contentWindow.location = "https://example.com/";
+ return iframe.browsingContext;
+ }
+ );
- let discarded = await observeDiscarded([browsingContext], async () => {
+ const expected = new Map([[frameBrowsingContext, "discard"]]);
+
+ const discarded = await observeDiscarded([...expected.keys()], async () => {
await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
let iframe = content.document.querySelector("iframe");
iframe.remove();
@@ -57,9 +82,37 @@ add_task(async function subframe() {
});
ok(
- !discarded.includes(tab.browsingContext),
+ !discarded.has(tab.linkedBrowser.browsingContext),
"no notification for toplevel browsing context"
);
+ ok(
+ !discarded.has(window.browsingContext),
+ "no notification for the current window's chrome browsing context"
+ );
+
+ check_reason(discarded, expected);
+
+ BrowserTestUtils.removeTab(tab);
+});
+
+add_task(async function replaceToplevel() {
+ const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
+ const browsingContext = tab.linkedBrowser.browsingContext;
+
+ const expected = new Map([[browsingContext, "replace"]]);
+
+ const discarded = await observeDiscarded([...expected.keys()], async () => {
+ await SpecialPowers.spawn(tab.linkedBrowser, [], () => {
+ content.location = "about:newtab";
+ });
+ });
+
+ ok(
+ !discarded.has(window.browsingContext),
+ "no notification for the current window's chrome browsing context"
+ );
+
+ check_reason(discarded, expected);
BrowserTestUtils.removeTab(tab);
});