Bug 1741280 - Part 1: Add more fullscreen tests; r=smaug,Gijs

Depends on D131185

Differential Revision: https://phabricator.services.mozilla.com/D131183
This commit is contained in:
Edgar Chen 2022-01-19 06:08:45 +00:00
parent 45ff0f12df
commit a9a876b4af
9 changed files with 543 additions and 26 deletions

View File

@ -36,6 +36,32 @@ skip-if = os == 'mac'
(os == 'linux' && bits == 64 && os_version == '18.04') # Bug 1601460, Bug 1494843
[browser_fullscreen-navigation.js]
tags = fullscreen
support-files =
fullscreen_helpers.js
file_fullscreen-iframe-top.html
file_fullscreen-iframe-middle.html
file_fullscreen-iframe-inner.html
[browser_fullscreen-navigation-race.js]
tags = fullscreen
support-files =
fullscreen_helpers.js
file_fullscreen-iframe-top.html
file_fullscreen-iframe-middle.html
file_fullscreen-iframe-inner.html
[browser_fullscreen-document-mutation.js]
tags = fullscreen
support-files =
fullscreen_helpers.js
file_fullscreen-iframe-top.html
file_fullscreen-iframe-middle.html
file_fullscreen-iframe-inner.html
[browser_fullscreen-document-mutation-race.js]
tags = fullscreen
support-files =
fullscreen_helpers.js
file_fullscreen-iframe-top.html
file_fullscreen-iframe-middle.html
file_fullscreen-iframe-inner.html
[browser_submission_flush.js]
[browser_refresh_after_document_write.js]
support-files =

View File

@ -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/html/test/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_task(async function init() {
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) {
await setupFun(browser);
let promiseFsState = 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
await RemoveElementFromRemoteDocument(browser.browsingContext, "div");
}, "document_mutation_toplevel");
startTests(async browser => {
// middle iframe
await RemoveElementFromRemoteDocument(
browser.browsingContext.children[0],
"div"
);
}, "document_mutation_middle_frame");
startTests(async browser => {
// innermost iframe
await RemoveElementFromRemoteDocument(
browser.browsingContext.children[0].children[0],
"div"
);
}, "document_mutation_inner_frame");

View File

@ -0,0 +1,98 @@
/* 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/html/test/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_task(async function init() {
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 => {
// toplevel
await RemoveElementFromRemoteDocument(browser.browsingContext, "div");
}, "document_mutation_toplevel");
startTests(async browser => {
// middle iframe
await RemoveElementFromRemoteDocument(
browser.browsingContext.children[0],
"div"
);
}, "document_mutation_middle_frame");
startTests(async browser => {
// innermost iframe
await RemoveElementFromRemoteDocument(
browser.browsingContext.children[0].children[0],
"div"
);
}, "document_mutation_inner_frame");

View File

@ -0,0 +1,128 @@
/* 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/html/test/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_task(async function init() {
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,
<button id="button">Click here</button>
<script>
let button = document.getElementById("button");
button.addEventListener("click", function() {
button.requestFullscreen();
location.href = "about:blank";
});
</script>`,
},
async function(browser) {
let promiseFsState = waitForFullscreenState(document, false, true);
BrowserTestUtils.synthesizeMouseAtCenter("#button", {}, 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"
);
}
);
});
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) {
await setupFun(browser);
let promiseFsState = 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
await NavigateRemoteDocument(
browser.browsingContext.children[0],
"about:blank"
);
}, "navigation_middle_frame");
startTests(async browser => {
// innermost iframe
await NavigateRemoteDocument(
browser.browsingContext.children[0].children[0],
"about:blank"
);
}, "navigation_inner_frame");

View File

@ -1,36 +1,27 @@
/* 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/html/test/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);
function waitFullscreenEvents(aDocument) {
return new Promise(resolve => {
function errorHandler() {
ok(false, "should not get fullscreenerror event");
}
let countFsChange = 0;
function changeHandler() {
++countFsChange;
if (countFsChange == 2) {
aDocument.removeEventListener("fullscreenchange", changeHandler);
aDocument.removeEventListener("fullscreenerror", errorHandler);
resolve();
}
}
aDocument.addEventListener("fullscreenchange", changeHandler);
aDocument.addEventListener("fullscreenerror", errorHandler);
});
}
add_task(async function init() {
await pushPrefs(
["full-screen-api.transition-duration.enter", "0 0"],
["full-screen-api.transition-duration.leave", "0 0"]
["full-screen-api.transition-duration.leave", "0 0"],
["full-screen-api.allow-trusted-requests-only", false]
);
});
@ -44,16 +35,22 @@ add_task(async function navigation() {
let button = document.getElementById("button");
button.addEventListener("click", function() {
button.requestFullscreen();
location.href = "about:blank";
});
</script>`,
},
async function(browser) {
let promiseFsEvents = waitFullscreenEvents(document);
let promiseFsState = waitForFullscreenState(document, true);
// Trigger click event
BrowserTestUtils.synthesizeMouseAtCenter("#button", {}, browser);
await promiseFsState;
await BrowserTestUtils.synthesizeMouseAtCenter("#button", {}, browser);
await promiseFsEvents;
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"),
@ -62,3 +59,73 @@ add_task(async function navigation() {
}
);
});
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 => {
// middle iframe
await NavigateRemoteDocument(
browser.browsingContext.children[0],
"about:blank"
);
}, "navigation_middle_frame");
startTests(async browser => {
// innermost iframe
await NavigateRemoteDocument(
browser.browsingContext.children[0].children[0],
"about:blank"
);
}, "navigation_inner_frame");

View File

@ -0,0 +1,5 @@
<html onclick="div.requestFullscreen()">
<body>
<div name="div" id="div" style="width: 100px; height: 100px; background: green;"></div>
</body>
</html>

View File

@ -0,0 +1,5 @@
<div name="div" id="div" style="width: 100px; height: 100px; background: blue;">
<iframe id="iframe" allowfullscreen="yes"
src="http://example.org/browser/dom/html/test/file_fullscreen-iframe-inner.html">
</iframe>
</div><br>

View File

@ -0,0 +1,5 @@
<div name="div" id="div" style="width: 100px; height: 100px; background: red;">
<iframe id="iframe" allowfullscreen="yes"
src="http://mochi.test:8888/browser/dom/html/test/file_fullscreen-iframe-middle.html">
</iframe>
</div><br>

View File

@ -0,0 +1,82 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const TEST_URLS = [
// all frames are in different process.
`data:text/html,
<div name="div" id="div" style="width: 100px; height: 100px; background: red;">
<iframe id="iframe" allowfullscreen="yes"
src="http://mochi.test:8888/browser/dom/html/test/file_fullscreen-iframe-middle.html"></iframe>
</div>`,
// toplevel and inner most iframe are in same process, and middle iframe is
// in a different process.
`http://example.org/browser/dom/html/test/file_fullscreen-iframe-top.html`,
// toplevel and middle iframe are in same process, and inner most iframe is
// in a different process.
`http://mochi.test:8888/browser/dom/html/test/file_fullscreen-iframe-top.html`,
];
function waitFullscreenEvent(aDocument, aIsInFullscreen, aWaitUntil = false) {
return new Promise(resolve => {
function errorHandler() {
ok(false, "should not get fullscreenerror event");
aDocument.removeEventListener("fullscreenchange", changeHandler);
aDocument.removeEventListener("fullscreenerror", errorHandler);
resolve();
}
function changeHandler() {
if (aWaitUntil && aIsInFullscreen != !!aDocument.fullscreenElement) {
return;
}
is(
aIsInFullscreen,
!!aDocument.fullscreenElement,
"check fullscreen (event)"
);
aDocument.removeEventListener("fullscreenchange", changeHandler);
aDocument.removeEventListener("fullscreenerror", errorHandler);
resolve();
}
aDocument.addEventListener("fullscreenchange", changeHandler);
aDocument.addEventListener("fullscreenerror", errorHandler);
});
}
function waitForFullScreenObserver(
aDocument,
aIsInFullscreen,
aWaitUntil = false
) {
return TestUtils.topicObserved("fullscreen-painted", (subject, data) => {
if (
aWaitUntil &&
aIsInFullscreen !=
aDocument.documentElement.hasAttribute("inDOMFullscreen")
) {
return false;
}
is(
aIsInFullscreen,
aDocument.documentElement.hasAttribute("inDOMFullscreen"),
"check fullscreen (observer)"
);
return true;
});
}
function waitForFullscreenState(
aDocument,
aIsInFullscreen,
aWaitUntil = false
) {
return Promise.all([
waitFullscreenEvent(aDocument, aIsInFullscreen, aWaitUntil),
waitForFullScreenObserver(aDocument, aIsInFullscreen, aWaitUntil),
]);
}