summaryrefslogtreecommitdiffstats
path: root/docshell/test/navigation/test_blockBFCache.html
diff options
context:
space:
mode:
Diffstat (limited to 'docshell/test/navigation/test_blockBFCache.html')
-rw-r--r--docshell/test/navigation/test_blockBFCache.html294
1 files changed, 294 insertions, 0 deletions
diff --git a/docshell/test/navigation/test_blockBFCache.html b/docshell/test/navigation/test_blockBFCache.html
new file mode 100644
index 0000000000..3d4a418369
--- /dev/null
+++ b/docshell/test/navigation/test_blockBFCache.html
@@ -0,0 +1,294 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Blocking pages from entering BFCache</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+</head>
+<body onload="">
+<script>
+
+const getUserMediaPrefs = {
+ set: [
+ ["media.devices.insecure.enabled", true],
+ ["media.getusermedia.insecure.enabled", true],
+ ["media.navigator.permission.disabled", true],
+ ],
+};
+const msePrefs = {
+ set: [
+ ["media.mediasource.enabled", true],
+ ["media.audio-max-decode-error", 0],
+ ["media.video-max-decode-error", 0],
+ ]
+};
+
+const blockBFCacheTests = [
+ {
+ name: "Request",
+ test: () => {
+ return new Promise((resolve) => {
+ const xhr = new XMLHttpRequest();
+ xhr.open("GET", "slow.sjs");
+ xhr.addEventListener("progress", () => { resolve(xhr); }, { once: true });
+ xhr.send();
+ });
+ },
+ },
+ {
+ name: "Background request",
+ test: () => {
+ return new Promise((resolve) => {
+ const xhr = new XMLHttpRequest();
+ xhr.open("GET", "slow.sjs");
+ xhr.addEventListener("readystatechange", () => { if (xhr.readyState == xhr.HEADERS_RECEIVED) resolve(xhr); });
+ xhr.send();
+ });
+ },
+ },
+ {
+ name: "getUserMedia",
+ prefs: getUserMediaPrefs,
+ test: () => {
+ return navigator.mediaDevices.getUserMedia({ audio: true, fake: true });
+ },
+ },
+ {
+ name: "RTCPeerConnection",
+ test: () => {
+ let pc = new RTCPeerConnection();
+ return pc.createOffer();
+ },
+ },
+ {
+ name: "MSE",
+ prefs: msePrefs,
+ test: () => {
+ const ms = new MediaSource();
+ const el = document.createElement("video");
+ el.src = URL.createObjectURL(ms);
+ el.preload = "auto";
+ return el;
+ },
+ },
+ {
+ name: "WebSpeech",
+ test: () => {
+ return new Promise((resolve) => {
+ const utterance = new SpeechSynthesisUtterance('bfcache');
+ utterance.lang = 'it-IT-noend';
+ utterance.addEventListener('start', () => { resolve(utterance); })
+ speechSynthesis.speak(utterance);
+ });
+ },
+ },
+ {
+ name: "WebVR",
+ prefs: {
+ set: [
+ ["dom.vr.test.enabled", true],
+ ["dom.vr.puppet.enabled", true],
+ ["dom.vr.require-gesture", false],
+ ],
+ },
+ test: () => {
+ return navigator.requestVRServiceTest();
+ }
+ },
+];
+
+if (SpecialPowers.Services.appinfo.fissionAutostart) {
+ blockBFCacheTests.push({
+ name: "Loading OOP iframe",
+ test: () => {
+ return new Promise((resolve) => {
+ const el = document.body.appendChild(document.createElement("iframe"));
+ el.id = "frame";
+ addEventListener("message", ({ data }) => {
+ if (data == "onload") {
+ resolve();
+ }
+ });
+ el.src = "https://example.com/tests/docshell/test/navigation/iframe_slow_onload.html";
+ });
+ },
+ waitForDone: () => {
+ SimpleTest.requestFlakyTimeout("Test has a loop in an onload handler that runs for 5000ms, we need to make sure the loop is done before moving to the next test.");
+ return new Promise(resolve => {
+ setTimeout(resolve, 5000);
+ });
+ },
+ });
+}
+
+const dontBlockBFCacheTests = [
+ {
+ name: "getUserMedia",
+ prefs: getUserMediaPrefs,
+ test: () => {
+ return navigator.mediaDevices.getUserMedia({ video: true, fake: true }).then(stream => {
+ stream.getTracks().forEach(track => track.stop());
+ return stream;
+ });
+ },
+ },
+/*
+ Disabled because MediaKeys rely on being destroyed by the CC before they
+ notify their window, so the test would intermittently fail depending on
+ when the CC runs.
+
+ {
+ name: "MSE",
+ prefs: msePrefs,
+ test: () => {
+ return new Promise((resolve) => {
+ const ms = new MediaSource();
+ const el = document.createElement("video");
+ ms.addEventListener("sourceopen", () => { resolve(el) }, { once: true });
+ el.src = URL.createObjectURL(ms);
+ el.preload = "auto";
+ }).then(el => {
+ el.src = "";
+ return el;
+ });
+ },
+ },
+*/
+];
+
+
+
+function executeTest() {
+
+ let bc = new BroadcastChannel("bfcache_blocking");
+
+ function promiseMessage(type) {
+ return new Promise((resolve, reject) => {
+ bc.addEventListener("message", (e) => {
+ if (e.data.type == type) {
+ resolve(e.data);
+ }
+ }, { once: true });
+ });
+ }
+
+ function promisePageShow(shouldBePersisted) {
+ return promiseMessage("pageshow").then(data => data.persisted == shouldBePersisted);
+ }
+
+ function promisePageShowFromBFCache(e) {
+ return promisePageShow(true);
+ }
+
+ function promisePageShowNotFromBFCache(e) {
+ return promisePageShow(false);
+ }
+
+ function runTests(testArray, shouldBlockBFCache) {
+ for (const { name, prefs = {}, test, waitForDone } of testArray) {
+ add_task(async function() {
+ await SpecialPowers.pushPrefEnv(prefs, async function() {
+ // Load a mostly blank page that we can communicate with over
+ // BroadcastChannel (though it will close the BroadcastChannel after
+ // receiving the next "load" message, to avoid blocking BFCache).
+ let loaded = promisePageShowNotFromBFCache();
+ window.open("file_blockBFCache.html", "", "noopener");
+ await loaded;
+
+ // Load the same page with a different URL.
+ loaded = promisePageShowNotFromBFCache();
+ bc.postMessage({ message: "load", url: `file_blockBFCache.html?${name}_${shouldBlockBFCache}` });
+ await loaded;
+
+ // Run test script in the second page.
+ bc.postMessage({ message: "runScript", fun: test.toString() });
+ await promiseMessage("runScriptDone");
+
+ // Go back to the first page (this should just come from the BFCache).
+ let goneBack = promisePageShowFromBFCache();
+ bc.postMessage({ message: "back" });
+ await goneBack;
+
+ // Go forward again to the second page and check that it does/doesn't come
+ // from the BFCache.
+ let goneForward = promisePageShow(!shouldBlockBFCache);
+ bc.postMessage({ message: "forward" });
+ let result = await goneForward;
+ ok(result, `Page ${shouldBlockBFCache ? "should" : "should not"} have been blocked from going into the BFCache (${name})`);
+
+ // If the test will keep running after navigation, then we need to make
+ // sure it's completely done before moving to the next test, to avoid
+ // interfering with any following tests. If waitForDone is defined then
+ // it'll return a Promise that we can use to wait for the end of the
+ // test.
+ if (waitForDone) {
+ await waitForDone();
+ }
+
+ // Do a similar test, but replace the bfcache test page with a new page,
+ // not a page coming from the session history.
+
+ // Load the same page with a different URL.
+ loaded = promisePageShowNotFromBFCache();
+ bc.postMessage({ message: "load", url: `file_blockBFCache.html?p2_${name}_${shouldBlockBFCache}` });
+ await loaded;
+
+ // Run the test script.
+ bc.postMessage({ message: "runScript", fun: test.toString() });
+ await promiseMessage("runScriptDone");
+
+ // Load a new page.
+ loaded = promisePageShowNotFromBFCache();
+ bc.postMessage({ message: "load", url: "file_blockBFCache.html" });
+ await loaded;
+
+ // Go back to the previous page and check that it does/doesn't come
+ // from the BFCache.
+ goneBack = promisePageShow(!shouldBlockBFCache);
+ bc.postMessage({ message: "back" });
+ result = await goneBack;
+ ok(result, `Page ${shouldBlockBFCache ? "should" : "should not"} have been blocked from going into the BFCache (${name})`);
+
+ if (waitForDone) {
+ await waitForDone();
+ }
+
+ bc.postMessage({ message: "close" });
+
+ SpecialPowers.popPrefEnv();
+ });
+ });
+ }
+ }
+
+ // If Fission is disabled, the pref is no-op.
+ SpecialPowers.pushPrefEnv({set: [["fission.bfcacheInParent", true]]}, () => {
+ runTests(blockBFCacheTests, true);
+ runTests(dontBlockBFCacheTests, false);
+ });
+}
+
+if (isXOrigin) {
+ // Bug 1746646: Make mochitests work with TCP enabled (cookieBehavior = 5)
+ // Acquire storage access permission here so that the BroadcastChannel used to
+ // communicate with the opened windows works in xorigin tests. Otherwise,
+ // the iframe containing this page is isolated from first-party storage access,
+ // which isolates BroadcastChannel communication.
+ SpecialPowers.wrap(document).notifyUserGestureActivation();
+ SpecialPowers.addPermission("storageAccessAPI", true, window.location.href).then(() => {
+ SpecialPowers.wrap(document).requestStorageAccess().then(() => {
+ SpecialPowers.pushPrefEnv({
+ set: [["privacy.partition.always_partition_third_party_non_cookie_storage", false]]
+ }).then(() => {
+ executeTest();
+ });
+ });
+ });
+} else {
+ executeTest();
+}
+
+</script>
+</body>
+</html>