From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- .../test/fullscreen/MozDomFullscreen_chrome.xhtml | 108 +++++++ dom/base/test/fullscreen/browser.ini | 40 +++ .../test/fullscreen/browser_fullscreen-api-keys.js | 218 +++++++++++++ .../fullscreen/browser_fullscreen-bug-1798219.js | 127 ++++++++ .../browser_fullscreen-contextmenu-esc.js | 128 ++++++++ ...wser_fullscreen-document-mutation-navigation.js | 141 +++++++++ .../browser_fullscreen-document-mutation-race.js | 122 ++++++++ .../browser_fullscreen-document-mutation.js | 118 +++++++ .../browser_fullscreen-navigation-history.js | 100 ++++++ .../browser_fullscreen-navigation-race.js | 162 ++++++++++ .../fullscreen/browser_fullscreen-navigation.js | 142 +++++++++ .../test/fullscreen/browser_fullscreen-newtab.js | 91 ++++++ .../test/fullscreen/browser_fullscreen-sizemode.js | 225 ++++++++++++++ .../browser_fullscreen-tab-close-race.js | 101 ++++++ .../fullscreen/browser_fullscreen-tab-close.js | 65 ++++ .../browser_fullscreen-window-open-race.js | 73 +++++ ...browser_fullscreen_exit_on_external_protocol.js | 215 +++++++++++++ dom/base/test/fullscreen/chrome.ini | 10 + dom/base/test/fullscreen/dummy_page.html | 10 + .../test/fullscreen/file_MozDomFullscreen.html | 8 + .../test/fullscreen/file_fullscreen-api-keys.html | 41 +++ .../test/fullscreen/file_fullscreen-api-race.html | 8 + dom/base/test/fullscreen/file_fullscreen-api.html | 340 +++++++++++++++++++++ .../test/fullscreen/file_fullscreen-async.html | 50 +++ .../test/fullscreen/file_fullscreen-backdrop.html | 107 +++++++ .../fullscreen/file_fullscreen-bug-1798219-2.html | 22 ++ .../fullscreen/file_fullscreen-bug-1798219.html | 14 + .../fullscreen/file_fullscreen-denied-inner.html | 24 ++ .../test/fullscreen/file_fullscreen-denied.html | 171 +++++++++++ .../fullscreen/file_fullscreen-esc-exit-inner.html | 58 ++++ .../test/fullscreen/file_fullscreen-esc-exit.html | 63 ++++ .../fullscreen/file_fullscreen-event-order.html | 50 +++ .../file_fullscreen-featurePolicy-inner.html | 34 +++ .../fullscreen/file_fullscreen-featurePolicy.html | 90 ++++++ .../fullscreen/file_fullscreen-focus-inner.html | 24 ++ .../test/fullscreen/file_fullscreen-focus.html | 67 ++++ .../test/fullscreen/file_fullscreen-hidden.html | 56 ++++ .../fullscreen/file_fullscreen-iframe-inner.html | 5 + .../fullscreen/file_fullscreen-iframe-middle.html | 5 + .../fullscreen/file_fullscreen-iframe-top.html | 5 + .../file_fullscreen-lenient-setters.html | 61 ++++ .../fullscreen/file_fullscreen-multiple-inner.html | 25 ++ .../test/fullscreen/file_fullscreen-multiple.html | 67 ++++ .../fullscreen/file_fullscreen-navigation.html | 52 ++++ .../test/fullscreen/file_fullscreen-nested.html | 130 ++++++++ .../test/fullscreen/file_fullscreen-newtab.html | 4 + .../test/fullscreen/file_fullscreen-prefixed.html | 153 ++++++++++ .../test/fullscreen/file_fullscreen-resize.html | 39 +++ .../test/fullscreen/file_fullscreen-rollback.html | 140 +++++++++ .../test/fullscreen/file_fullscreen-scrollbar.html | 147 +++++++++ .../test/fullscreen/file_fullscreen-selector.html | 183 +++++++++++ .../test/fullscreen/file_fullscreen-shadowdom.html | 52 ++++ .../test/fullscreen/file_fullscreen-single.html | 78 +++++ .../fullscreen/file_fullscreen-sub-iframe.html | 53 ++++ .../fullscreen/file_fullscreen-svg-element.html | 49 +++ .../test/fullscreen/file_fullscreen-table.html | 52 ++++ .../test/fullscreen/file_fullscreen-top-layer.html | 160 ++++++++++ dom/base/test/fullscreen/file_fullscreen-utils.js | 87 ++++++ .../fullscreen/file_fullscreen-with-full-zoom.html | 36 +++ .../fullscreen/file_fullscreen_meta_viewport.html | 12 + dom/base/test/fullscreen/fullscreen.xhtml | 27 ++ dom/base/test/fullscreen/fullscreen_helpers.js | 174 +++++++++++ dom/base/test/fullscreen/head.js | 65 ++++ dom/base/test/fullscreen/mochitest.ini | 51 ++++ dom/base/test/fullscreen/moz.build | 17 ++ .../fullscreen/test_MozDomFullscreen_event.xhtml | 46 +++ .../test/fullscreen/test_fullscreen-api-race.html | 177 +++++++++++ .../test_fullscreen-api-rapid-cycle.html | 167 ++++++++++ dom/base/test/fullscreen/test_fullscreen-api.html | 150 +++++++++ dom/base/test/fullscreen/test_fullscreen.xhtml | 37 +++ .../fullscreen/test_fullscreen_meta_viewport.html | 33 ++ .../test/fullscreen/test_fullscreen_modal.html | 68 +++++ 72 files changed, 6030 insertions(+) create mode 100644 dom/base/test/fullscreen/MozDomFullscreen_chrome.xhtml create mode 100644 dom/base/test/fullscreen/browser.ini create mode 100644 dom/base/test/fullscreen/browser_fullscreen-api-keys.js create mode 100644 dom/base/test/fullscreen/browser_fullscreen-bug-1798219.js create mode 100644 dom/base/test/fullscreen/browser_fullscreen-contextmenu-esc.js create mode 100644 dom/base/test/fullscreen/browser_fullscreen-document-mutation-navigation.js create mode 100644 dom/base/test/fullscreen/browser_fullscreen-document-mutation-race.js create mode 100644 dom/base/test/fullscreen/browser_fullscreen-document-mutation.js create mode 100644 dom/base/test/fullscreen/browser_fullscreen-navigation-history.js create mode 100644 dom/base/test/fullscreen/browser_fullscreen-navigation-race.js create mode 100644 dom/base/test/fullscreen/browser_fullscreen-navigation.js create mode 100644 dom/base/test/fullscreen/browser_fullscreen-newtab.js create mode 100644 dom/base/test/fullscreen/browser_fullscreen-sizemode.js create mode 100644 dom/base/test/fullscreen/browser_fullscreen-tab-close-race.js create mode 100644 dom/base/test/fullscreen/browser_fullscreen-tab-close.js create mode 100644 dom/base/test/fullscreen/browser_fullscreen-window-open-race.js create mode 100644 dom/base/test/fullscreen/browser_fullscreen_exit_on_external_protocol.js create mode 100644 dom/base/test/fullscreen/chrome.ini create mode 100644 dom/base/test/fullscreen/dummy_page.html create mode 100644 dom/base/test/fullscreen/file_MozDomFullscreen.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-api-keys.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-api-race.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-api.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-async.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-backdrop.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-bug-1798219-2.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-bug-1798219.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-denied-inner.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-denied.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-esc-exit-inner.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-esc-exit.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-event-order.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-featurePolicy-inner.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-featurePolicy.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-focus-inner.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-focus.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-hidden.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-iframe-inner.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-iframe-middle.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-iframe-top.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-lenient-setters.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-multiple-inner.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-multiple.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-navigation.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-nested.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-newtab.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-prefixed.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-resize.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-rollback.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-scrollbar.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-selector.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-shadowdom.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-single.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-sub-iframe.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-svg-element.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-table.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-top-layer.html create mode 100644 dom/base/test/fullscreen/file_fullscreen-utils.js create mode 100644 dom/base/test/fullscreen/file_fullscreen-with-full-zoom.html create mode 100644 dom/base/test/fullscreen/file_fullscreen_meta_viewport.html create mode 100644 dom/base/test/fullscreen/fullscreen.xhtml create mode 100644 dom/base/test/fullscreen/fullscreen_helpers.js create mode 100644 dom/base/test/fullscreen/head.js create mode 100644 dom/base/test/fullscreen/mochitest.ini create mode 100644 dom/base/test/fullscreen/moz.build create mode 100644 dom/base/test/fullscreen/test_MozDomFullscreen_event.xhtml create mode 100644 dom/base/test/fullscreen/test_fullscreen-api-race.html create mode 100644 dom/base/test/fullscreen/test_fullscreen-api-rapid-cycle.html create mode 100644 dom/base/test/fullscreen/test_fullscreen-api.html create mode 100644 dom/base/test/fullscreen/test_fullscreen.xhtml create mode 100644 dom/base/test/fullscreen/test_fullscreen_meta_viewport.html create mode 100644 dom/base/test/fullscreen/test_fullscreen_modal.html (limited to 'dom/base/test/fullscreen') diff --git a/dom/base/test/fullscreen/MozDomFullscreen_chrome.xhtml b/dom/base/test/fullscreen/MozDomFullscreen_chrome.xhtml new file mode 100644 index 0000000000..93f00311e7 --- /dev/null +++ b/dom/base/test/fullscreen/MozDomFullscreen_chrome.xhtml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + diff --git a/dom/base/test/fullscreen/browser.ini b/dom/base/test/fullscreen/browser.ini new file mode 100644 index 0000000000..c472e09b5c --- /dev/null +++ b/dom/base/test/fullscreen/browser.ini @@ -0,0 +1,40 @@ +[DEFAULT] +tags = fullscreen +head = head.js +support-files = + dummy_page.html + file_fullscreen-api-keys.html + file_fullscreen-iframe-inner.html + file_fullscreen-iframe-middle.html + file_fullscreen-iframe-top.html + file_fullscreen-newtab.html + fullscreen_helpers.js + +[browser_fullscreen-api-keys.js] +[browser_fullscreen-document-mutation.js] +[browser_fullscreen-document-mutation-navigation.js] +[browser_fullscreen-document-mutation-race.js] +[browser_fullscreen-contextmenu-esc.js] +[browser_fullscreen-navigation.js] +skip-if = + os == "win" && os_version == "6.1" # Skip on Azure - frequent failure +[browser_fullscreen-navigation-history.js] +[browser_fullscreen-navigation-race.js] +[browser_fullscreen-newtab.js] +skip-if = + os == 'mac' # Bug 1494843 + os == 'linux' && bits == 64 && os_version == '18.04' # Bug 1601460 + os == "win" && os_version == "6.1" # Skip on Azure - frequent failure +[browser_fullscreen-tab-close.js] +[browser_fullscreen-tab-close-race.js] +skip-if = !fission # Bug 1750901 +[browser_fullscreen-bug-1798219.js] +skip-if = + !fission + !nightly_build # Bug 1818608 +support-files = + file_fullscreen-bug-1798219.html + file_fullscreen-bug-1798219-2.html +[browser_fullscreen-window-open-race.js] +[browser_fullscreen-sizemode.js] +[browser_fullscreen_exit_on_external_protocol.js] diff --git a/dom/base/test/fullscreen/browser_fullscreen-api-keys.js b/dom/base/test/fullscreen/browser_fullscreen-api-keys.js new file mode 100644 index 0000000000..1b1a07975e --- /dev/null +++ b/dom/base/test/fullscreen/browser_fullscreen-api-keys.js @@ -0,0 +1,218 @@ +"use strict"; + +// This test tends to trigger a race in the fullscreen time telemetry, +// where the fullscreen enter and fullscreen exit events (which use the +// same histogram ID) overlap. That causes TelemetryStopwatch to log an +// error. +SimpleTest.ignoreAllUncaughtExceptions(true); + +/** Test for Bug 545812 **/ + +// List of key codes which should exit full-screen mode. +const kKeyList = [ + { key: "Escape", keyCode: "VK_ESCAPE", suppressed: true }, + { key: "F11", keyCode: "VK_F11", suppressed: false }, +]; + +function receiveExpectedKeyEvents(aBrowser, aKeyCode, aTrusted) { + return SpecialPowers.spawn( + aBrowser, + [aKeyCode, aTrusted], + (keyCode, trusted) => { + return new Promise(resolve => { + let events = trusted + ? ["keydown", "keyup"] + : ["keydown", "keypress", "keyup"]; + if (trusted && keyCode == content.wrappedJSObject.KeyEvent.DOM_VK_F11) { + // trusted `F11` key shouldn't be fired because of reserved when it's + // a shortcut key for exiting from the full screen mode. + events.shift(); + } + function listener(event) { + let expected = events.shift(); + Assert.equal( + event.type, + expected, + `Should receive a ${expected} event` + ); + Assert.equal( + event.keyCode, + keyCode, + `Should receive the event with key code ${keyCode}` + ); + if (!events.length) { + content.document.removeEventListener("keydown", listener, true); + content.document.removeEventListener("keyup", listener, true); + content.document.removeEventListener("keypress", listener, true); + resolve(); + } + } + + content.document.addEventListener("keydown", listener, true); + content.document.addEventListener("keyup", listener, true); + content.document.addEventListener("keypress", listener, true); + }); + } + ); +} + +const kPage = + "https://example.org/browser/" + + "dom/base/test/fullscreen/file_fullscreen-api-keys.html"; + +add_task(async function () { + await pushPrefs( + ["full-screen-api.transition-duration.enter", "0 0"], + ["full-screen-api.transition-duration.leave", "0 0"] + ); + + let tab = BrowserTestUtils.addTab(gBrowser, kPage); + let browser = tab.linkedBrowser; + gBrowser.selectedTab = tab; + registerCleanupFunction(() => gBrowser.removeTab(tab)); + await waitForDocLoadComplete(); + + // Wait for the document being activated, so that + // fullscreen request won't be denied. + await SpecialPowers.spawn(browser, [], () => { + return ContentTaskUtils.waitForCondition( + () => content.browsingContext.isActive && content.document.hasFocus(), + "document is active" + ); + }); + + // Register listener to capture unexpected events + let keyEventsCount = 0; + let fullScreenEventsCount = 0; + let removeFullScreenListener = BrowserTestUtils.addContentEventListener( + browser, + "fullscreenchange", + () => fullScreenEventsCount++ + ); + let removeKeyDownListener = BrowserTestUtils.addContentEventListener( + browser, + "keydown", + () => keyEventsCount++, + { wantUntrusted: true } + ); + let removeKeyPressListener = BrowserTestUtils.addContentEventListener( + browser, + "keypress", + () => keyEventsCount++, + { wantUntrusted: true } + ); + let removeKeyUpListener = BrowserTestUtils.addContentEventListener( + browser, + "keyup", + () => keyEventsCount++, + { wantUntrusted: true } + ); + + let expectedFullScreenEventsCount = 0; + let expectedKeyEventsCount = 0; + + for (let { key, keyCode, suppressed } of kKeyList) { + let keyCodeValue = KeyEvent["DOM_" + keyCode]; + info(`Test keycode ${key} (${keyCodeValue})`); + + info("Enter fullscreen"); + let state = new Promise(resolve => { + let removeFun = BrowserTestUtils.addContentEventListener( + browser, + "fullscreenchange", + async () => { + removeFun(); + resolve( + await SpecialPowers.spawn(browser, [], () => { + return !!content.document.fullscreenElement; + }) + ); + } + ); + }); + // request fullscreen + SpecialPowers.spawn(browser, [], () => { + content.document.body.requestFullscreen(); + }); + ok(await state, "The content should have entered fullscreen"); + ok(document.fullscreenElement, "The chrome should also be in fullscreen"); + + is( + fullScreenEventsCount, + ++expectedFullScreenEventsCount, + "correct number of fullscreen events occurred" + ); + + info("Dispatch untrusted key events from content"); + let promiseExpectedKeyEvents = receiveExpectedKeyEvents( + browser, + keyCodeValue, + false + ); + + SpecialPowers.spawn(browser, [keyCode], keyCodeChild => { + var evt = new content.CustomEvent("Test:DispatchKeyEvents", { + detail: Cu.cloneInto({ code: keyCodeChild }, content), + }); + content.dispatchEvent(evt); + }); + await promiseExpectedKeyEvents; + + expectedKeyEventsCount += 3; + is( + keyEventsCount, + expectedKeyEventsCount, + "correct number of key events occurred" + ); + + info("Send trusted key events"); + + state = new Promise(resolve => { + let removeFun = BrowserTestUtils.addContentEventListener( + browser, + "fullscreenchange", + async () => { + removeFun(); + resolve( + await SpecialPowers.spawn(browser, [], () => { + return !!content.document.fullscreenElement; + }) + ); + } + ); + }); + + promiseExpectedKeyEvents = suppressed + ? Promise.resolve() + : receiveExpectedKeyEvents(browser, keyCodeValue, true); + await SpecialPowers.spawn(browser, [], () => {}); + + EventUtils.synthesizeKey("KEY_" + key); + await promiseExpectedKeyEvents; + + ok(!(await state), "The content should have exited fullscreen"); + ok( + !document.fullscreenElement, + "The chrome should also have exited fullscreen" + ); + + is( + fullScreenEventsCount, + ++expectedFullScreenEventsCount, + "correct number of fullscreen events occurred" + ); + if (!suppressed) { + expectedKeyEventsCount += keyCode == "VK_F11" ? 1 : 3; + } + is( + keyEventsCount, + expectedKeyEventsCount, + "correct number of key events occurred" + ); + } + + removeFullScreenListener(); + removeKeyDownListener(); + removeKeyPressListener(); + removeKeyUpListener(); +}); diff --git a/dom/base/test/fullscreen/browser_fullscreen-bug-1798219.js b/dom/base/test/fullscreen/browser_fullscreen-bug-1798219.js new file mode 100644 index 0000000000..2aef23b042 --- /dev/null +++ b/dom/base/test/fullscreen/browser_fullscreen-bug-1798219.js @@ -0,0 +1,127 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Import helpers +/* import-globals-from fullscreen_helpers.js */ +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js", + this +); + +// This test tends to trigger a race in the fullscreen time telemetry, +// where the fullscreen enter and fullscreen exit events (which use the +// same histogram ID) overlap. That causes TelemetryStopwatch to log an +// error, https://bugzilla.mozilla.org/show_bug.cgi?id=1742890. +SimpleTest.ignoreAllUncaughtExceptions(true); + +add_setup(async function () { + await pushPrefs( + ["full-screen-api.transition-duration.enter", "0 0"], + ["full-screen-api.transition-duration.leave", "0 0"], + ["full-screen-api.allow-trusted-requests-only", false] + ); +}); + +async function waitAndCheckFullscreenState(aWindow) { + // Wait fullscreen exit event if browser is still in fullscreen mode. + if ( + aWindow.fullScreen || + aWindow.document.documentElement.hasAttribute("inFullscreen") + ) { + info("The widget is still in fullscreen, wait again"); + await waitWidgetFullscreenEvent(aWindow, false, true); + } + if (aWindow.document.documentElement.hasAttribute("inDOMFullscreen")) { + info("The chrome document is still in fullscreen, wait again"); + await waitForFullScreenObserver(aWindow, false, true); + } + + // Ensure the browser exits fullscreen state. + ok(!aWindow.fullScreen, "The widget should not be in fullscreen"); + ok( + !aWindow.document.documentElement.hasAttribute("inFullscreen"), + "The chrome window should not be in fullscreen" + ); + ok( + !aWindow.document.documentElement.hasAttribute("inDOMFullscreen"), + "The chrome document should not be in fullscreen" + ); +} + +add_task(async () => { + const URL = + "http://mochi.test:8888/browser/dom/base/test/fullscreen/file_fullscreen-bug-1798219.html"; + // We need this dummy tab which load the same URL as test tab to keep the + // original content process alive after test page navigates away. + let dummyTab = await BrowserTestUtils.openNewForegroundTab(gBrowser, URL); + + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: URL, + }, + async function (browser) { + await SpecialPowers.spawn(browser, [], function () { + content.document.querySelector("button").click(); + }); + + // Test requests fullscreen and performs navigation simultaneously, + // the fullscreen request might be rejected directly if navigation happens + // first, so there might be no reliable state that we can wait. So give + // some time for possible fullscreen transition instead and ensure window + // should end up exiting fullscreen. + await new Promise(aResolve => { + SimpleTest.executeSoon(() => { + SimpleTest.executeSoon(aResolve); + }); + }); + await waitAndCheckFullscreenState(window); + } + ); + + let dummyTabClosed = BrowserTestUtils.waitForTabClosing(dummyTab); + BrowserTestUtils.removeTab(dummyTab); + await dummyTabClosed; +}); + +add_task(async () => { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: "http://mochi.test:8888/browser/dom/base/test/fullscreen/file_fullscreen-bug-1798219-2.html", + }, + async function (browser) { + // Open a new window to run the tests, the original window will keep the + // original content process alive after the test window navigates away. + let promiseWin = BrowserTestUtils.waitForNewWindow(); + await SpecialPowers.spawn(browser, [], function () { + content.document.querySelector("button").click(); + }); + let newWindow = await promiseWin; + + await SpecialPowers.spawn( + newWindow.gBrowser.selectedTab.linkedBrowser, + [], + function () { + content.document.querySelector("button").click(); + } + ); + + // Test requests fullscreen and performs navigation simultaneously, + // the fullscreen request might be rejected directly if navigation happens + // first, so there might be no reliable state that we can wait. So give + // some time for possible fullscreen transition instead and ensure window + // should end up exiting fullscreen. + await new Promise(aResolve => { + SimpleTest.executeSoon(() => { + SimpleTest.executeSoon(aResolve); + }); + }); + await waitAndCheckFullscreenState(newWindow); + + newWindow.close(); + } + ); +}); diff --git a/dom/base/test/fullscreen/browser_fullscreen-contextmenu-esc.js b/dom/base/test/fullscreen/browser_fullscreen-contextmenu-esc.js new file mode 100644 index 0000000000..e89409a90f --- /dev/null +++ b/dom/base/test/fullscreen/browser_fullscreen-contextmenu-esc.js @@ -0,0 +1,128 @@ +"use strict"; + +// This test tends to trigger a race in the fullscreen time telemetry, +// where the fullscreen enter and fullscreen exit events (which use the +// same histogram ID) overlap. That causes TelemetryStopwatch to log an +// error. +SimpleTest.ignoreAllUncaughtExceptions(true); + +function captureUnexpectedFullscreenChange() { + ok(false, "Caught an unexpected fullscreen change"); +} + +const kPage = + "https://example.org/browser/dom/base/test/fullscreen/dummy_page.html"; + +function waitForDocActivated(aBrowser) { + return SpecialPowers.spawn(aBrowser, [], () => { + return ContentTaskUtils.waitForCondition( + () => content.browsingContext.isActive && content.document.hasFocus() + ); + }); +} + +add_task(async function () { + await pushPrefs( + ["full-screen-api.transition-duration.enter", "0 0"], + ["full-screen-api.transition-duration.leave", "0 0"] + ); + + let tab = await BrowserTestUtils.openNewForegroundTab({ + gBrowser, + opening: kPage, + waitForStateStop: true, + }); + let browser = tab.linkedBrowser; + + // As requestFullscreen checks the active state of the docshell, + // wait for the document to be activated, just to be sure that + // the fullscreen request won't be denied. + await SpecialPowers.spawn(browser, [], () => { + return ContentTaskUtils.waitForCondition( + () => content.browsingContext.isActive && content.document.hasFocus() + ); + }); + + let contextMenu = document.getElementById("contentAreaContextMenu"); + ok(contextMenu, "Got context menu"); + + let state; + info("Enter DOM fullscreen"); + let fullScreenChangedPromise = BrowserTestUtils.waitForContentEvent( + browser, + "fullscreenchange" + ); + await SpecialPowers.spawn(browser, [], () => { + content.document.body.requestFullscreen(); + }); + + await fullScreenChangedPromise; + state = await SpecialPowers.spawn(browser, [], () => { + return !!content.document.fullscreenElement; + }); + ok(state, "The content should have entered fullscreen"); + ok(document.fullscreenElement, "The chrome should also be in fullscreen"); + + let removeContentEventListener = BrowserTestUtils.addContentEventListener( + browser, + "fullscreenchange", + captureUnexpectedFullscreenChange + ); + + info("Open context menu"); + is(contextMenu.state, "closed", "Should not have opened context menu"); + + let popupShownPromise = promiseWaitForEvent(window, "popupshown"); + + EventUtils.synthesizeMouse( + browser, + screen.width / 2, + screen.height / 2, + { type: "contextmenu", button: 2 }, + window + ); + await popupShownPromise; + is(contextMenu.state, "open", "Should have opened context menu"); + + let popupHidePromise = promiseWaitForEvent(window, "popuphidden"); + + if ( + !AppConstants.platform == "macosx" || + !Services.prefs.getBoolPref("widget.macos.native-context-menus", false) + ) { + info("Send the first escape"); + EventUtils.synthesizeKey("KEY_Escape"); + } else { + // We cannot synthesize key events at native macOS menus. + // We also do not see key events that are processed by native macOS menus, + // so we cannot accidentally exit fullscreen when the user closes a native + // menu with Escape. + // Close the menu normally. + info("Close the context menu"); + contextMenu.hidePopup(); + } + await popupHidePromise; + is(contextMenu.state, "closed", "Should have closed context menu"); + + // Wait a small time to confirm that the first ESC key + // does not exit fullscreen. + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout + await new Promise(resolve => setTimeout(resolve, 1000)); + state = await SpecialPowers.spawn(browser, [], () => { + return !!content.document.fullscreenElement; + }); + ok(state, "The content should still be in fullscreen"); + ok(document.fullscreenElement, "The chrome should still be in fullscreen"); + + removeContentEventListener(); + info("Send the second escape"); + let fullscreenExitPromise = BrowserTestUtils.waitForContentEvent( + browser, + "fullscreenchange" + ); + EventUtils.synthesizeKey("KEY_Escape"); + await fullscreenExitPromise; + ok(!document.fullscreenElement, "The chrome should have exited fullscreen"); + + gBrowser.removeTab(tab); +}); diff --git a/dom/base/test/fullscreen/browser_fullscreen-document-mutation-navigation.js b/dom/base/test/fullscreen/browser_fullscreen-document-mutation-navigation.js new file mode 100644 index 0000000000..f6b5715f59 --- /dev/null +++ b/dom/base/test/fullscreen/browser_fullscreen-document-mutation-navigation.js @@ -0,0 +1,141 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +requestLongerTimeout(2); + +// Import helpers +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js", + this +); + +// This test tends to trigger a race in the fullscreen time telemetry, +// where the fullscreen enter and fullscreen exit events (which use the +// same histogram ID) overlap. That causes TelemetryStopwatch to log an +// error. +SimpleTest.ignoreAllUncaughtExceptions(true); + +add_setup(async function () { + await pushPrefs( + ["full-screen-api.transition-duration.enter", "0 0"], + ["full-screen-api.transition-duration.leave", "0 0"], + ["full-screen-api.allow-trusted-requests-only", false] + ); +}); + +async function startTests(testFun, name) { + TEST_URLS.forEach(url => { + add_task(async () => { + info(`Test ${name}, url: ${url}`); + await BrowserTestUtils.withNewTab( + { + gBrowser, + url, + }, + async function (browser) { + let promiseFsState = waitForFullscreenState(document, true); + // Trigger click event in inner most iframe + SpecialPowers.spawn( + browser.browsingContext.children[0].children[0], + [], + function () { + content.setTimeout(() => { + content.document.getElementById("div").click(); + }, 0); + } + ); + await promiseFsState; + + // This should exit fullscreen + promiseFsState = waitForFullscreenState(document, false, true); + await testFun(browser); + await promiseFsState; + + // This test triggers a fullscreen request during the fullscreen exit + // process, so it could be possible that the widget or the chrome + // document goes into fullscreen mode again, but they should end up + // leaving fullscreen mode again. + if ( + window.fullScreen || + document.documentElement.hasAttribute("inFullscreen") + ) { + info("widget is still in fullscreen, wait again"); + await waitWidgetFullscreenEvent(window, false, true); + } + if (document.documentElement.hasAttribute("inDOMFullscreen")) { + info("chrome document is still in fullscreen, wait again"); + await waitForFullScreenObserver(document, false, true); + } + + // Ensure the browser exits fullscreen state. + ok(!window.fullScreen, "The widget should not be in fullscreen"); + ok( + !document.documentElement.hasAttribute("inFullscreen"), + "The chrome window should not be in fullscreen" + ); + ok( + !document.documentElement.hasAttribute("inDOMFullscreen"), + "The chrome document should not be in fullscreen" + ); + } + ); + }); + }); +} + +function MutateAndNavigateFromRemoteDocument( + aBrowsingContext, + aElementId, + aURL +) { + return SpecialPowers.spawn( + aBrowsingContext, + [aElementId, aURL], + async function (id, url) { + let element = content.document.getElementById(id); + element.requestFullscreen(); + content.document.body.appendChild(element); + content.location.href = url; + } + ); +} + +startTests(async browser => { + // toplevel + await MutateAndNavigateFromRemoteDocument( + browser.browsingContext, + "div", + "about:blank" + ); +}, "document_mutation_navigation_toplevel"); + +startTests(async browser => { + let promiseRemoteFsState = waitRemoteFullscreenExitEvents([ + // browsingContext, name + [browser.browsingContext, "toplevel"], + ]); + // middle iframe + await MutateAndNavigateFromRemoteDocument( + browser.browsingContext.children[0], + "div", + "about:blank" + ); + await promiseRemoteFsState; +}, "document_mutation_navigation_middle_frame"); + +startTests(async browser => { + let promiseRemoteFsState = waitRemoteFullscreenExitEvents([ + // browsingContext, name + [browser.browsingContext, "toplevel"], + [browser.browsingContext.children[0], "middle"], + ]); + // innermost iframe + await MutateAndNavigateFromRemoteDocument( + browser.browsingContext.children[0].children[0], + "div", + "about:blank" + ); + await promiseRemoteFsState; +}, "document_mutation_navigation_inner_frame"); diff --git a/dom/base/test/fullscreen/browser_fullscreen-document-mutation-race.js b/dom/base/test/fullscreen/browser_fullscreen-document-mutation-race.js new file mode 100644 index 0000000000..75ca199aaa --- /dev/null +++ b/dom/base/test/fullscreen/browser_fullscreen-document-mutation-race.js @@ -0,0 +1,122 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +requestLongerTimeout(2); + +// Import helpers +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js", + this +); + +// This test tends to trigger a race in the fullscreen time telemetry, +// where the fullscreen enter and fullscreen exit events (which use the +// same histogram ID) overlap. That causes TelemetryStopwatch to log an +// error. +SimpleTest.ignoreAllUncaughtExceptions(true); + +add_setup(async function () { + await pushPrefs( + ["full-screen-api.transition-duration.enter", "0 0"], + ["full-screen-api.transition-duration.leave", "0 0"], + ["full-screen-api.allow-trusted-requests-only", false] + ); +}); + +async function startTests(setupFun, name) { + TEST_URLS.forEach(url => { + add_task(async () => { + info(`Test ${name}, url: ${url}`); + await BrowserTestUtils.withNewTab( + { + gBrowser, + url, + }, + async function (browser) { + let promiseFsState = Promise.all([ + setupFun(browser), + waitForFullscreenState(document, false, true), + ]); + // Trigger click event in inner most iframe + SpecialPowers.spawn( + browser.browsingContext.children[0].children[0], + [], + function () { + content.setTimeout(() => { + content.document.getElementById("div").click(); + }, 0); + } + ); + await promiseFsState; + + // Ensure the browser exits fullscreen state. + ok( + !window.fullScreen, + "The chrome window should not be in fullscreen" + ); + ok( + !document.documentElement.hasAttribute("inDOMFullscreen"), + "The chrome document should not be in fullscreen" + ); + } + ); + }); + }); +} + +function RemoveElementFromRemoteDocument(aBrowsingContext, aElementId) { + return SpecialPowers.spawn( + aBrowsingContext, + [aElementId], + async function (id) { + content.document.addEventListener( + "fullscreenchange", + function () { + content.document.getElementById(id).remove(); + }, + { once: true } + ); + } + ); +} + +startTests(async browser => { + // toplevel + let promise = waitRemoteFullscreenExitEvents([ + // browsingContext, name + [browser.browsingContext, "toplevel"], + ]); + await RemoveElementFromRemoteDocument(browser.browsingContext, "div"); + return promise; +}, "document_mutation_toplevel"); + +startTests(async browser => { + // middle iframe + let promise = waitRemoteFullscreenExitEvents([ + // browsingContext, name + [browser.browsingContext, "toplevel"], + [browser.browsingContext.children[0], "middle"], + ]); + await RemoveElementFromRemoteDocument( + browser.browsingContext.children[0], + "div" + ); + return promise; +}, "document_mutation_middle_frame"); + +startTests(async browser => { + // innermost iframe + let promise = waitRemoteFullscreenExitEvents([ + // browsingContext, name + [browser.browsingContext, "toplevel"], + [browser.browsingContext.children[0], "middle"], + [browser.browsingContext.children[0].children[0], "inner"], + ]); + await RemoveElementFromRemoteDocument( + browser.browsingContext.children[0].children[0], + "div" + ); + return promise; +}, "document_mutation_inner_frame"); diff --git a/dom/base/test/fullscreen/browser_fullscreen-document-mutation.js b/dom/base/test/fullscreen/browser_fullscreen-document-mutation.js new file mode 100644 index 0000000000..7cecdabb95 --- /dev/null +++ b/dom/base/test/fullscreen/browser_fullscreen-document-mutation.js @@ -0,0 +1,118 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +requestLongerTimeout(2); + +// Import helpers +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js", + this +); + +// This test tends to trigger a race in the fullscreen time telemetry, +// where the fullscreen enter and fullscreen exit events (which use the +// same histogram ID) overlap. That causes TelemetryStopwatch to log an +// error. +SimpleTest.ignoreAllUncaughtExceptions(true); + +add_setup(async function () { + await pushPrefs( + ["full-screen-api.transition-duration.enter", "0 0"], + ["full-screen-api.transition-duration.leave", "0 0"], + ["full-screen-api.allow-trusted-requests-only", false] + ); +}); + +async function startTests(testFun, name) { + TEST_URLS.forEach(url => { + add_task(async () => { + info(`Test ${name}, url: ${url}`); + await BrowserTestUtils.withNewTab( + { + gBrowser, + url, + }, + async function (browser) { + let promiseFsState = waitForFullscreenState(document, true); + // Trigger click event in inner most iframe + SpecialPowers.spawn( + browser.browsingContext.children[0].children[0], + [], + function () { + content.setTimeout(() => { + content.document.getElementById("div").click(); + }, 0); + } + ); + await promiseFsState; + + // This should exit fullscreen + promiseFsState = waitForFullscreenState(document, false); + await testFun(browser); + await promiseFsState; + + // Ensure the browser exits fullscreen state. + ok( + !window.fullScreen, + "The chrome window should not be in fullscreen" + ); + ok( + !document.documentElement.hasAttribute("inDOMFullscreen"), + "The chrome document should not be in fullscreen" + ); + } + ); + }); + }); +} + +function RemoveElementFromRemoteDocument(aBrowsingContext, aElementId) { + return SpecialPowers.spawn( + aBrowsingContext, + [aElementId], + async function (id) { + content.document.getElementById(id).remove(); + } + ); +} + +startTests(async browser => { + let promiseRemoteFsState = waitRemoteFullscreenExitEvents([ + // browsingContext, name + [browser.browsingContext, "toplevel"], + ]); + // toplevel + await RemoveElementFromRemoteDocument(browser.browsingContext, "div"); + await promiseRemoteFsState; +}, "document_mutation_toplevel"); + +startTests(async browser => { + let promiseRemoteFsState = waitRemoteFullscreenExitEvents([ + // browsingContext, name + [browser.browsingContext, "toplevel"], + [browser.browsingContext.children[0], "middle"], + ]); + // middle iframe + await RemoveElementFromRemoteDocument( + browser.browsingContext.children[0], + "div" + ); + await promiseRemoteFsState; +}, "document_mutation_middle_frame"); + +startTests(async browser => { + let promiseRemoteFsState = waitRemoteFullscreenExitEvents([ + // browsingContext, name + [browser.browsingContext, "toplevel"], + [browser.browsingContext.children[0], "middle"], + [browser.browsingContext.children[0].children[0], "inner"], + ]); + // innermost iframe + await RemoveElementFromRemoteDocument( + browser.browsingContext.children[0].children[0], + "div" + ); + await promiseRemoteFsState; +}, "document_mutation_inner_frame"); diff --git a/dom/base/test/fullscreen/browser_fullscreen-navigation-history.js b/dom/base/test/fullscreen/browser_fullscreen-navigation-history.js new file mode 100644 index 0000000000..08624ed327 --- /dev/null +++ b/dom/base/test/fullscreen/browser_fullscreen-navigation-history.js @@ -0,0 +1,100 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +requestLongerTimeout(2); + +// Import helpers +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js", + this +); + +// This test tends to trigger a race in the fullscreen time telemetry, +// where the fullscreen enter and fullscreen exit events (which use the +// same histogram ID) overlap. That causes TelemetryStopwatch to log an +// error, bug 1742890. +SimpleTest.ignoreAllUncaughtExceptions(true); + +add_setup(async function () { + await pushPrefs( + ["full-screen-api.transition-duration.enter", "0 0"], + ["full-screen-api.transition-duration.leave", "0 0"], + ["full-screen-api.allow-trusted-requests-only", false] + ); +}); + +function preventBFCache(aBrowsingContext, aPrevent) { + return SpecialPowers.spawn(aBrowsingContext, [aPrevent], prevent => { + if (prevent) { + // Using a dummy onunload listener to disable the bfcache. + content.window.addEventListener("unload", () => {}); + } + content.window.addEventListener( + "pagehide", + e => { + // XXX checking persisted property causes intermittent failures, so we + // dump the value instead, bug 1822263. + // is(e.persisted, !prevent, `Check BFCache state`); + info(`Check BFCache state: e.persisted is ${e.persisted}`); + }, + { once: true } + ); + }); +} + +[true, false].forEach(crossOrigin => { + [true, false].forEach(initialPagePreventsBFCache => { + [true, false].forEach(fullscreenPagePreventsBFCache => { + add_task(async function navigation_history() { + info( + `crossOrigin: ${crossOrigin}, initialPagePreventsBFCache: ${initialPagePreventsBFCache}, fullscreenPagePreventsBFCache: ${fullscreenPagePreventsBFCache}` + ); + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: "http://mochi.test:8888/browser/dom/base/test/fullscreen/dummy_page.html", + }, + async function (browser) { + // Maybe prevent BFCache on initial page. + await preventBFCache( + browser.browsingContext, + initialPagePreventsBFCache + ); + + // Navigate to fullscreen page. + const url = crossOrigin + ? "https://example.org/browser/dom/base/test/fullscreen/file_fullscreen-iframe-inner.html" + : "http://mochi.test:8888/browser/dom/base/test/fullscreen/file_fullscreen-iframe-inner.html"; + const loaded = BrowserTestUtils.browserLoaded(browser, false, url); + BrowserTestUtils.loadURIString(browser, url); + await loaded; + + // Maybe prevent BFCache on fullscreen test page. + await preventBFCache( + browser.browsingContext, + fullscreenPagePreventsBFCache + ); + + // Trigger click event to enter fullscreen. + let promiseFsState = waitForFullscreenState(document, true); + SpecialPowers.spawn(browser.browsingContext, [], () => { + content.setTimeout(() => { + content.document.getElementById("div").click(); + }, 0); + }); + await promiseFsState; + + // Navigate back to the previous page should exit fullscreen. + promiseFsState = waitForFullscreenState(document, false); + await SpecialPowers.spawn(browser.browsingContext, [], () => { + content.window.history.back(); + }); + await promiseFsState; + } + ); + }); + }); + }); +}); diff --git a/dom/base/test/fullscreen/browser_fullscreen-navigation-race.js b/dom/base/test/fullscreen/browser_fullscreen-navigation-race.js new file mode 100644 index 0000000000..f9d1543a1a --- /dev/null +++ b/dom/base/test/fullscreen/browser_fullscreen-navigation-race.js @@ -0,0 +1,162 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +requestLongerTimeout(2); + +// Import helpers +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js", + this +); + +// This test tends to trigger a race in the fullscreen time telemetry, +// where the fullscreen enter and fullscreen exit events (which use the +// same histogram ID) overlap. That causes TelemetryStopwatch to log an +// error. +SimpleTest.ignoreAllUncaughtExceptions(true); + +add_setup(async function () { + await pushPrefs( + ["full-screen-api.transition-duration.enter", "0 0"], + ["full-screen-api.transition-duration.leave", "0 0"], + ["full-screen-api.allow-trusted-requests-only", false] + ); +}); + +add_task(async function navigation() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: `data:text/html, + + `, + }, + async function (browser) { + BrowserTestUtils.synthesizeMouseAtCenter("#button", {}, browser); + + // Give some time for fullscreen transition. + await new Promise(aResolve => { + SimpleTest.executeSoon(() => { + SimpleTest.executeSoon(aResolve); + }); + }); + + // Wait fullscreen exit event if browser is still in fullscreen mode. + if ( + window.fullScreen || + document.documentElement.hasAttribute("inFullscreen") + ) { + info("The widget is still in fullscreen, wait again"); + await waitWidgetFullscreenEvent(window, false, true); + } + if (document.documentElement.hasAttribute("inDOMFullscreen")) { + info("The chrome document is still in fullscreen, wait again"); + await waitForFullScreenObserver(window, false, true); + } + + // Ensure the browser exits fullscreen state. + ok(!window.fullScreen, "The widget should not be in fullscreen"); + ok( + !document.documentElement.hasAttribute("inFullscreen"), + "The chrome window should not be in fullscreen" + ); + ok( + !document.documentElement.hasAttribute("inDOMFullscreen"), + "The chrome document should not be in fullscreen" + ); + } + ); +}); + +async function startTests(setupFun, name) { + TEST_URLS.forEach(url => { + add_task(async () => { + info(`Test ${name}, url: ${url}`); + await BrowserTestUtils.withNewTab( + { + gBrowser, + url, + }, + async function (browser) { + let promiseFsState = Promise.all([ + setupFun(browser), + waitForFullscreenState(document, false, true), + ]); + // Trigger click event in inner most iframe + SpecialPowers.spawn( + browser.browsingContext.children[0].children[0], + [], + function () { + content.setTimeout(() => { + content.document.getElementById("div").click(); + }, 0); + } + ); + await promiseFsState; + + // Ensure the browser exits fullscreen state. + ok( + !window.fullScreen, + "The chrome window should not be in fullscreen" + ); + ok( + !document.documentElement.hasAttribute("inDOMFullscreen"), + "The chrome document should not be in fullscreen" + ); + } + ); + }); + }); +} + +function NavigateRemoteDocument(aBrowsingContext, aURL) { + return SpecialPowers.spawn(aBrowsingContext, [aURL], async function (url) { + content.document.addEventListener( + "fullscreenchange", + function () { + content.location.href = url; + }, + { once: true } + ); + }); +} + +startTests(async browser => { + // toplevel + await NavigateRemoteDocument(browser.browsingContext, "about:blank"); +}, "navigation_toplevel"); + +startTests(async browser => { + // middle iframe + let promise = waitRemoteFullscreenExitEvents([ + // browsingContext, name + [browser.browsingContext, "toplevel"], + ]); + await NavigateRemoteDocument( + browser.browsingContext.children[0], + "about:blank" + ); + return promise; +}, "navigation_middle_frame"); + +startTests(async browser => { + // innermost iframe + let promise = waitRemoteFullscreenExitEvents([ + // browsingContext, name + [browser.browsingContext, "toplevel"], + [browser.browsingContext.children[0], "middle"], + ]); + await NavigateRemoteDocument( + browser.browsingContext.children[0].children[0], + "about:blank" + ); + return promise; +}, "navigation_inner_frame"); diff --git a/dom/base/test/fullscreen/browser_fullscreen-navigation.js b/dom/base/test/fullscreen/browser_fullscreen-navigation.js new file mode 100644 index 0000000000..02387eb437 --- /dev/null +++ b/dom/base/test/fullscreen/browser_fullscreen-navigation.js @@ -0,0 +1,142 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +requestLongerTimeout(2); + +// Import helpers +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js", + this +); + +// This test tends to trigger a race in the fullscreen time telemetry, +// where the fullscreen enter and fullscreen exit events (which use the +// same histogram ID) overlap. That causes TelemetryStopwatch to log an +// error. +SimpleTest.ignoreAllUncaughtExceptions(true); + +add_setup(async function () { + await pushPrefs( + ["full-screen-api.transition-duration.enter", "0 0"], + ["full-screen-api.transition-duration.leave", "0 0"], + ["full-screen-api.allow-trusted-requests-only", false] + ); +}); + +add_task(async function navigation() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: `data:text/html, + + `, + }, + async function (browser) { + let promiseFsState = waitForFullscreenState(document, true); + // Trigger click event + BrowserTestUtils.synthesizeMouseAtCenter("#button", {}, browser); + await promiseFsState; + + promiseFsState = waitForFullscreenState(document, false); + await SpecialPowers.spawn(browser, [], async function () { + content.location.href = "about:blank"; + }); + await promiseFsState; + + // Ensure the browser exits fullscreen state. + ok(!window.fullScreen, "The chrome window should not be in fullscreen"); + ok( + !document.documentElement.hasAttribute("inDOMFullscreen"), + "The chrome document should not be in fullscreen" + ); + } + ); +}); + +async function startTests(testFun, name) { + TEST_URLS.forEach(url => { + add_task(async () => { + info(`Test ${name}, url: ${url}`); + await BrowserTestUtils.withNewTab( + { + gBrowser, + url, + }, + async function (browser) { + let promiseFsState = waitForFullscreenState(document, true); + // Trigger click event in inner most iframe + SpecialPowers.spawn( + browser.browsingContext.children[0].children[0], + [], + function () { + content.setTimeout(() => { + content.document.getElementById("div").click(); + }, 0); + } + ); + await promiseFsState; + + // This should exit fullscreen + promiseFsState = waitForFullscreenState(document, false); + await testFun(browser); + await promiseFsState; + + // Ensure the browser exits fullscreen state. + ok( + !window.fullScreen, + "The chrome window should not be in fullscreen" + ); + ok( + !document.documentElement.hasAttribute("inDOMFullscreen"), + "The chrome document should not be in fullscreen" + ); + } + ); + }); + }); +} + +function NavigateRemoteDocument(aBrowsingContext, aURL) { + return SpecialPowers.spawn(aBrowsingContext, [aURL], async function (url) { + content.location.href = url; + }); +} + +startTests(async browser => { + // toplevel + await NavigateRemoteDocument(browser.browsingContext, "about:blank"); +}, "navigation_toplevel"); + +startTests(async browser => { + let promiseRemoteFsState = waitRemoteFullscreenExitEvents([ + // browsingContext, name + [browser.browsingContext, "toplevel"], + ]); + // middle iframe + await NavigateRemoteDocument( + browser.browsingContext.children[0], + "about:blank" + ); + await promiseRemoteFsState; +}, "navigation_middle_frame"); + +startTests(async browser => { + let promiseRemoteFsState = waitRemoteFullscreenExitEvents([ + // browsingContext, name + [browser.browsingContext, "toplevel"], + [browser.browsingContext.children[0], "middle"], + ]); + // innermost iframe + await NavigateRemoteDocument( + browser.browsingContext.children[0].children[0], + "about:blank" + ); + await promiseRemoteFsState; +}, "navigation_inner_frame"); diff --git a/dom/base/test/fullscreen/browser_fullscreen-newtab.js b/dom/base/test/fullscreen/browser_fullscreen-newtab.js new file mode 100644 index 0000000000..af714b1248 --- /dev/null +++ b/dom/base/test/fullscreen/browser_fullscreen-newtab.js @@ -0,0 +1,91 @@ +"use strict"; + +// This test tends to trigger a race in the fullscreen time telemetry, +// where the fullscreen enter and fullscreen exit events (which use the +// same histogram ID) overlap. That causes TelemetryStopwatch to log an +// error. +SimpleTest.ignoreAllUncaughtExceptions(true); + +const kPage = + "https://example.org/browser/" + + "dom/base/test/fullscreen/file_fullscreen-newtab.html"; + +function getSizeMode() { + return document.documentElement.getAttribute("sizemode"); +} + +async function runTest() { + await BrowserTestUtils.withNewTab( + { + gBrowser, + url: kPage, + }, + async function (browser) { + let promiseFsEvents = SpecialPowers.spawn(browser, [], function () { + return new Promise(resolve => { + let countFsChange = 0; + let countFsError = 0; + function checkAndResolve() { + if (countFsChange > 0 && countFsError > 0) { + Assert.ok( + false, + "Got both fullscreenchange and fullscreenerror events" + ); + } else if (countFsChange > 2) { + Assert.ok(false, "Got too many fullscreenchange events"); + } else if (countFsError > 1) { + Assert.ok(false, "Got too many fullscreenerror events"); + } else if (countFsChange == 2 || countFsError == 1) { + resolve(); + } + } + + content.document.addEventListener("fullscreenchange", () => { + ++countFsChange; + checkAndResolve(); + }); + content.document.addEventListener("fullscreenerror", () => { + ++countFsError; + checkAndResolve(); + }); + }); + }); + let promiseNewTab = BrowserTestUtils.waitForNewTab( + gBrowser, + "about:blank" + ); + await BrowserTestUtils.synthesizeMouseAtCenter("#link", {}, browser); + let [newtab] = await Promise.all([promiseNewTab, promiseFsEvents]); + await BrowserTestUtils.removeTab(newtab); + + // Ensure the browser exits fullscreen state in reasonable time. + await Promise.race([ + BrowserTestUtils.waitForCondition(() => getSizeMode() == "normal"), + // eslint-disable-next-line mozilla/no-arbitrary-setTimeout + new Promise(resolve => setTimeout(resolve, 2000)), + ]); + + ok(!window.fullScreen, "The chrome window should not be in fullscreen"); + ok( + !document.fullscreen, + "The chrome document should not be in fullscreen" + ); + } + ); +} + +add_task(async function () { + await pushPrefs( + ["full-screen-api.transition-duration.enter", "0 0"], + ["full-screen-api.transition-duration.leave", "0 0"] + ); + await runTest(); +}); + +add_task(async function () { + await pushPrefs( + ["full-screen-api.transition-duration.enter", "200 200"], + ["full-screen-api.transition-duration.leave", "200 200"] + ); + await runTest(); +}); diff --git a/dom/base/test/fullscreen/browser_fullscreen-sizemode.js b/dom/base/test/fullscreen/browser_fullscreen-sizemode.js new file mode 100644 index 0000000000..0aa79e5694 --- /dev/null +++ b/dom/base/test/fullscreen/browser_fullscreen-sizemode.js @@ -0,0 +1,225 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const isMac = AppConstants.platform == "macosx"; +const isWin = AppConstants.platform == "win"; + +async function waitForSizeMode(aWindow, aSizeMode) { + await BrowserTestUtils.waitForEvent(aWindow, "sizemodechange", false, () => { + return aWindow.windowState === aSizeMode; + }); + const expectedHidden = + aSizeMode == aWindow.STATE_MINIMIZED || aWindow.isFullyOccluded; + if (aWindow.document.hidden != expectedHidden) { + await BrowserTestUtils.waitForEvent(aWindow, "visibilitychange"); + } + is( + aWindow.document.hidden, + expectedHidden, + "Should be inactive if minimized or occluded" + ); +} + +async function checkSizeModeAndFullscreenState( + aWindow, + aSizeMode, + aFullscreen, + aFullscreenEventShouldHaveFired, + aStepFun +) { + let promises = []; + if (aWindow.windowState != aSizeMode) { + promises.push(waitForSizeMode(aWindow, aSizeMode)); + } + if (aFullscreenEventShouldHaveFired) { + promises.push( + BrowserTestUtils.waitForEvent( + aWindow, + aFullscreen ? "willenterfullscreen" : "willexitfullscreen" + ) + ); + promises.push(BrowserTestUtils.waitForEvent(aWindow, "fullscreen")); + } + + // Add listener for unexpected event. + let unexpectedEventListener = aEvent => { + ok(false, `should not receive ${aEvent.type} event`); + }; + if (aFullscreenEventShouldHaveFired) { + aWindow.addEventListener( + aFullscreen ? "willexitfullscreen" : "willenterfullscreen", + unexpectedEventListener + ); + } else { + aWindow.addEventListener("willenterfullscreen", unexpectedEventListener); + aWindow.addEventListener("willexitfullscreen", unexpectedEventListener); + aWindow.addEventListener("fullscreen", unexpectedEventListener); + } + + let eventPromise = Promise.all(promises); + aStepFun(); + await eventPromise; + + // Check SizeMode. + is( + aWindow.windowState, + aSizeMode, + "The new sizemode should have the expected value" + ); + // Check Fullscreen state. + is( + aWindow.fullScreen, + aFullscreen, + `chrome window should ${aFullscreen ? "be" : "not be"} in fullscreen` + ); + is( + aWindow.document.documentElement.hasAttribute("inFullscreen"), + aFullscreen, + `chrome documentElement should ${ + aFullscreen ? "have" : "not have" + } inFullscreen attribute` + ); + + // Remove listener for unexpected event. + if (aFullscreenEventShouldHaveFired) { + aWindow.removeEventListener( + aFullscreen ? "willexitfullscreen" : "willenterfullscreen", + unexpectedEventListener + ); + } else { + aWindow.removeEventListener("willenterfullscreen", unexpectedEventListener); + aWindow.removeEventListener("willexitfullscreen", unexpectedEventListener); + aWindow.removeEventListener("fullscreen", unexpectedEventListener); + } +} + +async function restoreWindowToNormal(aWindow) { + while (aWindow.windowState != aWindow.STATE_NORMAL) { + info(`Try to restore window with state ${aWindow.windowState} to normal`); + let eventPromise = BrowserTestUtils.waitForEvent(aWindow, "sizemodechange"); + aWindow.restore(); + await eventPromise; + info(`Window is now in state ${aWindow.windowState}`); + } +} + +add_task(async function test_fullscreen_restore() { + let win = await BrowserTestUtils.openNewBrowserWindow(); + await restoreWindowToNormal(win); + + info("Enter fullscreen"); + await checkSizeModeAndFullscreenState( + win, + win.STATE_FULLSCREEN, + true, + true, + () => { + win.fullScreen = true; + } + ); + + info("Restore window"); + await checkSizeModeAndFullscreenState( + win, + win.STATE_NORMAL, + false, + true, + () => { + win.restore(); + } + ); + + await BrowserTestUtils.closeWindow(win); +}); + +// This test only enable on Windows because: +// - Test gets intermittent timeout on macOS, see bug 1828848. +// - Restoring a fullscreen window on GTK doesn't return it to the previous +// sizemode, see bug 1828837. +if (isWin) { + add_task(async function test_maximize_fullscreen_restore() { + let win = await BrowserTestUtils.openNewBrowserWindow(); + await restoreWindowToNormal(win); + + info("Maximize window"); + await checkSizeModeAndFullscreenState( + win, + win.STATE_MAXIMIZED, + false, + false, + () => { + win.maximize(); + } + ); + + info("Enter fullscreen"); + await checkSizeModeAndFullscreenState( + win, + win.STATE_FULLSCREEN, + true, + true, + () => { + win.fullScreen = true; + } + ); + + info("Restore window"); + await checkSizeModeAndFullscreenState( + win, + win.STATE_MAXIMIZED, + false, + true, + () => { + win.restore(); + } + ); + + await BrowserTestUtils.closeWindow(win); + }); +} + +// Restoring a minimized window on macOS doesn't return it to the previous +// sizemode, see bug 1828706. +if (!isMac) { + add_task(async function test_fullscreen_minimize_restore() { + let win = await BrowserTestUtils.openNewBrowserWindow(); + await restoreWindowToNormal(win); + + info("Enter fullscreen"); + await checkSizeModeAndFullscreenState( + win, + win.STATE_FULLSCREEN, + true, + true, + () => { + win.fullScreen = true; + } + ); + + info("Minimize window"); + await checkSizeModeAndFullscreenState( + win, + win.STATE_MINIMIZED, + true, + false, + () => { + win.minimize(); + } + ); + + info("Restore window"); + await checkSizeModeAndFullscreenState( + win, + win.STATE_FULLSCREEN, + true, + false, + () => { + win.restore(); + } + ); + + await BrowserTestUtils.closeWindow(win); + }); +} diff --git a/dom/base/test/fullscreen/browser_fullscreen-tab-close-race.js b/dom/base/test/fullscreen/browser_fullscreen-tab-close-race.js new file mode 100644 index 0000000000..f1b300b93a --- /dev/null +++ b/dom/base/test/fullscreen/browser_fullscreen-tab-close-race.js @@ -0,0 +1,101 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +requestLongerTimeout(2); + +// Import helpers +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js", + this +); + +// This test tends to trigger a race in the fullscreen time telemetry, +// where the fullscreen enter and fullscreen exit events (which use the +// same histogram ID) overlap. That causes TelemetryStopwatch to log an +// error. +SimpleTest.ignoreAllUncaughtExceptions(true); + +add_setup(async function () { + await pushPrefs( + ["full-screen-api.transition-duration.enter", "0 0"], + ["full-screen-api.transition-duration.leave", "0 0"], + ["full-screen-api.allow-trusted-requests-only", false] + ); +}); + +async function startTests(setupFun, name) { + TEST_URLS.forEach(url => { + add_task(async () => { + info(`Test ${name}, url: ${url}`); + await BrowserTestUtils.withNewTab( + { + gBrowser, + url, + }, + async function (browser) { + let promiseFsState = waitForFullscreenExit(document); + setupFun(browser); + // Trigger click event in inner most iframe + SpecialPowers.spawn( + browser.browsingContext.children[0].children[0], + [], + function () { + content.setTimeout(() => { + content.document.getElementById("div").click(); + }, 0); + } + ); + await promiseFsState; + + // Ensure the browser exits fullscreen state. + ok( + !window.fullScreen, + "The chrome window should not be in fullscreen" + ); + ok( + !document.documentElement.hasAttribute("inDOMFullscreen"), + "The chrome document should not be in fullscreen" + ); + } + ); + }); + }); +} + +async function WaitRemoveDocumentAndCloseTab(aBrowser, aBrowsingContext) { + await SpecialPowers.spawn(aBrowsingContext, [], async function () { + return new Promise(resolve => { + content.document.addEventListener( + "fullscreenchange", + e => { + resolve(); + }, + { once: true } + ); + }); + }); + + // This should exit fullscreen + let tab = gBrowser.getTabForBrowser(aBrowser); + BrowserTestUtils.removeTab(tab); +} + +startTests(async browser => { + // toplevel + WaitRemoveDocumentAndCloseTab(browser, browser.browsingContext); +}, "tab_close_toplevel"); + +startTests(browser => { + // middle iframe + WaitRemoveDocumentAndCloseTab(browser, browser.browsingContext.children[0]); +}, "tab_close_middle_frame"); + +startTests(async browser => { + // innermost iframe + WaitRemoveDocumentAndCloseTab( + browser, + browser.browsingContext.children[0].children[0] + ); +}, "tab_close_inner_frame"); diff --git a/dom/base/test/fullscreen/browser_fullscreen-tab-close.js b/dom/base/test/fullscreen/browser_fullscreen-tab-close.js new file mode 100644 index 0000000000..7d1772cd48 --- /dev/null +++ b/dom/base/test/fullscreen/browser_fullscreen-tab-close.js @@ -0,0 +1,65 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +requestLongerTimeout(2); + +// Import helpers +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js", + this +); + +// This test tends to trigger a race in the fullscreen time telemetry, +// where the fullscreen enter and fullscreen exit events (which use the +// same histogram ID) overlap. That causes TelemetryStopwatch to log an +// error. +SimpleTest.ignoreAllUncaughtExceptions(true); + +add_setup(async function () { + await pushPrefs( + ["full-screen-api.transition-duration.enter", "0 0"], + ["full-screen-api.transition-duration.leave", "0 0"], + ["full-screen-api.allow-trusted-requests-only", false] + ); +}); + +TEST_URLS.forEach(url => { + add_task(async () => { + info(`url: ${url}`); + await BrowserTestUtils.withNewTab( + { + gBrowser, + url, + }, + async function (browser) { + let promiseFsState = waitForFullscreenState(document, true); + // Trigger click event in inner most iframe + SpecialPowers.spawn( + browser.browsingContext.children[0].children[0], + [], + function () { + content.setTimeout(() => { + content.document.getElementById("div").click(); + }, 0); + } + ); + await promiseFsState; + + let promiseFsExit = waitForFullscreenExit(document, false); + // This should exit fullscreen + let tab = gBrowser.getTabForBrowser(browser); + BrowserTestUtils.removeTab(tab); + await promiseFsExit; + + // Ensure the browser exits fullscreen state. + ok(!window.fullScreen, "The chrome window should not be in fullscreen"); + ok( + !document.documentElement.hasAttribute("inDOMFullscreen"), + "The chrome document should not be in fullscreen" + ); + } + ); + }); +}); diff --git a/dom/base/test/fullscreen/browser_fullscreen-window-open-race.js b/dom/base/test/fullscreen/browser_fullscreen-window-open-race.js new file mode 100644 index 0000000000..4cf8a3d8c7 --- /dev/null +++ b/dom/base/test/fullscreen/browser_fullscreen-window-open-race.js @@ -0,0 +1,73 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +requestLongerTimeout(2); + +// Import helpers +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js", + this +); + +// This test tends to trigger a race in the fullscreen time telemetry, +// where the fullscreen enter and fullscreen exit events (which use the +// same histogram ID) overlap. That causes TelemetryStopwatch to log an +// error, bug 1742890. +SimpleTest.ignoreAllUncaughtExceptions(true); + +add_setup(async function () { + await pushPrefs( + ["full-screen-api.transition-duration.enter", "0 0"], + ["full-screen-api.transition-duration.leave", "0 0"], + ["full-screen-api.allow-trusted-requests-only", false] + ); +}); + +add_task(async () => { + const url = + "http://mochi.test:8888/browser/dom/base/test/fullscreen/dummy_page.html"; + const name = "foo"; + + await BrowserTestUtils.withNewTab( + { + gBrowser, + url, + }, + async function (browser) { + info("open new window"); + SpecialPowers.spawn(browser, [url, name], function (u, n) { + content.document.notifyUserGestureActivation(); + content.window.open(u, n, "width=100,height=100"); + }); + let newWin = await BrowserTestUtils.waitForNewWindow({ url }); + await SimpleTest.promiseFocus(newWin); + + info("re-focusing main window"); + await SimpleTest.promiseFocus(window); + + info("open an existing window and request fullscreen"); + await SpecialPowers.spawn(browser, [url, name], function (u, n) { + content.document.notifyUserGestureActivation(); + content.window.open(u, n); + content.document.body.requestFullscreen(); + }); + + // We call window.open() first than requestFullscreen() in a row on + // content page, but given that focus sync-up takes several IPC exchanges, + // so parent process ends up processing the requests in a reverse order, + // which should reject the fullscreen request and leave fullscreen. + await waitWidgetFullscreenEvent(window, false, true); + + // Ensure the browser exits fullscreen state. + ok(!window.fullScreen, "The chrome window should not be in fullscreen"); + ok( + !document.documentElement.hasAttribute("inDOMFullscreen"), + "The chrome document should not be in fullscreen" + ); + + await BrowserTestUtils.closeWindow(newWin); + } + ); +}); diff --git a/dom/base/test/fullscreen/browser_fullscreen_exit_on_external_protocol.js b/dom/base/test/fullscreen/browser_fullscreen_exit_on_external_protocol.js new file mode 100644 index 0000000000..6f525da541 --- /dev/null +++ b/dom/base/test/fullscreen/browser_fullscreen_exit_on_external_protocol.js @@ -0,0 +1,215 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +SimpleTest.requestCompleteLog(); + +requestLongerTimeout(2); + +// Import helpers +Services.scriptloader.loadSubScript( + "chrome://mochitests/content/browser/dom/base/test/fullscreen/fullscreen_helpers.js", + this +); + +add_setup(async function () { + await pushPrefs( + ["full-screen-api.transition-duration.enter", "0 0"], + ["full-screen-api.transition-duration.leave", "0 0"], + ["full-screen-api.allow-trusted-requests-only", false] + ); +}); + +const { HandlerServiceTestUtils } = ChromeUtils.importESModule( + "resource://testing-common/HandlerServiceTestUtils.sys.mjs" +); + +const gHandlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].getService( + Ci.nsIHandlerService +); + +const CONTENT = `data:text/html, + + + + + + +`; + +// This test tends to trigger a race in the fullscreen time telemetry, +// where the fullscreen enter and fullscreen exit events (which use the +// same histogram ID) overlap. That causes TelemetryStopwatch to log an +// error. +SimpleTest.ignoreAllUncaughtExceptions(true); + +function setupMailHandler() { + let mailHandlerInfo = HandlerServiceTestUtils.getHandlerInfo("mailto"); + let gOldMailHandlers = []; + + // Remove extant web handlers because they have icons that + // we fetch from the web, which isn't allowed in tests. + let handlers = mailHandlerInfo.possibleApplicationHandlers; + for (let i = handlers.Count() - 1; i >= 0; i--) { + try { + let handler = handlers.queryElementAt(i, Ci.nsIWebHandlerApp); + gOldMailHandlers.push(handler); + // If we get here, this is a web handler app. Remove it: + handlers.removeElementAt(i); + } catch (ex) {} + } + + let previousHandling = mailHandlerInfo.alwaysAskBeforeHandling; + mailHandlerInfo.alwaysAskBeforeHandling = true; + + // Create a dummy web mail handler so we always know the mailto: protocol. + // Without this, the test fails on VMs without a default mailto: handler, + // because no dialog is ever shown, as we ignore subframe navigations to + // protocols that cannot be handled. + let dummy = Cc["@mozilla.org/uriloader/web-handler-app;1"].createInstance( + Ci.nsIWebHandlerApp + ); + dummy.name = "Handler 1"; + dummy.uriTemplate = "https://example.com/first/%s"; + mailHandlerInfo.possibleApplicationHandlers.appendElement(dummy); + + gHandlerSvc.store(mailHandlerInfo); + registerCleanupFunction(() => { + // Re-add the original protocol handlers: + let mailHandlers = mailHandlerInfo.possibleApplicationHandlers; + for (let i = handlers.Count() - 1; i >= 0; i--) { + try { + // See if this is a web handler. If it is, it'll throw, otherwise, + // we will remove it. + mailHandlers.queryElementAt(i, Ci.nsIWebHandlerApp); + mailHandlers.removeElementAt(i); + } catch (ex) {} + } + for (let h of gOldMailHandlers) { + mailHandlers.appendElement(h); + } + mailHandlerInfo.alwaysAskBeforeHandling = previousHandling; + gHandlerSvc.store(mailHandlerInfo); + }); +} + +add_task(setupMailHandler); + +// Fullscreen is canceled during fullscreen transition +add_task(async function OpenExternalProtocolOnPendingLaterFullscreen() { + for (const useClick of [true, false]) { + await BrowserTestUtils.withNewTab(CONTENT, async browser => { + const leavelFullscreen = waitForFullscreenState(document, false, true); + await SpecialPowers.spawn( + browser, + [useClick], + async function (shouldClick) { + const button = content.document.querySelector("button"); + + const clickDone = new Promise(r => { + button.addEventListener( + "click", + function () { + content.document.documentElement.requestFullscreen(); + // When anchor.click() is called, the fullscreen request + // is probably still pending. + content.setTimeout(() => { + if (shouldClick) { + content.document.querySelector("a").click(); + } else { + content.document.location = "mailto:test@example.com"; + } + r(); + }, 0); + }, + { once: true } + ); + }); + button.click(); + await clickDone; + } + ); + + await leavelFullscreen; + ok(true, "Fullscreen should be exited"); + }); + } +}); + +// Fullscreen is canceled immediately. +add_task(async function OpenExternalProtocolOnPendingFullscreen() { + for (const useClick of [true, false]) { + await BrowserTestUtils.withNewTab(CONTENT, async browser => { + await SpecialPowers.spawn( + browser, + [useClick], + async function (shouldClick) { + const button = content.document.querySelector("button"); + + const clickDone = new Promise(r => { + button.addEventListener( + "click", + function () { + content.document.documentElement + .requestFullscreen() + .then(() => { + ok(false, "Don't enter fullscreen"); + }) + .catch(() => { + ok(true, "Cancel entering fullscreen"); + r(); + }); + // When anchor.click() is called, the fullscreen request + // is probably still pending. + if (shouldClick) { + content.document.querySelector("a").click(); + } else { + content.document.location = "mailto:test@example.com"; + } + }, + { once: true } + ); + }); + button.click(); + await clickDone; + } + ); + + ok(true, "Fullscreen should be exited"); + }); + } +}); + +add_task(async function OpenExternalProtocolOnFullscreen() { + for (const useClick of [true, false]) { + await BrowserTestUtils.withNewTab(CONTENT, async browser => { + const leavelFullscreen = waitForFullscreenState(document, false, true); + await SpecialPowers.spawn( + browser, + [useClick], + async function (shouldClick) { + let button = content.document.querySelector("button"); + button.addEventListener("click", function () { + content.document.documentElement.requestFullscreen(); + }); + button.click(); + + await new Promise(r => { + content.document.addEventListener("fullscreenchange", r); + }); + + if (shouldClick) { + content.document.querySelector("a").click(); + } else { + content.document.location = "mailto:test@example.com"; + } + } + ); + + await leavelFullscreen; + ok(true, "Fullscreen should be exited"); + }); + } +}); diff --git a/dom/base/test/fullscreen/chrome.ini b/dom/base/test/fullscreen/chrome.ini new file mode 100644 index 0000000000..cf60c0f0b5 --- /dev/null +++ b/dom/base/test/fullscreen/chrome.ini @@ -0,0 +1,10 @@ +[DEFAULT] +tags = fullscreen + +[test_fullscreen.xhtml] +support-files = + file_MozDomFullscreen.html +[test_MozDomFullscreen_event.xhtml] +support-files = + fullscreen.xhtml + MozDomFullscreen_chrome.xhtml diff --git a/dom/base/test/fullscreen/dummy_page.html b/dom/base/test/fullscreen/dummy_page.html new file mode 100644 index 0000000000..fd238954c6 --- /dev/null +++ b/dom/base/test/fullscreen/dummy_page.html @@ -0,0 +1,10 @@ + + + +Dummy test page + + + +

Dummy test page

+ + diff --git a/dom/base/test/fullscreen/file_MozDomFullscreen.html b/dom/base/test/fullscreen/file_MozDomFullscreen.html new file mode 100644 index 0000000000..f954892706 --- /dev/null +++ b/dom/base/test/fullscreen/file_MozDomFullscreen.html @@ -0,0 +1,8 @@ + + + + +

Outer doc

+ + + diff --git a/dom/base/test/fullscreen/file_fullscreen-api-keys.html b/dom/base/test/fullscreen/file_fullscreen-api-keys.html new file mode 100644 index 0000000000..f526aa55ba --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-api-keys.html @@ -0,0 +1,41 @@ + + + + + + + + + diff --git a/dom/base/test/fullscreen/file_fullscreen-api-race.html b/dom/base/test/fullscreen/file_fullscreen-api-race.html new file mode 100644 index 0000000000..8310bc0a60 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-api-race.html @@ -0,0 +1,8 @@ + + + + Helper file for test_fullscreen-api-race.html + + + + diff --git a/dom/base/test/fullscreen/file_fullscreen-api.html b/dom/base/test/fullscreen/file_fullscreen-api.html new file mode 100644 index 0000000000..645e6ece46 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-api.html @@ -0,0 +1,340 @@ + + + + + Test for Bug 545812 + + + + + + +
+ + + + diff --git a/dom/base/test/fullscreen/file_fullscreen-async.html b/dom/base/test/fullscreen/file_fullscreen-async.html new file mode 100644 index 0000000000..e9b4147124 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-async.html @@ -0,0 +1,50 @@ + +Test for Bug 1129227 + + + + + + diff --git a/dom/base/test/fullscreen/file_fullscreen-backdrop.html b/dom/base/test/fullscreen/file_fullscreen-backdrop.html new file mode 100644 index 0000000000..27be77a6d1 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-backdrop.html @@ -0,0 +1,107 @@ + + + + + Test for Bug 1064843 + + + + + + + + +
+
+ + + diff --git a/dom/base/test/fullscreen/file_fullscreen-bug-1798219-2.html b/dom/base/test/fullscreen/file_fullscreen-bug-1798219-2.html new file mode 100644 index 0000000000..61db80c228 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-bug-1798219-2.html @@ -0,0 +1,22 @@ + + + diff --git a/dom/base/test/fullscreen/file_fullscreen-bug-1798219.html b/dom/base/test/fullscreen/file_fullscreen-bug-1798219.html new file mode 100644 index 0000000000..7490f12936 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-bug-1798219.html @@ -0,0 +1,14 @@ + + + diff --git a/dom/base/test/fullscreen/file_fullscreen-denied-inner.html b/dom/base/test/fullscreen/file_fullscreen-denied-inner.html new file mode 100644 index 0000000000..6b5916b2e2 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-denied-inner.html @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/dom/base/test/fullscreen/file_fullscreen-denied.html b/dom/base/test/fullscreen/file_fullscreen-denied.html new file mode 100644 index 0000000000..db9a69e71a --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-denied.html @@ -0,0 +1,171 @@ + + + + + Test for Bug 545812 + + + + + + + + + + diff --git a/dom/base/test/fullscreen/file_fullscreen-esc-exit-inner.html b/dom/base/test/fullscreen/file_fullscreen-esc-exit-inner.html new file mode 100644 index 0000000000..d7d8a90aaf --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-esc-exit-inner.html @@ -0,0 +1,58 @@ + + + + + Test for Bug 700764 + + + + + + + +

Inner frame

+ + diff --git a/dom/base/test/fullscreen/file_fullscreen-esc-exit.html b/dom/base/test/fullscreen/file_fullscreen-esc-exit.html new file mode 100644 index 0000000000..f65f930b3f --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-esc-exit.html @@ -0,0 +1,63 @@ + + + + + Test for Bug 700764 + + + + + + + + + + + + + + + diff --git a/dom/base/test/fullscreen/file_fullscreen-event-order.html b/dom/base/test/fullscreen/file_fullscreen-event-order.html new file mode 100644 index 0000000000..72fb2c9b47 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-event-order.html @@ -0,0 +1,50 @@ + + + + + + diff --git a/dom/base/test/fullscreen/file_fullscreen-featurePolicy-inner.html b/dom/base/test/fullscreen/file_fullscreen-featurePolicy-inner.html new file mode 100644 index 0000000000..844684b054 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-featurePolicy-inner.html @@ -0,0 +1,34 @@ + + + + + + + + + diff --git a/dom/base/test/fullscreen/file_fullscreen-featurePolicy.html b/dom/base/test/fullscreen/file_fullscreen-featurePolicy.html new file mode 100644 index 0000000000..c8b943c612 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-featurePolicy.html @@ -0,0 +1,90 @@ + + + + Test for FeaturePolicy + fullscreen + + + + + + + + + + diff --git a/dom/base/test/fullscreen/file_fullscreen-focus-inner.html b/dom/base/test/fullscreen/file_fullscreen-focus-inner.html new file mode 100644 index 0000000000..73d39a9d83 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-focus-inner.html @@ -0,0 +1,24 @@ + + + + Focus test - child window + + + + + + + + diff --git a/dom/base/test/fullscreen/file_fullscreen-focus.html b/dom/base/test/fullscreen/file_fullscreen-focus.html new file mode 100644 index 0000000000..be91025f45 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-focus.html @@ -0,0 +1,67 @@ + + + + + Test fullscreen request is blocked when window is not focused + + + + + + + + +
+ + diff --git a/dom/base/test/fullscreen/file_fullscreen-hidden.html b/dom/base/test/fullscreen/file_fullscreen-hidden.html new file mode 100644 index 0000000000..bd8c8189c9 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-hidden.html @@ -0,0 +1,56 @@ + + + + + Test for Bug 697636 + + + + + + + +Mozilla Bug 697636 +

+ +
+
+
+ + + diff --git a/dom/base/test/fullscreen/file_fullscreen-iframe-inner.html b/dom/base/test/fullscreen/file_fullscreen-iframe-inner.html new file mode 100644 index 0000000000..4a614fdecf --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-iframe-inner.html @@ -0,0 +1,5 @@ + + +
+ + diff --git a/dom/base/test/fullscreen/file_fullscreen-iframe-middle.html b/dom/base/test/fullscreen/file_fullscreen-iframe-middle.html new file mode 100644 index 0000000000..b60dea43bf --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-iframe-middle.html @@ -0,0 +1,5 @@ +
+ +

diff --git a/dom/base/test/fullscreen/file_fullscreen-iframe-top.html b/dom/base/test/fullscreen/file_fullscreen-iframe-top.html new file mode 100644 index 0000000000..dddf4930c2 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-iframe-top.html @@ -0,0 +1,5 @@ +
+ +

diff --git a/dom/base/test/fullscreen/file_fullscreen-lenient-setters.html b/dom/base/test/fullscreen/file_fullscreen-lenient-setters.html new file mode 100644 index 0000000000..02491c177e --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-lenient-setters.html @@ -0,0 +1,61 @@ + + + + + Test for Bug 1268798 + + + + + + + diff --git a/dom/base/test/fullscreen/file_fullscreen-multiple-inner.html b/dom/base/test/fullscreen/file_fullscreen-multiple-inner.html new file mode 100644 index 0000000000..cb5ca9b28e --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-multiple-inner.html @@ -0,0 +1,25 @@ + + + + Test for Bug 724554 + + + + + + + diff --git a/dom/base/test/fullscreen/file_fullscreen-multiple.html b/dom/base/test/fullscreen/file_fullscreen-multiple.html new file mode 100644 index 0000000000..f9e35b5e78 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-multiple.html @@ -0,0 +1,67 @@ + + + + + Test for Bug 724554 + + + + + + + + +
+ + diff --git a/dom/base/test/fullscreen/file_fullscreen-navigation.html b/dom/base/test/fullscreen/file_fullscreen-navigation.html new file mode 100644 index 0000000000..9b68fedf9a --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-navigation.html @@ -0,0 +1,52 @@ + + + + + Test for Bug 685402 + + + + + + + +Mozilla Bug 685402 +

+ +
+
+
+ + diff --git a/dom/base/test/fullscreen/file_fullscreen-nested.html b/dom/base/test/fullscreen/file_fullscreen-nested.html new file mode 100644 index 0000000000..1629d8386c --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-nested.html @@ -0,0 +1,130 @@ + + + + Test for Bug 1187801 + + + + + + + + + diff --git a/dom/base/test/fullscreen/file_fullscreen-newtab.html b/dom/base/test/fullscreen/file_fullscreen-newtab.html new file mode 100644 index 0000000000..0eaf5dd546 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-newtab.html @@ -0,0 +1,4 @@ + + +Click here diff --git a/dom/base/test/fullscreen/file_fullscreen-prefixed.html b/dom/base/test/fullscreen/file_fullscreen-prefixed.html new file mode 100644 index 0000000000..dfe1965365 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-prefixed.html @@ -0,0 +1,153 @@ + + + + + Test for Bug 743198 + + + + +
+ + + diff --git a/dom/base/test/fullscreen/file_fullscreen-resize.html b/dom/base/test/fullscreen/file_fullscreen-resize.html new file mode 100644 index 0000000000..3050ba0d5d --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-resize.html @@ -0,0 +1,39 @@ + + + + + Test for Bug 1742421 + + + + + +Mozilla Bug 1742421 +

+ +
+
+
+ + diff --git a/dom/base/test/fullscreen/file_fullscreen-rollback.html b/dom/base/test/fullscreen/file_fullscreen-rollback.html new file mode 100644 index 0000000000..b1578b39cd --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-rollback.html @@ -0,0 +1,140 @@ + + + + + Test for Bug 700764 + + + + + + +
+
+ +
+
+ +
+ + + + + diff --git a/dom/base/test/fullscreen/file_fullscreen-scrollbar.html b/dom/base/test/fullscreen/file_fullscreen-scrollbar.html new file mode 100644 index 0000000000..05ab51431a --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-scrollbar.html @@ -0,0 +1,147 @@ + + + + + Test for Bug 1201798 + + + + + + +
+
+
+
+
+
+ + + diff --git a/dom/base/test/fullscreen/file_fullscreen-selector.html b/dom/base/test/fullscreen/file_fullscreen-selector.html new file mode 100644 index 0000000000..64947b6cfd --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-selector.html @@ -0,0 +1,183 @@ + + + + Test for Bug 1199522 + + + + + + + + +
+
+
+
+
+
+ + diff --git a/dom/base/test/fullscreen/file_fullscreen-shadowdom.html b/dom/base/test/fullscreen/file_fullscreen-shadowdom.html new file mode 100644 index 0000000000..348e08ae87 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-shadowdom.html @@ -0,0 +1,52 @@ + + + + + Bug 1430305 + + + + + + + Mozilla Bug 1430305 + +
+ +
+      
+    
+ + diff --git a/dom/base/test/fullscreen/file_fullscreen-single.html b/dom/base/test/fullscreen/file_fullscreen-single.html new file mode 100644 index 0000000000..2ebc58bdae --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-single.html @@ -0,0 +1,78 @@ + + + + + Simple Fullscreen Enter and Exit Test + + + + + + +

Fullscreen div

+ + + + + diff --git a/dom/base/test/fullscreen/file_fullscreen-sub-iframe.html b/dom/base/test/fullscreen/file_fullscreen-sub-iframe.html new file mode 100644 index 0000000000..28b0235c87 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-sub-iframe.html @@ -0,0 +1,53 @@ + +Test for Bug 1609180 + + + + + + + diff --git a/dom/base/test/fullscreen/file_fullscreen-svg-element.html b/dom/base/test/fullscreen/file_fullscreen-svg-element.html new file mode 100644 index 0000000000..1dfc78aa1c --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-svg-element.html @@ -0,0 +1,49 @@ + + + + + Bug 735031 + + + + + + + Mozilla Bug 735031 + + + + + +
+      
+    
+ + diff --git a/dom/base/test/fullscreen/file_fullscreen-table.html b/dom/base/test/fullscreen/file_fullscreen-table.html new file mode 100644 index 0000000000..39c602334a --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-table.html @@ -0,0 +1,52 @@ + + + + + Test for Bug 1223561 + + + + + + +
+ + + diff --git a/dom/base/test/fullscreen/file_fullscreen-top-layer.html b/dom/base/test/fullscreen/file_fullscreen-top-layer.html new file mode 100644 index 0000000000..9e95182b02 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-top-layer.html @@ -0,0 +1,160 @@ + + + + + Test for Bug 1126230 + + + + + + + +Mozilla Bug 1126230 +
+
+
+
+ + + + + + + + + diff --git a/dom/base/test/fullscreen/file_fullscreen-utils.js b/dom/base/test/fullscreen/file_fullscreen-utils.js new file mode 100644 index 0000000000..b4779da4de --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-utils.js @@ -0,0 +1,87 @@ +// Keep track of how many fullscreenChange enters we've received, so that +// we can balance them with the number of exits we receive. We reset this +// to 0 when we load a test. +var fullscreenChangeEnters = 0; + +addLoadEvent(function () { + info(`Resetting fullscreen enter count.`); + fullscreenChangeEnters = 0; +}); + +// This can be used to force a certain value for fullscreenChangeEnters +// to handle unusual conditions -- such as exiting multiple levels of +// fullscreen forcibly. +function setFullscreenChangeEnters(enters) { + info(`Setting fullscreen enter count to ${enters}.`); + fullscreenChangeEnters = enters; +} + +// Returns true if the window believes it is in fullscreen. This may be true even +// before an asynchronous fullscreen transition is complete. +function inFullscreenMode(win) { + return win.document.fullscreenElement; +} + +// Adds a listener that will be called once a fullscreen transition +// is complete. When type==='enter', callback is called when we've +// received a fullscreenchange event, and the fullscreen transition is +// complete. When type==='exit', callback is called when we've +// received a fullscreenchange event and the window is out of +// fullscreen. inDoc is the document which the listeners are added on, +// if absent, the listeners are added to the current document. +// the current document. +function addFullscreenChangeContinuation(type, callback, inDoc) { + var doc = inDoc || document; + var topWin = doc.defaultView.top; + function checkCondition() { + if (type == "enter") { + fullscreenChangeEnters++; + return inFullscreenMode(topWin); + } else if (type == "exit") { + fullscreenChangeEnters--; + return fullscreenChangeEnters + ? inFullscreenMode(topWin) + : !inFullscreenMode(topWin); + } + throw new Error("'type' must be either 'enter', or 'exit'."); + } + function onFullscreenChange(event) { + doc.removeEventListener("fullscreenchange", onFullscreenChange); + ok(checkCondition(), `Should ${type} fullscreen.`); + // Delay invocation so other listeners have a chance to respond before + // we continue. + requestAnimationFrame(() => setTimeout(() => callback(event), 0), 0); + } + doc.addEventListener("fullscreenchange", onFullscreenChange); +} + +// Calls |callback| when the next fullscreenerror is dispatched to inDoc||document. +function addFullscreenErrorContinuation(callback, inDoc) { + let doc = inDoc || document; + let listener = function (event) { + doc.removeEventListener("fullscreenerror", listener); + // Delay invocation so other listeners have a chance to respond before + // we continue. + requestAnimationFrame(() => setTimeout(() => callback(event), 0), 0); + }; + doc.addEventListener("fullscreenerror", listener); +} + +// Waits until the window has both the load event and a MozAfterPaint called on +// it, and then invokes the callback +function waitForLoadAndPaint(win, callback) { + win.addEventListener( + "MozAfterPaint", + function () { + // The load event may have fired before the MozAfterPaint, in which case + // listening for it now will hang. Instead we check the readyState to see if + // it already fired, and if so, invoke the callback right away. + if (win.document.readyState == "complete") { + callback(); + } else { + win.addEventListener("load", callback, { once: true }); + } + }, + { once: true } + ); +} diff --git a/dom/base/test/fullscreen/file_fullscreen-with-full-zoom.html b/dom/base/test/fullscreen/file_fullscreen-with-full-zoom.html new file mode 100644 index 0000000000..620bc5acf9 --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen-with-full-zoom.html @@ -0,0 +1,36 @@ + + + + + Test for Bug 1223561 + + + + + + +
+ + + diff --git a/dom/base/test/fullscreen/file_fullscreen_meta_viewport.html b/dom/base/test/fullscreen/file_fullscreen_meta_viewport.html new file mode 100644 index 0000000000..9938fdda6b --- /dev/null +++ b/dom/base/test/fullscreen/file_fullscreen_meta_viewport.html @@ -0,0 +1,12 @@ + + + +
+
diff --git a/dom/base/test/fullscreen/fullscreen.xhtml b/dom/base/test/fullscreen/fullscreen.xhtml new file mode 100644 index 0000000000..2cc95642b6 --- /dev/null +++ b/dom/base/test/fullscreen/fullscreen.xhtml @@ -0,0 +1,27 @@ + + + + + + + + + + + + -- cgit v1.2.3