From cb49a37c5ceab4f8c71ec3b44cea1bcbd13dfb43 Mon Sep 17 00:00:00 2001 From: OrcaWin Date: Wed, 28 Oct 2026 19:06:51 -0700 Subject: [PATCH] fix(extensions): honor transient popup dismissal (#35360) * fix(extensions): honor transient popup dismissal * refactor(extensions): reuse allowPageUnload for the action popup * test(extensions): cover action popup close despite a beforeunload veto --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> --- .../extensions/browser-extension-popup-host.ts | 2 ++ .../browser-extension-toolbar-electron-fixture.ts | 14 ++++++++++++++ .../browser-extension-toolbar.electron.test.ts | 6 ++++++ 3 files changed, 22 insertions(+) diff --git a/src/main/browser/extensions/browser-extension-popup-host.ts b/src/main/browser/extensions/browser-extension-popup-host.ts index c5bf148220e..337a7880e65 100644 --- a/src/main/browser/extensions/browser-extension-popup-host.ts +++ b/src/main/browser/extensions/browser-extension-popup-host.ts @@ -4,6 +4,7 @@ import { getChromeExtensionOrigin, isSameExtensionNavigation } from '../../../shared/browser-extension-url' +import { allowPageUnload } from '../browser-guest-unload-policy' import { BrowserExtensionApiError } from './browser-extension-namespace-registry' import { BROWSER_EXTENSION_POPUP_MAX, @@ -135,6 +136,7 @@ export function openBrowserExtensionPopup(options: BrowserExtensionPopupOptions) } current = popup const contents = window.webContents + contents.on('will-prevent-unload', allowPageUnload) // Why measure in the page: preferred-size-changed only reports while the window paints, and its // height never drops below the viewport, so a hidden or late-rendering popup kept its first size. diff --git a/src/main/browser/extensions/browser-extension-toolbar-electron-fixture.ts b/src/main/browser/extensions/browser-extension-toolbar-electron-fixture.ts index fec6e2b93e1..75926975d2f 100644 --- a/src/main/browser/extensions/browser-extension-toolbar-electron-fixture.ts +++ b/src/main/browser/extensions/browser-extension-toolbar-electron-fixture.ts @@ -15,6 +15,7 @@ import { getBrowserExtensionToolbarState } from './browser-extension-toolbar' import { + closeBrowserExtensionPopup, getOpenBrowserExtensionPopup, openBrowserExtensionPopup } from './browser-extension-popup-host' @@ -237,6 +238,19 @@ async function run(): Promise { const { width, height } = quirks.getBounds() return width === 170 ? { width, height } : null }) + // A page that vetoes unload after a user gesture still closes when the popup is dismissed. + const veto = openBrowserExtensionPopup({ + session: extensionSession, + profileId: profile.id, + extensionId, + popupPath: 'veto.html', + anchor, + openTab: () => {} + }) + await waitForReport('veto') + await veto.webContents.executeJavaScript('1', true) + closeBrowserExtensionPopup() + status.vetoPopupClosed = await waitFor(() => (veto.isDestroyed() ? true : null)) status.done = true writeStatus() } diff --git a/src/main/browser/extensions/browser-extension-toolbar.electron.test.ts b/src/main/browser/extensions/browser-extension-toolbar.electron.test.ts index d615d47eba0..22d48364a6f 100644 --- a/src/main/browser/extensions/browser-extension-toolbar.electron.test.ts +++ b/src/main/browser/extensions/browser-extension-toolbar.electron.test.ts @@ -119,6 +119,11 @@ beforeAll(async () => { join(extensionDir, 'quirks.html'), '
Vue.js not detected
' ) + writeFileSync(join(extensionDir, 'veto.html'), '') + writeFileSync( + join(extensionDir, 'veto.js'), + "onbeforeunload = (event) => { event.preventDefault(); event.returnValue = '' }; console.log('ORCA_EXT_VETO true')" + ) writeFileSync( join(extensionDir, 'late.js'), "setTimeout(() => { const box = document.createElement('div'); box.style.cssText = 'width:300px;height:180px'; document.body.append(box) }, 300)" @@ -236,6 +241,7 @@ describe('extension toolbar, action popup and tab activation in a real Electron expect(status.openAfterSecondClick).toBeNull() expect(status.latePopupBounds).toEqual({ width: 300, height: 180 }) expect(status.quirksPopupBounds).toEqual({ width: 170, height: 46 }) + expect(status.vetoPopupClosed).toBe(true) expect(status.windowsHidden).toBe(true) expect(status.presentationCalls).toEqual([])