diff options
Diffstat (limited to 'browser/base/content/test/popups')
29 files changed, 2248 insertions, 0 deletions
diff --git a/browser/base/content/test/popups/browser.toml b/browser/base/content/test/popups/browser.toml new file mode 100644 index 0000000000..f3ecb82b5b --- /dev/null +++ b/browser/base/content/test/popups/browser.toml @@ -0,0 +1,93 @@ +[DEFAULT] +support-files = [ + "head.js", + "popup_blocker_a.html", # used as dummy file +] + +["browser_popupUI.js"] + +["browser_popup_blocker.js"] +support-files = [ + "popup_blocker.html", + "popup_blocker_a.html", + "popup_blocker_b.html", + "popup_blocker_10_popups.html", +] +skip-if = [ + "os == 'linux'", # Frequent bug 1081925 and bug 1125520 failures + "debug", +] + +["browser_popup_blocker_frames.js"] +https_first_disabled = true +support-files = [ + "popup_blocker.html", + "popup_blocker_a.html", + "popup_blocker_b.html", +] + +["browser_popup_blocker_identity_block.js"] +https_first_disabled = true +support-files = [ + "popup_blocker2.html", + "popup_blocker_a.html", +] + +["browser_popup_blocker_iframes.js"] +https_first_disabled = true +support-files = [ + "popup_blocker.html", + "popup_blocker_frame.html", + "popup_blocker_a.html", + "popup_blocker_b.html", +] +skip-if = [ + "debug", # This test triggers Bug 1578794 due to opening many popups. +] + +["browser_popup_close_main_window.js"] + +["browser_popup_frames.js"] +https_first_disabled = true +support-files = [ + "popup_blocker.html", + "popup_blocker_a.html", + "popup_blocker_b.html", +] + +["browser_popup_inner_outer_size.js"] + +["browser_popup_linux_move.js"] +run-if = ["os == 'linux' && !headless"] # subset of other move tests + +["browser_popup_linux_resize.js"] +run-if = ["os == 'linux' && !headless"] # subset of other resize tests + +["browser_popup_move.js"] +skip-if = ["os == 'linux' && !headless"] # Wayland doesn't like moving windows, X11/XWayland unreliable current positions + +["browser_popup_move_instant.js"] +skip-if = ["os == 'linux' && !headless"] # Wayland doesn't like moving windows, X11/XWayland unreliable current positions + +["browser_popup_new_window_resize.js"] + +["browser_popup_new_window_size.js"] +support-files = ["popup_size.html"] + +["browser_popup_resize.js"] +skip-if = ["os == 'linux' && !headless"] # outdated current sizes + +["browser_popup_resize_instant.js"] +skip-if = ["os == 'linux' && !headless"] # outdated current sizes + +["browser_popup_resize_repeat.js"] +skip-if = ["os == 'linux' && !headless"] # outdated current sizes + +["browser_popup_resize_repeat_instant.js"] +skip-if = ["os == 'linux' && !headless"] # outdated current sizes + +["browser_popup_resize_revert.js"] +skip-if = ["os == 'linux' && !headless"] # outdated current sizes + +["browser_popup_resize_revert_instant.js"] +skip-if = ["os == 'linux' && !headless"] # outdated current sizes diff --git a/browser/base/content/test/popups/browser_popupUI.js b/browser/base/content/test/popups/browser_popupUI.js new file mode 100644 index 0000000000..27423b5868 --- /dev/null +++ b/browser/base/content/test/popups/browser_popupUI.js @@ -0,0 +1,192 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +add_task(async function toolbar_ui_visibility() { + SpecialPowers.pushPrefEnv({ set: [["dom.disable_open_during_load", false]] }); + + let popupOpened = BrowserTestUtils.waitForNewWindow({ url: "about:blank" }); + BrowserTestUtils.openNewForegroundTab( + gBrowser, + "data:text/html,<html><script>popup=open('about:blank','','width=300,height=200')</script>" + ); + const win = await popupOpened; + const doc = win.document; + + ok(win.gURLBar, "location bar exists in the popup"); + isnot(win.gURLBar.clientWidth, 0, "location bar is visible in the popup"); + ok(win.gURLBar.readOnly, "location bar is read-only in the popup"); + isnot( + doc.getElementById("Browser:OpenLocation").getAttribute("disabled"), + "true", + "'open location' command is not disabled in the popup" + ); + + EventUtils.synthesizeKey("t", { accelKey: true }, win); + is( + win.gBrowser.browsers.length, + 1, + "Accel+T doesn't open a new tab in the popup" + ); + is( + gBrowser.browsers.length, + 3, + "Accel+T opened a new tab in the parent window" + ); + gBrowser.removeCurrentTab(); + + EventUtils.synthesizeKey("w", { accelKey: true }, win); + ok(win.closed, "Accel+W closes the popup"); + + if (!win.closed) { + win.close(); + } + gBrowser.removeCurrentTab(); +}); + +add_task(async function titlebar_buttons_visibility() { + if (!navigator.platform.startsWith("Win")) { + ok(true, "Testing only on Windows"); + return; + } + + const BUTTONS_MAY_VISIBLE = true; + const BUTTONS_NEVER_VISIBLE = false; + + // Always open a new window. + // With default behavior, it opens a new tab, that doesn't affect button + // visibility at all. + Services.prefs.setIntPref("browser.link.open_newwindow", 2); + + const drawInTitlebarValues = [ + [1, BUTTONS_MAY_VISIBLE], + [0, BUTTONS_NEVER_VISIBLE], + ]; + const windowFeaturesValues = [ + // Opens a popup + ["width=300,height=100", BUTTONS_NEVER_VISIBLE], + ["toolbar", BUTTONS_NEVER_VISIBLE], + ["menubar", BUTTONS_NEVER_VISIBLE], + ["menubar,toolbar", BUTTONS_NEVER_VISIBLE], + + // Opens a new window + ["", BUTTONS_MAY_VISIBLE], + ]; + const menuBarShownValues = [true, false]; + + for (const [drawInTitlebar, drawInTitlebarButtons] of drawInTitlebarValues) { + Services.prefs.setIntPref("browser.tabs.inTitlebar", drawInTitlebar); + + for (const [ + windowFeatures, + windowFeaturesButtons, + ] of windowFeaturesValues) { + for (const menuBarShown of menuBarShownValues) { + CustomizableUI.setToolbarVisibility("toolbar-menubar", menuBarShown); + + const popupPromise = BrowserTestUtils.waitForNewWindow("about:blank"); + BrowserTestUtils.openNewForegroundTab( + gBrowser, + `data:text/html;charset=UTF-8,<html><script>window.open("about:blank","","${windowFeatures}")</script>` + ); + const popupWin = await popupPromise; + + const menubar = popupWin.document.querySelector("#toolbar-menubar"); + const menubarIsShown = + menubar.getAttribute("autohide") != "true" || + menubar.getAttribute("inactive") != "true"; + const buttonsInMenubar = menubar.querySelector( + ".titlebar-buttonbox-container" + ); + const buttonsInMenubarShown = + menubarIsShown && + popupWin.getComputedStyle(buttonsInMenubar).display != "none"; + + const buttonsInTabbar = popupWin.document.querySelector( + "#TabsToolbar .titlebar-buttonbox-container" + ); + const buttonsInTabbarShown = + popupWin.getComputedStyle(buttonsInTabbar).display != "none"; + + const params = `drawInTitlebar=${drawInTitlebar}, windowFeatures=${windowFeatures}, menuBarShown=${menuBarShown}`; + if ( + drawInTitlebarButtons == BUTTONS_MAY_VISIBLE && + windowFeaturesButtons == BUTTONS_MAY_VISIBLE + ) { + ok( + buttonsInMenubarShown || buttonsInTabbarShown, + `Titlebar buttons should be visible: ${params}` + ); + } else { + ok( + !buttonsInMenubarShown, + `Titlebar buttons should not be visible: ${params}` + ); + ok( + !buttonsInTabbarShown, + `Titlebar buttons should not be visible: ${params}` + ); + } + + const closedPopupPromise = BrowserTestUtils.windowClosed(popupWin); + popupWin.close(); + await closedPopupPromise; + gBrowser.removeCurrentTab(); + } + } + } + + CustomizableUI.setToolbarVisibility("toolbar-menubar", false); + Services.prefs.clearUserPref("browser.tabs.inTitlebar"); + Services.prefs.clearUserPref("browser.link.open_newwindow"); +}); + +// Test only `visibility` rule here, to verify bug 1636229 fix. +// Other styles and ancestors can be different for each OS. +function isVisible(element) { + const style = element.ownerGlobal.getComputedStyle(element); + return style.visibility == "visible"; +} + +async function testTabBarVisibility() { + SpecialPowers.pushPrefEnv({ set: [["dom.disable_open_during_load", false]] }); + + const popupOpened = BrowserTestUtils.waitForNewWindow({ url: "about:blank" }); + BrowserTestUtils.openNewForegroundTab( + gBrowser, + "data:text/html,<html><script>popup=open('about:blank','','width=300,height=200')</script>" + ); + const win = await popupOpened; + const doc = win.document; + + ok( + !isVisible(doc.getElementById("TabsToolbar")), + "tabbar should be hidden for popup" + ); + + const closedPopupPromise = BrowserTestUtils.windowClosed(win); + win.close(); + await closedPopupPromise; + + gBrowser.removeCurrentTab(); +} + +add_task(async function tabbar_visibility() { + await testTabBarVisibility(); +}); + +add_task(async function tabbar_visibility_with_theme() { + const extension = ExtensionTestUtils.loadExtension({ + manifest: { + theme: {}, + }, + }); + + await extension.startup(); + + await testTabBarVisibility(); + + await extension.unload(); +}); diff --git a/browser/base/content/test/popups/browser_popup_blocker.js b/browser/base/content/test/popups/browser_popup_blocker.js new file mode 100644 index 0000000000..bfda12331e --- /dev/null +++ b/browser/base/content/test/popups/browser_popup_blocker.js @@ -0,0 +1,155 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const baseURL = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" +); + +function clearAllPermissionsByPrefix(aPrefix) { + for (let perm of Services.perms.all) { + if (perm.type.startsWith(aPrefix)) { + Services.perms.removePermission(perm); + } + } +} + +add_setup(async function () { + // Enable the popup blocker. + await SpecialPowers.pushPrefEnv({ + set: [["dom.disable_open_during_load", true]], + }); +}); + +// Tests that we show a special message when popup blocking exceeds +// a certain maximum of popups per page. +add_task(async function test_maximum_reported_blocks() { + Services.prefs.setIntPref("privacy.popups.maxReported", 5); + + // Open the test page. + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + baseURL + "popup_blocker_10_popups.html" + ); + + // Wait for the popup-blocked notification. + let notification = await TestUtils.waitForCondition(() => + gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked") + ); + + // Slightly hacky way to ensure we show the correct message in this case. + ok( + notification.messageText.textContent.includes("more than"), + "Notification label has 'more than'" + ); + ok( + notification.messageText.textContent.includes("5"), + "Notification label shows the maximum number of popups" + ); + + gBrowser.removeTab(tab); + + Services.prefs.clearUserPref("privacy.popups.maxReported"); +}); + +add_task(async function test_opening_blocked_popups() { + // Open the test page. + let tab = await BrowserTestUtils.openNewForegroundTab( + gBrowser, + baseURL + "popup_blocker.html" + ); + + await testPopupBlockingToolbar(tab); +}); + +add_task(async function test_opening_blocked_popups_privateWindow() { + let win = await BrowserTestUtils.openNewBrowserWindow({ + private: true, + }); + // Open the test page. + let tab = await BrowserTestUtils.openNewForegroundTab( + win.gBrowser, + baseURL + "popup_blocker.html" + ); + await testPopupBlockingToolbar(tab); + await BrowserTestUtils.closeWindow(win); +}); + +async function testPopupBlockingToolbar(tab) { + let win = tab.ownerGlobal; + // Wait for the popup-blocked notification. + let notification; + await TestUtils.waitForCondition( + () => + (notification = win.gBrowser + .getNotificationBox() + .getNotificationWithValue("popup-blocked")) + ); + + // Show the menu. + let popupShown = BrowserTestUtils.waitForEvent(win, "popupshown"); + let popupFilled = waitForBlockedPopups(2, { + doc: win.document, + }); + EventUtils.synthesizeMouseAtCenter( + notification.buttonContainer.querySelector("button"), + {}, + win + ); + let popup_event = await popupShown; + let menu = popup_event.target; + is(menu.id, "blockedPopupOptions", "Blocked popup menu shown"); + + await popupFilled; + + // Pressing "allow" should open all blocked popups. + let popupTabs = []; + function onTabOpen(event) { + popupTabs.push(event.target); + } + win.gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen); + + // Press the button. + let allow = win.document.getElementById("blockedPopupAllowSite"); + allow.doCommand(); + await TestUtils.waitForCondition( + () => + popupTabs.length == 2 && + popupTabs.every( + aTab => aTab.linkedBrowser.currentURI.spec != "about:blank" + ) + ); + + win.gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen); + + ok( + popupTabs[0].linkedBrowser.currentURI.spec.endsWith("popup_blocker_a.html"), + "Popup a" + ); + ok( + popupTabs[1].linkedBrowser.currentURI.spec.endsWith("popup_blocker_b.html"), + "Popup b" + ); + + let popupPerms = Services.perms.getAllByTypeSince("popup", 0); + is(popupPerms.length, 1, "One popup permission added"); + let popupPerm = popupPerms[0]; + let expectedExpireType = PrivateBrowsingUtils.isWindowPrivate(win) + ? Services.perms.EXPIRE_SESSION + : Services.perms.EXPIRE_NEVER; + is( + popupPerm.expireType, + expectedExpireType, + "Check expireType is appropriate for the window" + ); + + // Clean up. + win.gBrowser.removeTab(tab); + for (let popup of popupTabs) { + win.gBrowser.removeTab(popup); + } + clearAllPermissionsByPrefix("popup"); + // Ensure the menu closes. + menu.hidePopup(); +} diff --git a/browser/base/content/test/popups/browser_popup_blocker_frames.js b/browser/base/content/test/popups/browser_popup_blocker_frames.js new file mode 100644 index 0000000000..163fa4a0bb --- /dev/null +++ b/browser/base/content/test/popups/browser_popup_blocker_frames.js @@ -0,0 +1,100 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const baseURL = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://example.com" +); + +async function test_opening_blocked_popups(testURL) { + // Enable the popup blocker. + await SpecialPowers.pushPrefEnv({ + set: [["dom.disable_open_during_load", true]], + }); + + // Open the test page. + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, testURL); + + await SpecialPowers.spawn( + tab.linkedBrowser, + [baseURL + "popup_blocker.html"], + uri => { + let iframe = content.document.createElement("iframe"); + iframe.id = "popupframe"; + iframe.src = uri; + content.document.body.appendChild(iframe); + } + ); + + // Wait for the popup-blocked notification. + await TestUtils.waitForCondition( + () => + gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked"), + "Waiting for the popup-blocked notification." + ); + + let popupTabs = []; + function onTabOpen(event) { + popupTabs.push(event.target); + } + gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen); + + await SpecialPowers.pushPermissions([ + { type: "popup", allow: true, context: testURL }, + ]); + + await SpecialPowers.spawn( + tab.linkedBrowser, + [baseURL + "popup_blocker.html"], + uri => { + content.document.getElementById("popupframe").remove(); + let iframe = content.document.createElement("iframe"); + iframe.id = "popupframe"; + iframe.src = uri; + content.document.body.appendChild(iframe); + } + ); + + await TestUtils.waitForCondition( + () => + popupTabs.length == 2 && + popupTabs.every( + aTab => aTab.linkedBrowser.currentURI.spec != "about:blank" + ), + "Waiting for two tabs to be opened." + ); + + ok( + popupTabs[0].linkedBrowser.currentURI.spec.endsWith("popup_blocker_a.html"), + "Popup a" + ); + ok( + popupTabs[1].linkedBrowser.currentURI.spec.endsWith("popup_blocker_b.html"), + "Popup b" + ); + + await SpecialPowers.popPermissions(); + + gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen); + + await SpecialPowers.spawn(tab.linkedBrowser, [], () => { + content.document.getElementById("popupframe").remove(); + }); + + BrowserTestUtils.removeTab(tab); + for (let popup of popupTabs) { + gBrowser.removeTab(popup); + } +} + +add_task(async function () { + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + await test_opening_blocked_popups("http://example.com/"); +}); + +add_task(async function () { + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + await test_opening_blocked_popups("http://w3c-test.org/"); +}); diff --git a/browser/base/content/test/popups/browser_popup_blocker_identity_block.js b/browser/base/content/test/popups/browser_popup_blocker_identity_block.js new file mode 100644 index 0000000000..c277be2c40 --- /dev/null +++ b/browser/base/content/test/popups/browser_popup_blocker_identity_block.js @@ -0,0 +1,242 @@ +"use strict"; + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const { PermissionTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/PermissionTestUtils.sys.mjs" +); + +const baseURL = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://example.com" +); +const URL = baseURL + "popup_blocker2.html"; +const URI = Services.io.newURI(URL); +const PRINCIPAL = Services.scriptSecurityManager.createContentPrincipal( + URI, + {} +); + +function openPermissionPopup() { + let promise = BrowserTestUtils.waitForEvent( + window, + "popupshown", + true, + event => event.target == gPermissionPanel._permissionPopup + ); + gPermissionPanel._identityPermissionBox.click(); + return promise; +} + +function closePermissionPopup() { + let promise = BrowserTestUtils.waitForEvent( + gPermissionPanel._permissionPopup, + "popuphidden" + ); + gPermissionPanel._permissionPopup.hidePopup(); + return promise; +} + +add_task(async function enable_popup_blocker() { + // Enable popup blocker. + await SpecialPowers.pushPrefEnv({ + set: [["dom.disable_open_during_load", true]], + }); + await SpecialPowers.pushPrefEnv({ + set: [["dom.disable_open_click_delay", 0]], + }); +}); + +add_task(async function check_blocked_popup_indicator() { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL); + + // Blocked popup indicator should not exist in the identity popup when there are no blocked popups. + await openPermissionPopup(); + Assert.equal(document.getElementById("blocked-popup-indicator-item"), null); + await closePermissionPopup(); + + // Blocked popup notification icon should be hidden in the identity block when no popups are blocked. + let icon = gPermissionPanel._identityPermissionBox.querySelector( + ".blocked-permission-icon[data-permission-id='popup']" + ); + Assert.equal(icon.hasAttribute("showing"), false); + + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async () => { + let open = content.document.getElementById("pop"); + open.click(); + }); + + // Wait for popup block. + await TestUtils.waitForCondition(() => + gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked") + ); + + // Check if blocked popup indicator text is visible in the identity popup. It should be visible. + document.getElementById("identity-permission-box").click(); + await openPermissionPopup(); + await TestUtils.waitForCondition( + () => document.getElementById("blocked-popup-indicator-item") !== null + ); + + // Check that the default state is correctly set to "Block". + let menulist = document.getElementById("permission-popup-menulist"); + Assert.equal(menulist.value, "0"); + Assert.equal(menulist.label, "Block"); + + await closePermissionPopup(); + + // Check if blocked popup icon is visible in the identity block. + Assert.equal(icon.getAttribute("showing"), "true"); + + gBrowser.removeTab(tab); +}); + +// Check if clicking on "Show blocked popups" shows blocked popups. +add_task(async function check_popup_showing() { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL); + + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async () => { + let open = content.document.getElementById("pop"); + open.click(); + }); + + // Wait for popup block. + await TestUtils.waitForCondition(() => + gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked") + ); + + // Store the popup that opens in this array. + let popup; + function onTabOpen(event) { + popup = event.target; + } + gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen); + + // Open identity popup and click on "Show blocked popups". + await openPermissionPopup(); + let e = document.getElementById("blocked-popup-indicator-item"); + let text = e.getElementsByTagName("label")[0]; + text.click(); + + await BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabOpen"); + await TestUtils.waitForCondition( + () => popup.linkedBrowser.currentURI.spec != "about:blank" + ); + + gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen); + + ok( + popup.linkedBrowser.currentURI.spec.endsWith("popup_blocker_a.html"), + "Popup a" + ); + + gBrowser.removeTab(popup); + gBrowser.removeTab(tab); +}); + +// Test if changing menulist values of blocked popup indicator changes permission state and popup behavior. +add_task(async function check_permission_state_change() { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL); + + // Initially the permission state is BLOCK for popups (set by the prefs). + let state = SitePermissions.getForPrincipal( + PRINCIPAL, + "popup", + gBrowser + ).state; + Assert.equal(state, SitePermissions.BLOCK); + + await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async () => { + let open = content.document.getElementById("pop"); + open.click(); + }); + + // Wait for popup block. + await TestUtils.waitForCondition(() => + gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked") + ); + + // Open identity popup and change permission state to allow. + await openPermissionPopup(); + let menulist = document.getElementById("permission-popup-menulist"); + menulist.menupopup.openPopup(); // Open the allow/block menu + let menuitem = menulist.getElementsByTagName("menuitem")[0]; + menuitem.click(); + await closePermissionPopup(); + + state = SitePermissions.getForPrincipal(PRINCIPAL, "popup", gBrowser).state; + Assert.equal(state, SitePermissions.ALLOW); + + // Store the popup that opens in this array. + let popup; + function onTabOpen(event) { + popup = event.target; + } + gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen); + + // Check if a popup opens. + await Promise.all([ + SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => { + let open = content.document.getElementById("pop"); + open.click(); + }), + BrowserTestUtils.waitForEvent(gBrowser.tabContainer, "TabOpen"), + ]); + await TestUtils.waitForCondition( + () => popup.linkedBrowser.currentURI.spec != "about:blank" + ); + + gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen); + + ok( + popup.linkedBrowser.currentURI.spec.endsWith("popup_blocker_a.html"), + "Popup a" + ); + + gBrowser.removeTab(popup); + + // Open identity popup and change permission state to block. + await openPermissionPopup(); + menulist = document.getElementById("permission-popup-menulist"); + menulist.menupopup.openPopup(); // Open the allow/block menu + menuitem = menulist.getElementsByTagName("menuitem")[1]; + menuitem.click(); + await closePermissionPopup(); + + // Clicking on the "Block" menuitem should remove the permission object(same behavior as UNKNOWN state). + // We have already confirmed that popups are blocked when the permission state is BLOCK. + state = SitePermissions.getForPrincipal(PRINCIPAL, "popup", gBrowser).state; + Assert.equal(state, SitePermissions.BLOCK); + + gBrowser.removeTab(tab); +}); + +// Explicitly set the permission to the otherwise default state and check that +// the label still displays correctly. +add_task(async function check_explicit_default_permission() { + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL); + + // DENY only works if triggered through Services.perms (it's very edge-casey), + // since SitePermissions.sys.mjs considers setting default permissions to be removal. + PermissionTestUtils.add(URI, "popup", Ci.nsIPermissionManager.DENY_ACTION); + + await openPermissionPopup(); + let menulist = document.getElementById("permission-popup-menulist"); + Assert.equal(menulist.value, "0"); + Assert.equal(menulist.label, "Block"); + await closePermissionPopup(); + + PermissionTestUtils.add(URI, "popup", Services.perms.ALLOW_ACTION); + + await openPermissionPopup(); + menulist = document.getElementById("permission-popup-menulist"); + Assert.equal(menulist.value, "1"); + Assert.equal(menulist.label, "Allow"); + await closePermissionPopup(); + + PermissionTestUtils.remove(URI, "popup"); + gBrowser.removeTab(tab); +}); diff --git a/browser/base/content/test/popups/browser_popup_blocker_iframes.js b/browser/base/content/test/popups/browser_popup_blocker_iframes.js new file mode 100644 index 0000000000..ec1002befd --- /dev/null +++ b/browser/base/content/test/popups/browser_popup_blocker_iframes.js @@ -0,0 +1,186 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +"use strict"; + +requestLongerTimeout(5); + +const testURL = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://example.org" +); + +const examplecomURL = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://example.com" +); + +const w3cURL = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://w3c-test.org" +); + +const examplenetURL = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://example.net" +); + +const prefixexamplecomURL = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://prefixexample.com" +); + +class TestCleanup { + constructor() { + this.tabs = []; + } + + count() { + return this.tabs.length; + } + + static setup() { + let cleaner = new TestCleanup(); + this.onTabOpen = event => { + cleaner.tabs.push(event.target); + }; + gBrowser.tabContainer.addEventListener("TabOpen", this.onTabOpen); + return cleaner; + } + + clean() { + gBrowser.tabContainer.removeEventListener("TabOpen", this.onTabOpen); + for (let tab of this.tabs) { + gBrowser.removeTab(tab); + } + } +} + +async function runTest(count, urls, permissions, delayedAllow) { + let cleaner = TestCleanup.setup(); + + // Enable the popup blocker. + await SpecialPowers.pushPrefEnv({ + set: [["dom.disable_open_during_load", true]], + }); + + await SpecialPowers.pushPermissions(permissions); + + // Open the test page. + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, testURL); + + let contexts = await SpecialPowers.spawn( + tab.linkedBrowser, + [...urls, !!delayedAllow], + async (url1, url2, url3, url4, delay) => { + let iframe1 = content.document.createElement("iframe"); + let iframe2 = content.document.createElement("iframe"); + iframe1.id = "iframe1"; + iframe2.id = "iframe2"; + iframe1.src = new URL( + `popup_blocker_frame.html?delayed=${delay}&base=${url3}`, + url1 + ); + iframe2.src = new URL( + `popup_blocker_frame.html?delayed=${delay}&base=${url4}`, + url2 + ); + + let promises = [ + new Promise(resolve => (iframe1.onload = resolve)), + new Promise(resolve => (iframe2.onload = resolve)), + ]; + + content.document.body.appendChild(iframe1); + content.document.body.appendChild(iframe2); + + await Promise.all(promises); + return [iframe1.browsingContext, iframe2.browsingContext]; + } + ); + + if (delayedAllow) { + await delayedAllow(); + await SpecialPowers.spawn( + tab.linkedBrowser, + contexts, + async function (bc1, bc2) { + bc1.window.postMessage("allow", "*"); + bc2.window.postMessage("allow", "*"); + } + ); + } + + await TestUtils.waitForCondition( + () => cleaner.count() == count, + `waiting for ${count} tabs, got ${cleaner.count()}` + ); + + Assert.equal(cleaner.count(), count, `should have ${count} tabs`); + + await SpecialPowers.popPermissions(); + cleaner.clean(); +} + +add_task(async function () { + let permission = { + type: "popup", + allow: true, + context: "", + }; + + let expected = []; + + let tests = [ + [examplecomURL, w3cURL, prefixexamplecomURL, examplenetURL], + [examplecomURL, examplecomURL, prefixexamplecomURL, examplenetURL], + [examplecomURL, examplecomURL, prefixexamplecomURL, prefixexamplecomURL], + [examplecomURL, w3cURL, prefixexamplecomURL, prefixexamplecomURL], + ]; + + permission.context = testURL; + expected = [5, 5, 3, 3]; + for (let test in tests) { + await runTest(expected[test], tests[test], [permission]); + } + + permission.context = examplecomURL; + expected = [3, 5, 3, 3]; + for (let test in tests) { + await runTest(expected[test], tests[test], [permission]); + } + + permission.context = prefixexamplecomURL; + expected = [3, 3, 3, 3]; + for (let test in tests) { + await runTest(expected[test], tests[test], [permission]); + } + + async function allowPopup() { + await SpecialPowers.pushPermissions([permission]); + } + + permission.context = testURL; + expected = [5, 5, 3, 3]; + for (let test in tests) { + await runTest(expected[test], tests[test], [], allowPopup); + } + + permission.context = examplecomURL; + expected = [3, 5, 3, 3]; + for (let test in tests) { + await runTest(expected[test], tests[test], [], allowPopup); + } + + permission.context = prefixexamplecomURL; + expected = [3, 3, 3, 3]; + for (let test in tests) { + await runTest(expected[test], tests[test], [], allowPopup); + } +}); diff --git a/browser/base/content/test/popups/browser_popup_close_main_window.js b/browser/base/content/test/popups/browser_popup_close_main_window.js new file mode 100644 index 0000000000..148e937bca --- /dev/null +++ b/browser/base/content/test/popups/browser_popup_close_main_window.js @@ -0,0 +1,84 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +function muffleMainWindowType() { + let oldWinType = document.documentElement.getAttribute("windowtype"); + // Check if we've already done this to allow calling multiple times: + if (oldWinType != "navigator:testrunner") { + // Make the main test window not count as a browser window any longer + document.documentElement.setAttribute("windowtype", "navigator:testrunner"); + + registerCleanupFunction(() => { + document.documentElement.setAttribute("windowtype", oldWinType); + }); + } +} + +/** + * Check that if we close the 1 remaining window, we treat it as quitting on + * non-mac. + * + * Sets the window type for the main browser test window to something else to + * avoid having to actually close the main browser window. + */ +add_task(async function closing_last_window_equals_quitting() { + if (navigator.platform.startsWith("Mac")) { + ok(true, "Not testing on mac"); + return; + } + muffleMainWindowType(); + + let observed = 0; + function obs() { + observed++; + } + Services.obs.addObserver(obs, "browser-lastwindow-close-requested"); + let newWin = await BrowserTestUtils.openNewBrowserWindow(); + let closedPromise = BrowserTestUtils.windowClosed(newWin); + newWin.BrowserTryToCloseWindow(); + await closedPromise; + is(observed, 1, "Got a notification for closing the normal window."); + Services.obs.removeObserver(obs, "browser-lastwindow-close-requested"); +}); + +/** + * Check that if we close the 1 remaining window and also have a popup open, + * we don't treat it as quitting. + * + * Sets the window type for the main browser test window to something else to + * avoid having to actually close the main browser window. + */ +add_task(async function closing_last_window_equals_quitting() { + if (navigator.platform.startsWith("Mac")) { + ok(true, "Not testing on mac"); + return; + } + muffleMainWindowType(); + let observed = 0; + function obs() { + observed++; + } + Services.obs.addObserver(obs, "browser-lastwindow-close-requested"); + let newWin = await BrowserTestUtils.openNewBrowserWindow(); + let popupPromise = BrowserTestUtils.waitForNewWindow("https://example.com/"); + SpecialPowers.spawn(newWin.gBrowser.selectedBrowser, [], function () { + content.open("https://example.com/", "_blank", "height=500"); + }); + let popupWin = await popupPromise; + let closedPromise = BrowserTestUtils.windowClosed(newWin); + newWin.BrowserTryToCloseWindow(); + await closedPromise; + is(observed, 0, "Got no notification for closing the normal window."); + + closedPromise = BrowserTestUtils.windowClosed(popupWin); + popupWin.BrowserTryToCloseWindow(); + await closedPromise; + is( + observed, + 0, + "Got no notification now that we're closing the last window, as it's a popup." + ); + Services.obs.removeObserver(obs, "browser-lastwindow-close-requested"); +}); diff --git a/browser/base/content/test/popups/browser_popup_frames.js b/browser/base/content/test/popups/browser_popup_frames.js new file mode 100644 index 0000000000..838eb5c045 --- /dev/null +++ b/browser/base/content/test/popups/browser_popup_frames.js @@ -0,0 +1,128 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const baseURL = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + "http://example.com" +); + +async function test_opening_blocked_popups(testURL) { + // Enable the popup blocker. + await SpecialPowers.pushPrefEnv({ + set: [["dom.disable_open_during_load", true]], + }); + + // Open the test page. + let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, testURL); + + let popupframeBC = await SpecialPowers.spawn( + tab.linkedBrowser, + [baseURL + "popup_blocker.html"], + uri => { + let iframe = content.document.createElement("iframe"); + iframe.id = "popupframe"; + iframe.src = uri; + content.document.body.appendChild(iframe); + return iframe.browsingContext; + } + ); + + // Wait for the popup-blocked notification. + let notification; + await TestUtils.waitForCondition( + () => + (notification = gBrowser + .getNotificationBox() + .getNotificationWithValue("popup-blocked")), + "Waiting for the popup-blocked notification." + ); + + ok(notification, "Should have notification."); + + let pageHideHappened = BrowserTestUtils.waitForContentEvent( + tab.linkedBrowser, + "pagehide", + true + ); + await SpecialPowers.spawn(tab.linkedBrowser, [baseURL], async function (uri) { + let iframe = content.document.createElement("iframe"); + content.document.body.appendChild(iframe); + iframe.src = uri; + }); + + await pageHideHappened; + notification = gBrowser + .getNotificationBox() + .getNotificationWithValue("popup-blocked"); + ok(notification, "Should still have notification"); + + pageHideHappened = BrowserTestUtils.waitForContentEvent( + tab.linkedBrowser, + "pagehide", + true + ); + // Now navigate the subframe. + await SpecialPowers.spawn(popupframeBC, [], async function () { + content.document.location.href = "about:blank"; + }); + await pageHideHappened; + await TestUtils.waitForCondition( + () => + !gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked"), + "Notification should go away" + ); + ok( + !gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked"), + "Should no longer have notification" + ); + + // Remove the frame and add another one: + await SpecialPowers.spawn( + tab.linkedBrowser, + [baseURL + "popup_blocker.html"], + uri => { + content.document.getElementById("popupframe").remove(); + let iframe = content.document.createElement("iframe"); + iframe.id = "popupframe"; + iframe.src = uri; + content.document.body.appendChild(iframe); + } + ); + + // Wait for the popup-blocked notification. + await TestUtils.waitForCondition( + () => + (notification = gBrowser + .getNotificationBox() + .getNotificationWithValue("popup-blocked")) + ); + + ok(notification, "Should have notification."); + + await SpecialPowers.spawn(tab.linkedBrowser, [], () => { + content.document.getElementById("popupframe").remove(); + }); + + await TestUtils.waitForCondition( + () => + !gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked") + ); + ok( + !gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked"), + "Should no longer have notification" + ); + + BrowserTestUtils.removeTab(tab); +} + +add_task(async function () { + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + await test_opening_blocked_popups("http://example.com/"); +}); + +add_task(async function () { + // eslint-disable-next-line @microsoft/sdl/no-insecure-url + await test_opening_blocked_popups("http://w3c-test.org/"); +}); diff --git a/browser/base/content/test/popups/browser_popup_inner_outer_size.js b/browser/base/content/test/popups/browser_popup_inner_outer_size.js new file mode 100644 index 0000000000..7e2e0e43fe --- /dev/null +++ b/browser/base/content/test/popups/browser_popup_inner_outer_size.js @@ -0,0 +1,120 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +async function checkForDeltaMismatch(aMsg) { + let getDelta = () => { + return { + width: this.content.outerWidth - this.content.innerWidth, + height: this.content.outerHeight - this.content.innerHeight, + }; + }; + + let initialDelta = getDelta(); + let latestDelta = initialDelta; + + this.content.testerPromise = new Promise(resolve => { + // Called from stopCheck + this.content.resolveFunc = resolve; + info(`[${aMsg}] Starting interval tester.`); + this.content.intervalID = this.content.setInterval(() => { + let currentDelta = getDelta(); + if ( + latestDelta.width != currentDelta.width || + latestDelta.height != currentDelta.height + ) { + latestDelta = currentDelta; + + let { innerWidth: iW, outerWidth: oW } = this.content; + let { innerHeight: iH, outerHeight: oH } = this.content; + info(`[${aMsg}] Delta changed. (inner ${iW}x${iH}, outer ${oW}x${oH})`); + + let { width: w, height: h } = currentDelta; + is(w, initialDelta.width, `[${aMsg}] Inner to outer width delta.`); + is(h, initialDelta.height, `[${aMsg}] Inner to outer height delta.`); + } + }, 0); + }).then(() => { + let { width: w, height: h } = latestDelta; + is(w, initialDelta.width, `[${aMsg}] Final inner to outer width delta.`); + is(h, initialDelta.height, `[${aMsg}] Final Inner to outer height delta.`); + }); +} + +async function stopCheck(aMsg) { + info(`[${aMsg}] Stopping interval tester.`); + this.content.clearInterval(this.content.intervalID); + info(`[${aMsg}] Resolving interval tester.`); + this.content.resolveFunc(); + await this.content.testerPromise; +} + +add_task(async function test_innerToOuterDelta() { + let tab = await BrowserTestUtils.openNewForegroundTab( + window.gBrowser, + "https://example.net" + ); + let popupBrowsingContext = await SpecialPowers.spawn( + tab.linkedBrowser, + [], + async () => { + info("Opening popup."); + let popup = this.content.open( + "https://example.net", + "", + "width=200,height=200" + ); + info("Waiting for load event."); + await ContentTaskUtils.waitForEvent(popup, "load"); + return popup.browsingContext; + } + ); + + await SpecialPowers.spawn( + popupBrowsingContext, + ["Content"], + checkForDeltaMismatch + ); + let popupChrome = popupBrowsingContext.topChromeWindow; + await SpecialPowers.spawn(popupChrome, ["Chrome"], checkForDeltaMismatch); + + let numResizes = 3; + let resizeStep = 5; + let { outerWidth: width, outerHeight: height } = popupChrome; + let finalWidth = width + numResizes * resizeStep; + let finalHeight = height + numResizes * resizeStep; + + info(`Starting ${numResizes} resizes.`); + await new Promise(resolve => { + let resizeListener = () => { + if ( + popupChrome.outerWidth == finalWidth && + popupChrome.outerHeight == finalHeight + ) { + popupChrome.removeEventListener("resize", resizeListener); + resolve(); + } + }; + popupChrome.addEventListener("resize", resizeListener); + + let resizeNext = () => { + width += resizeStep; + height += resizeStep; + info(`Resizing to ${width}x${height}`); + popupChrome.resizeTo(width, height); + numResizes--; + if (numResizes > 0) { + info(`${numResizes} resizes remaining.`); + popupChrome.requestAnimationFrame(resizeNext); + } + }; + resizeNext(); + }); + + await SpecialPowers.spawn(popupBrowsingContext, ["Content"], stopCheck); + await SpecialPowers.spawn(popupChrome, ["Chrome"], stopCheck); + + await SpecialPowers.spawn(popupBrowsingContext, [], () => { + this.content.close(); + }); + await BrowserTestUtils.removeTab(tab); +}); diff --git a/browser/base/content/test/popups/browser_popup_linux_move.js b/browser/base/content/test/popups/browser_popup_linux_move.js new file mode 100644 index 0000000000..f318ee1873 --- /dev/null +++ b/browser/base/content/test/popups/browser_popup_linux_move.js @@ -0,0 +1,56 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function createLinuxMoveTests(aFirstValue, aSecondValue, aMsg) { + for (let prop of ["screenX", "screenY"]) { + let first = {}; + first[prop] = aFirstValue; + let second = {}; + second[prop] = aSecondValue; + new ResizeMoveTest( + [first, second], + /* aInstant */ true, + `${aMsg} ${prop},${prop}` + ); + new ResizeMoveTest( + [first, second], + /* aInstant */ false, + `${aMsg} ${prop},${prop}` + ); + } +} + +if (AppConstants.platform == "linux" && gfxInfo.windowProtocol == "wayland") { + add_task(async () => { + let tab = await ResizeMoveTest.GetOrCreateTab(); + let browsingContext = + await ResizeMoveTest.GetOrCreatePopupBrowsingContext(); + let win = browsingContext.topChromeWindow; + let targetX = win.screenX + 10; + win.moveTo(targetX, win.screenY); + await BrowserTestUtils.waitForCondition(() => win.screenX == targetX).catch( + () => {} + ); + todo(win.screenX == targetX, "Moving windows on wayland."); + win.close(); + await BrowserTestUtils.removeTab(tab); + }); +} else { + createLinuxMoveTests(9, 10, "Move"); + createLinuxMoveTests(10, 0, "Move revert"); + createLinuxMoveTests(10, 10, "Move repeat"); + + new ResizeMoveTest( + [{ screenX: 10 }, { screenY: 10 }, { screenX: 20 }], + /* aInstant */ true, + "Move sequence", + /* aWaitForCompletion */ true + ); + + new ResizeMoveTest( + [{ screenX: 10 }, { screenY: 10 }, { screenX: 20 }], + /* aInstant */ false, + "Move sequence", + /* aWaitForCompletion */ true + ); +} diff --git a/browser/base/content/test/popups/browser_popup_linux_resize.js b/browser/base/content/test/popups/browser_popup_linux_resize.js new file mode 100644 index 0000000000..6917c5823d --- /dev/null +++ b/browser/base/content/test/popups/browser_popup_linux_resize.js @@ -0,0 +1,53 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function createLinuxResizeTests(aFirstValue, aSecondValue, aMsg) { + for (let prop of ResizeMoveTest.PropInfo.sizeProps) { + // For e.g 'outerWidth' this will be 'innerWidth'. + let otherProp = ResizeMoveTest.PropInfo.crossBoundsMapping[prop]; + let first = {}; + first[prop] = aFirstValue; + let second = {}; + second[otherProp] = aSecondValue; + new ResizeMoveTest( + [first, second], + /* aInstant */ true, + `${aMsg} ${prop},${otherProp}` + ); + new ResizeMoveTest( + [first, second], + /* aInstant */ false, + `${aMsg} ${prop},${otherProp}` + ); + } +} + +createLinuxResizeTests(9, 10, "Resize"); +createLinuxResizeTests(10, 0, "Resize revert"); +createLinuxResizeTests(10, 10, "Resize repeat"); + +new ResizeMoveTest( + [ + { outerWidth: 10 }, + { innerHeight: 10 }, + { innerWidth: 20 }, + { outerHeight: 20 }, + { outerWidth: 30 }, + ], + /* aInstant */ true, + "Resize sequence", + /* aWaitForCompletion */ true +); + +new ResizeMoveTest( + [ + { outerWidth: 10 }, + { innerHeight: 10 }, + { innerWidth: 20 }, + { outerHeight: 20 }, + { outerWidth: 30 }, + ], + /* aInstant */ false, + "Resize sequence", + /* aWaitForCompletion */ true +); diff --git a/browser/base/content/test/popups/browser_popup_move.js b/browser/base/content/test/popups/browser_popup_move.js new file mode 100644 index 0000000000..d7d47e12f5 --- /dev/null +++ b/browser/base/content/test/popups/browser_popup_move.js @@ -0,0 +1,6 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +createGenericMoveTests(/* aInstant */ false, "Move"); diff --git a/browser/base/content/test/popups/browser_popup_move_instant.js b/browser/base/content/test/popups/browser_popup_move_instant.js new file mode 100644 index 0000000000..c8a9219d82 --- /dev/null +++ b/browser/base/content/test/popups/browser_popup_move_instant.js @@ -0,0 +1,6 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +createGenericMoveTests(/* aInstant */ true, "Move"); diff --git a/browser/base/content/test/popups/browser_popup_new_window_resize.js b/browser/base/content/test/popups/browser_popup_new_window_resize.js new file mode 100644 index 0000000000..81d3cf5a9a --- /dev/null +++ b/browser/base/content/test/popups/browser_popup_new_window_resize.js @@ -0,0 +1,51 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +add_task(async function test_new_window_resize() { + let tab = await BrowserTestUtils.openNewForegroundTab( + window.gBrowser, + "https://example.net" + ); + + await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { + info("Opening popup."); + let win = this.content.open( + "https://example.net", + "", + "width=200,height=200" + ); + + await ContentTaskUtils.waitForEvent(win, "load"); + + let { outerWidth: initialWidth, outerHeight: initialHeight } = win; + let targetWidth = initialWidth + 100; + let targetHeight = initialHeight + 100; + + let observedOurResizeEvent = false; + let resizeListener = () => { + let { outerWidth: currentWidth, outerHeight: currentHeight } = win; + info(`Resize event for ${currentWidth}x${currentHeight}.`); + if (currentWidth == targetWidth && currentHeight == targetHeight) { + ok(!observedOurResizeEvent, "First time we receive our resize event."); + observedOurResizeEvent = true; + } + }; + win.addEventListener("resize", resizeListener); + win.resizeTo(targetWidth, targetHeight); + + await ContentTaskUtils.waitForCondition( + () => observedOurResizeEvent, + `Waiting for our resize event (${targetWidth}x${targetHeight}).` + ); + + info("Waiting for potentially incoming resize events."); + for (let i = 0; i < 10; i++) { + await new Promise(r => win.requestAnimationFrame(r)); + } + win.removeEventListener("resize", resizeListener); + info("Closing popup."); + win.close(); + }); + + await BrowserTestUtils.removeTab(tab); +}); diff --git a/browser/base/content/test/popups/browser_popup_new_window_size.js b/browser/base/content/test/popups/browser_popup_new_window_size.js new file mode 100644 index 0000000000..5f5d57e31e --- /dev/null +++ b/browser/base/content/test/popups/browser_popup_new_window_size.js @@ -0,0 +1,90 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const baseURL = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" +); + +add_task(async function test_new_window_size() { + let tab = await BrowserTestUtils.openNewForegroundTab( + window.gBrowser, + baseURL + ); + + await SpecialPowers.spawn(tab.linkedBrowser, [], async () => { + info("Opening popup."); + let requestedWidth = 200; + let requestedHeight = 200; + let win = this.content.open( + "popup_size.html", + "", + `width=${requestedWidth},height=${requestedHeight}` + ); + + let loadPromise = ContentTaskUtils.waitForEvent(win, "load"); + + let { innerWidth: preLoadWidth, innerHeight: preLoadHeight } = win; + is(preLoadWidth, requestedWidth, "Width before load event."); + is(preLoadHeight, requestedHeight, "Height before load event."); + + await loadPromise; + + let { innerWidth: postLoadWidth, innerHeight: postLoadHeight } = win; + is(postLoadWidth, requestedWidth, "Width after load event."); + is(postLoadHeight, requestedHeight, "Height after load event."); + + await ContentTaskUtils.waitForCondition( + () => + win.innerWidth == requestedWidth && win.innerHeight == requestedHeight, + "Waiting for window to become request size." + ); + + let { innerWidth: finalWidth, innerHeight: finalHeight } = win; + is(finalWidth, requestedWidth, "Final width."); + is(finalHeight, requestedHeight, "Final height."); + + await SpecialPowers.spawn( + win, + [{ requestedWidth, requestedHeight }], + async input => { + let { initialSize, loadSize } = this.content.wrappedJSObject; + is( + initialSize.width, + input.requestedWidth, + "Content width before load event." + ); + is( + initialSize.height, + input.requestedHeight, + "Content height before load event." + ); + is( + loadSize.width, + input.requestedWidth, + "Content width after load event." + ); + is( + loadSize.height, + input.requestedHeight, + "Content height after load event." + ); + is( + this.content.innerWidth, + input.requestedWidth, + "Content final width." + ); + is( + this.content.innerHeight, + input.requestedHeight, + "Content final height." + ); + } + ); + + info("Closing popup."); + win.close(); + }); + + await BrowserTestUtils.removeTab(tab); +}); diff --git a/browser/base/content/test/popups/browser_popup_resize.js b/browser/base/content/test/popups/browser_popup_resize.js new file mode 100644 index 0000000000..c73ffb58c5 --- /dev/null +++ b/browser/base/content/test/popups/browser_popup_resize.js @@ -0,0 +1,6 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +createGenericResizeTests(9, 10, /* aInstant */ false, "Resize"); diff --git a/browser/base/content/test/popups/browser_popup_resize_instant.js b/browser/base/content/test/popups/browser_popup_resize_instant.js new file mode 100644 index 0000000000..4613e272d6 --- /dev/null +++ b/browser/base/content/test/popups/browser_popup_resize_instant.js @@ -0,0 +1,6 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +createGenericResizeTests(9, 10, /* aInstant */ true, "Resize"); diff --git a/browser/base/content/test/popups/browser_popup_resize_repeat.js b/browser/base/content/test/popups/browser_popup_resize_repeat.js new file mode 100644 index 0000000000..d76f0fd3a2 --- /dev/null +++ b/browser/base/content/test/popups/browser_popup_resize_repeat.js @@ -0,0 +1,6 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +createGenericResizeTests(10, 10, /* aInstant */ false, "Resize repeat"); diff --git a/browser/base/content/test/popups/browser_popup_resize_repeat_instant.js b/browser/base/content/test/popups/browser_popup_resize_repeat_instant.js new file mode 100644 index 0000000000..9870813d87 --- /dev/null +++ b/browser/base/content/test/popups/browser_popup_resize_repeat_instant.js @@ -0,0 +1,6 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +createGenericResizeTests(10, 10, /* aInstant */ true, "Resize repeat"); diff --git a/browser/base/content/test/popups/browser_popup_resize_revert.js b/browser/base/content/test/popups/browser_popup_resize_revert.js new file mode 100644 index 0000000000..e87ef30f69 --- /dev/null +++ b/browser/base/content/test/popups/browser_popup_resize_revert.js @@ -0,0 +1,6 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +createGenericResizeTests(10, 0, /* aInstant */ false, "Resize revert"); diff --git a/browser/base/content/test/popups/browser_popup_resize_revert_instant.js b/browser/base/content/test/popups/browser_popup_resize_revert_instant.js new file mode 100644 index 0000000000..5fa2ce7d5d --- /dev/null +++ b/browser/base/content/test/popups/browser_popup_resize_revert_instant.js @@ -0,0 +1,6 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +createGenericResizeTests(10, 0, /* aInstant */ true, "Resize revert"); diff --git a/browser/base/content/test/popups/head.js b/browser/base/content/test/popups/head.js new file mode 100644 index 0000000000..9e7ca68e66 --- /dev/null +++ b/browser/base/content/test/popups/head.js @@ -0,0 +1,568 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService( + SpecialPowers.Ci.nsIGfxInfo +); + +async function waitForBlockedPopups(numberOfPopups, { doc }) { + let toolbarDoc = doc || document; + let menupopup = toolbarDoc.getElementById("blockedPopupOptions"); + await BrowserTestUtils.waitForCondition(() => { + let popups = menupopup.querySelectorAll("[popupReportIndex]"); + return popups.length == numberOfPopups; + }, `Waiting for ${numberOfPopups} popups`); +} + +/* + * Tests that a sequence of size changes ultimately results in the latest + * requested size. The test also fails when an unexpected window size is + * observed in a resize event. + * + * aPropertyDeltas List of objects where keys describe the name of a window + * property and the values the difference to its initial + * value. + * + * aInstant Issue changes without additional waiting in between. + * + * A brief example of the resutling code that is effectively run for the + * following list of deltas: + * [{outerWidth: 5, outerHeight: 10}, {outerWidth: 10}] + * + * let initialWidth = win.outerWidth; + * let initialHeight = win.outerHeight; + * + * if (aInstant) { + * win.outerWidth = initialWidth + 5; + * win.outerHeight = initialHeight + 10; + * + * win.outerWidth = initialWidth + 10; + * } else { + * win.requestAnimationFrame(() => { + * win.outerWidth = initialWidth + 5; + * win.outerHeight = initialHeight + 10; + * + * win.requestAnimationFrame(() => { + * win.outerWidth = initialWidth + 10; + * }); + * }); + * } + */ +async function testPropertyDeltas( + aPropertyDeltas, + aInstant, + aPropInfo, + aMsg, + aWaitForCompletion +) { + let msg = `[${aMsg}]`; + + let win = this.content.popup || this.content.wrappedJSObject; + + // Property names and mapping from ResizeMoveTest + let { + sizeProps, + positionProps /* can be empty/incomplete as workaround on Linux */, + readonlyProps, + crossBoundsMapping, + } = aPropInfo; + + let stringifyState = state => { + let stateMsg = sizeProps + .concat(positionProps) + .filter(prop => state[prop] !== undefined) + .map(prop => `${prop}: ${state[prop]}`) + .join(", "); + return `{ ${stateMsg} }`; + }; + + let initialState = {}; + let finalState = {}; + + info("Initializing all values to current state."); + for (let prop of sizeProps.concat(positionProps)) { + let value = win[prop]; + initialState[prop] = value; + finalState[prop] = value; + } + + // List of potential states during resize events. The current state is also + // considered valid, as the resize event might still be outstanding. + let validResizeStates = [initialState]; + + let updateFinalState = (aProp, aDelta) => { + if ( + readonlyProps.includes(aProp) || + !sizeProps.concat(positionProps).includes(aProp) + ) { + throw new Error(`Unexpected property "${aProp}".`); + } + + // Update both properties of the same axis. + let otherProp = crossBoundsMapping[aProp]; + finalState[aProp] = initialState[aProp] + aDelta; + finalState[otherProp] = initialState[otherProp] + aDelta; + + // Mark size as valid in resize event. + if (sizeProps.includes(aProp)) { + let state = {}; + sizeProps.forEach(p => (state[p] = finalState[p])); + validResizeStates.push(state); + } + }; + + info("Adding resize event listener."); + let resizeCount = 0; + let resizeListener = evt => { + resizeCount++; + + let currentSizeState = {}; + sizeProps.forEach(p => (currentSizeState[p] = win[p])); + + info( + `${msg} ${resizeCount}. resize event: ${stringifyState(currentSizeState)}` + ); + let matchingIndex = validResizeStates.findIndex(state => + sizeProps.every(p => state[p] == currentSizeState[p]) + ); + if (matchingIndex < 0) { + info(`${msg} Size state should have been one of:`); + for (let state of validResizeStates) { + info(stringifyState(state)); + } + } + + if (win.gBrowser && evt.target != win) { + // Without e10s we receive content resize events in chrome windows. + todo(false, `${msg} Resize event target is our window.`); + return; + } + + Assert.greaterOrEqual( + matchingIndex, + 0, + `${msg} Valid intermediate state. Current: ` + + stringifyState(currentSizeState) + ); + + // No longer allow current and preceding states. + validResizeStates.splice(0, matchingIndex + 1); + }; + win.addEventListener("resize", resizeListener); + + info("Starting property changes."); + await new Promise(resolve => { + let index = 0; + let next = async () => { + let pre = `${msg} [${index + 1}/${aPropertyDeltas.length}]`; + + let deltaObj = aPropertyDeltas[index]; + for (let prop in deltaObj) { + updateFinalState(prop, deltaObj[prop]); + + let targetValue = initialState[prop] + deltaObj[prop]; + info(`${pre} Setting ${prop} to ${targetValue}.`); + if (sizeProps.includes(prop)) { + win.resizeTo(finalState.outerWidth, finalState.outerHeight); + } else { + win.moveTo(finalState.screenX, finalState.screenY); + } + if (aWaitForCompletion) { + await ContentTaskUtils.waitForCondition( + () => win[prop] == targetValue, + `${msg} Waiting for ${prop} to be ${targetValue}.` + ); + } + } + + index++; + if (index < aPropertyDeltas.length) { + scheduleNext(); + } else { + resolve(); + } + }; + + let scheduleNext = () => { + if (aInstant) { + next(); + } else { + info(`${msg} Requesting animation frame.`); + win.requestAnimationFrame(next); + } + }; + scheduleNext(); + }); + + try { + info(`${msg} Waiting for window to match the final state.`); + await ContentTaskUtils.waitForCondition( + () => sizeProps.concat(positionProps).every(p => win[p] == finalState[p]), + "Waiting for final state." + ); + } catch (e) {} + + info(`${msg} Checking final state.`); + info(`${msg} Exepected: ${stringifyState(finalState)}`); + info(`${msg} Actual: ${stringifyState(win)}`); + for (let prop of sizeProps.concat(positionProps)) { + is(win[prop], finalState[prop], `${msg} Expected final value for ${prop}`); + } + + win.removeEventListener("resize", resizeListener); +} + +function roundedCenter(aDimension, aOrigin) { + let center = aOrigin + Math.floor(aDimension / 2); + return center - (center % 100); +} + +class ResizeMoveTest { + static WindowWidth = 200; + static WindowHeight = 200; + static WindowLeft = roundedCenter(screen.availWidth - 200, screen.left); + static WindowTop = roundedCenter(screen.availHeight - 200, screen.top); + + static PropInfo = { + sizeProps: ["outerWidth", "outerHeight", "innerWidth", "innerHeight"], + positionProps: [ + "screenX", + "screenY", + /* readonly */ "mozInnerScreenX", + /* readonly */ "mozInnerScreenY", + ], + readonlyProps: ["mozInnerScreenX", "mozInnerScreenY"], + crossAxisMapping: { + outerWidth: "outerHeight", + outerHeight: "outerWidth", + innerWidth: "innerHeight", + innerHeight: "innerWidth", + screenX: "screenY", + screenY: "screenX", + mozInnerScreenX: "mozInnerScreenY", + mozInnerScreenY: "mozInnerScreenX", + }, + crossBoundsMapping: { + outerWidth: "innerWidth", + outerHeight: "innerHeight", + innerWidth: "outerWidth", + innerHeight: "outerHeight", + screenX: "mozInnerScreenX", + screenY: "mozInnerScreenY", + mozInnerScreenX: "screenX", + mozInnerScreenY: "screenY", + }, + }; + + constructor( + aPropertyDeltas, + aInstant = false, + aMsg = "ResizeMoveTest", + aWaitForCompletion = false + ) { + this.propertyDeltas = aPropertyDeltas; + this.instant = aInstant; + this.msg = aMsg; + this.waitForCompletion = aWaitForCompletion; + + // Allows to ignore positions while testing. + this.ignorePositions = false; + // Allows to ignore only mozInnerScreenX/Y properties while testing. + this.ignoreMozInnerScreen = false; + // Allows to skip checking the restored position after testing. + this.ignoreRestoredPosition = false; + + if (AppConstants.platform == "linux" && !SpecialPowers.isHeadless) { + // We can occasionally start the test while nsWindow reports a wrong + // client offset (gdk origin and root_origin are out of sync). This + // results in false expectations for the final mozInnerScreenX/Y values. + this.ignoreMozInnerScreen = !ResizeMoveTest.hasCleanUpTask; + + let { positionProps } = ResizeMoveTest.PropInfo; + let resizeOnlyTest = aPropertyDeltas.every(deltaObj => + positionProps.every(prop => deltaObj[prop] === undefined) + ); + + let isWayland = gfxInfo.windowProtocol == "wayland"; + if (resizeOnlyTest && isWayland) { + // On Wayland we can't move the window in general. The window also + // doesn't necessarily open our specified position. + this.ignoreRestoredPosition = true; + // We can catch bad screenX/Y at the start of the first test in a + // window. + this.ignorePositions = !ResizeMoveTest.hasCleanUpTask; + } + } + + if (!ResizeMoveTest.hasCleanUpTask) { + ResizeMoveTest.hasCleanUpTask = true; + registerCleanupFunction(ResizeMoveTest.Cleanup); + } + + add_task(async () => { + let tab = await ResizeMoveTest.GetOrCreateTab(); + let browsingContext = + await ResizeMoveTest.GetOrCreatePopupBrowsingContext(); + if (!browsingContext) { + return; + } + + info("=== Running in content. ==="); + await this.run(browsingContext, `${this.msg} (content)`); + await this.restorePopupState(browsingContext); + + info("=== Running in chrome. ==="); + let popupChrome = browsingContext.topChromeWindow; + await this.run(popupChrome.browsingContext, `${this.msg} (chrome)`); + await this.restorePopupState(browsingContext); + + info("=== Running in opener. ==="); + await this.run(tab.linkedBrowser, `${this.msg} (opener)`); + await this.restorePopupState(browsingContext); + }); + } + + async run(aBrowsingContext, aMsg) { + let testType = this.instant ? "instant" : "fanned out"; + let msg = `${aMsg} (${testType})`; + + let propInfo = {}; + for (let k in ResizeMoveTest.PropInfo) { + propInfo[k] = ResizeMoveTest.PropInfo[k]; + } + if (this.ignoreMozInnerScreen) { + todo(false, `[${aMsg}] Shouldn't ignore mozInnerScreenX/Y.`); + propInfo.positionProps = propInfo.positionProps.filter( + prop => !["mozInnerScreenX", "mozInnerScreenY"].includes(prop) + ); + } + if (this.ignorePositions) { + todo(false, `[${aMsg}] Shouldn't ignore position.`); + propInfo.positionProps = []; + } + + info(`${msg}: ` + JSON.stringify(this.propertyDeltas)); + await SpecialPowers.spawn( + aBrowsingContext, + [ + this.propertyDeltas, + this.instant, + propInfo, + msg, + this.waitForCompletion, + ], + testPropertyDeltas + ); + } + + async restorePopupState(aBrowsingContext) { + info("Restore popup state."); + + let { deltaWidth, deltaHeight } = await SpecialPowers.spawn( + aBrowsingContext, + [], + () => { + return { + deltaWidth: this.content.outerWidth - this.content.innerWidth, + deltaHeight: this.content.outerHeight - this.content.innerHeight, + }; + } + ); + + let chromeWindow = aBrowsingContext.topChromeWindow; + let { + WindowLeft: left, + WindowTop: top, + WindowWidth: width, + WindowHeight: height, + } = ResizeMoveTest; + + chromeWindow.resizeTo(width + deltaWidth, height + deltaHeight); + chromeWindow.moveTo(left, top); + + await SpecialPowers.spawn( + aBrowsingContext, + [left, top, width, height, this.ignoreRestoredPosition], + async (aLeft, aTop, aWidth, aHeight, aIgnorePosition) => { + let win = this.content.wrappedJSObject; + + info("Waiting for restored size."); + await ContentTaskUtils.waitForCondition( + () => win.innerWidth == aWidth && win.innerHeight === aHeight, + "Waiting for restored size." + ); + is(win.innerWidth, aWidth, "Restored width."); + is(win.innerHeight, aHeight, "Restored height."); + + if (!aIgnorePosition) { + info("Waiting for restored position."); + await ContentTaskUtils.waitForCondition( + () => win.screenX == aLeft && win.screenY === aTop, + "Waiting for restored position." + ); + is(win.screenX, aLeft, "Restored screenX."); + is(win.screenY, aTop, "Restored screenY."); + } else { + todo(false, "Shouldn't ignore restored position."); + } + } + ); + } + + static async GetOrCreateTab() { + if (ResizeMoveTest.tab) { + return ResizeMoveTest.tab; + } + + info("Opening tab."); + ResizeMoveTest.tab = await BrowserTestUtils.openNewForegroundTab( + window.gBrowser, + "https://example.net/browser/browser/base/content/test/popups/popup_blocker_a.html" + ); + return ResizeMoveTest.tab; + } + + static async GetOrCreatePopupBrowsingContext() { + if (ResizeMoveTest.popupBrowsingContext) { + if (!ResizeMoveTest.popupBrowsingContext.isActive) { + return undefined; + } + return ResizeMoveTest.popupBrowsingContext; + } + + let tab = await ResizeMoveTest.GetOrCreateTab(); + info("Opening popup."); + ResizeMoveTest.popupBrowsingContext = await SpecialPowers.spawn( + tab.linkedBrowser, + [ + ResizeMoveTest.WindowWidth, + ResizeMoveTest.WindowHeight, + ResizeMoveTest.WindowLeft, + ResizeMoveTest.WindowTop, + ], + async (aWidth, aHeight, aLeft, aTop) => { + let win = this.content.open( + this.content.document.location.href, + "_blank", + `left=${aLeft},top=${aTop},width=${aWidth},height=${aHeight}` + ); + this.content.popup = win; + + await new Promise(r => (win.onload = r)); + + return win.browsingContext; + } + ); + + return ResizeMoveTest.popupBrowsingContext; + } + + static async Cleanup() { + let browsingContext = ResizeMoveTest.popupBrowsingContext; + if (browsingContext) { + await SpecialPowers.spawn(browsingContext, [], () => { + this.content.close(); + }); + delete ResizeMoveTest.popupBrowsingContext; + } + + let tab = ResizeMoveTest.tab; + if (tab) { + await BrowserTestUtils.removeTab(tab); + delete ResizeMoveTest.tab; + } + ResizeMoveTest.hasCleanUpTask = false; + } +} + +function chaosRequestLongerTimeout(aDoRequest) { + if (aDoRequest && parseInt(Services.env.get("MOZ_CHAOSMODE"), 16)) { + requestLongerTimeout(2); + } +} + +function createGenericResizeTests(aFirstValue, aSecondValue, aInstant, aMsg) { + // Runtime almost doubles in chaos mode on Mac. + chaosRequestLongerTimeout(AppConstants.platform == "macosx"); + + let { crossBoundsMapping, crossAxisMapping } = ResizeMoveTest.PropInfo; + + for (let prop of ["innerWidth", "outerHeight"]) { + // Mixing inner and outer property. + for (let secondProp of [prop, crossBoundsMapping[prop]]) { + let first = {}; + first[prop] = aFirstValue; + let second = {}; + second[secondProp] = aSecondValue; + new ResizeMoveTest( + [first, second], + aInstant, + `${aMsg} ${prop},${secondProp}` + ); + } + } + + for (let prop of ["innerHeight", "outerWidth"]) { + let first = {}; + first[prop] = aFirstValue; + let second = {}; + second[prop] = aSecondValue; + + // Setting property of other axis before/between two changes. + let otherProps = [ + crossAxisMapping[prop], + crossAxisMapping[crossBoundsMapping[prop]], + ]; + for (let interferenceProp of otherProps) { + let interference = {}; + interference[interferenceProp] = 20; + new ResizeMoveTest( + [first, interference, second], + aInstant, + `${aMsg} ${prop},${interferenceProp},${prop}` + ); + new ResizeMoveTest( + [interference, first, second], + aInstant, + `${aMsg} ${interferenceProp},${prop},${prop}` + ); + } + } +} + +function createGenericMoveTests(aInstant, aMsg) { + // Runtime almost doubles in chaos mode on Mac. + chaosRequestLongerTimeout(AppConstants.platform == "macosx"); + + let { crossAxisMapping } = ResizeMoveTest.PropInfo; + + for (let prop of ["screenX", "screenY"]) { + for (let [v1, v2, msg] of [ + [9, 10, `${aMsg}`], + [11, 11, `${aMsg} repeat`], + [12, 0, `${aMsg} revert`], + ]) { + let first = {}; + first[prop] = v1; + let second = {}; + second[prop] = v2; + new ResizeMoveTest([first, second], aInstant, `${msg} ${prop},${prop}`); + + let interferenceProp = crossAxisMapping[prop]; + let interference = {}; + interference[interferenceProp] = 20; + new ResizeMoveTest( + [first, interference, second], + aInstant, + `${aMsg} ${prop},${interferenceProp},${prop}` + ); + new ResizeMoveTest( + [interference, first, second], + aInstant, + `${msg} ${interferenceProp},${prop},${prop}` + ); + } + } +} diff --git a/browser/base/content/test/popups/popup_blocker.html b/browser/base/content/test/popups/popup_blocker.html new file mode 100644 index 0000000000..8e2d958059 --- /dev/null +++ b/browser/base/content/test/popups/popup_blocker.html @@ -0,0 +1,13 @@ +<!doctype html> +<html> + <head> + <meta charset="UTF-8"> + <title>Page creating two popups</title> + </head> + <body> + <script type="text/javascript"> + window.open("popup_blocker_a.html", "a"); + window.open("popup_blocker_b.html", "b"); + </script> + </body> +</html> diff --git a/browser/base/content/test/popups/popup_blocker2.html b/browser/base/content/test/popups/popup_blocker2.html new file mode 100644 index 0000000000..ec880c0821 --- /dev/null +++ b/browser/base/content/test/popups/popup_blocker2.html @@ -0,0 +1,10 @@ +<!doctype html> +<html> + <head> + <meta charset="UTF-8"> + <title>Page creating a popup</title> + </head> + <body> + <button id="pop" onclick='window.setTimeout(() => {window.open("popup_blocker_a.html", "a");}, 10);'>Open Popup</button> + </body> +</html> diff --git a/browser/base/content/test/popups/popup_blocker_10_popups.html b/browser/base/content/test/popups/popup_blocker_10_popups.html new file mode 100644 index 0000000000..9dc288f472 --- /dev/null +++ b/browser/base/content/test/popups/popup_blocker_10_popups.html @@ -0,0 +1,14 @@ +<!doctype html> +<html> + <head> + <meta charset="UTF-8"> + <title>Page creating ten popups</title> + </head> + <body> + <script type="text/javascript"> + for (let i = 0; i < 10; i++) { + window.open("https://example.com"); + } + </script> + </body> +</html> diff --git a/browser/base/content/test/popups/popup_blocker_a.html b/browser/base/content/test/popups/popup_blocker_a.html new file mode 100644 index 0000000000..b6f94b5b26 --- /dev/null +++ b/browser/base/content/test/popups/popup_blocker_a.html @@ -0,0 +1 @@ +<html><body>a</body></html> diff --git a/browser/base/content/test/popups/popup_blocker_b.html b/browser/base/content/test/popups/popup_blocker_b.html new file mode 100644 index 0000000000..954061e2ce --- /dev/null +++ b/browser/base/content/test/popups/popup_blocker_b.html @@ -0,0 +1 @@ +<html><body>b</body></html> diff --git a/browser/base/content/test/popups/popup_blocker_frame.html b/browser/base/content/test/popups/popup_blocker_frame.html new file mode 100644 index 0000000000..e29452fb63 --- /dev/null +++ b/browser/base/content/test/popups/popup_blocker_frame.html @@ -0,0 +1,27 @@ +<!doctype html> +<html> + <head> + <meta charset="UTF-8"> + <title>Page with iframe that contains page that opens two popups</title> + </head> + <body> + <iframe id="iframe"></iframe> + <script type="text/javascript"> + let params = new URLSearchParams(location.search); + let base = params.get('base') || location.href; + let frame = document.getElementById('iframe'); + + function addPopupOpeningFrame() { + frame.src = new URL("popup_blocker.html", base); + } + + if (params.get('delayed') !== 'true') { + addPopupOpeningFrame(); + } else { + addEventListener("message", () => { + addPopupOpeningFrame(); + }, {once: true}); + } + </script> + </body> +</html> diff --git a/browser/base/content/test/popups/popup_size.html b/browser/base/content/test/popups/popup_size.html new file mode 100644 index 0000000000..c214486dee --- /dev/null +++ b/browser/base/content/test/popups/popup_size.html @@ -0,0 +1,16 @@ +<!doctype html> +<html> + <head> + <meta charset="UTF-8"> + <title>Page recording its size</title> + </head> + <body> + <script> + var initialSize = { width: innerWidth, height: innerHeight }; + var loadSize; + onload = () => { + loadSize = { width: innerWidth, height: innerHeight }; + }; + </script> + </body> +</html> |