diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /testing/web-platform/tests/portals/resources | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/portals/resources')
43 files changed, 755 insertions, 0 deletions
diff --git a/testing/web-platform/tests/portals/resources/attempt-portal-load.html b/testing/web-platform/tests/portals/resources/attempt-portal-load.html new file mode 100644 index 0000000000..183178006f --- /dev/null +++ b/testing/web-platform/tests/portals/resources/attempt-portal-load.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<body> +<script> +portalLoaded = new Promise((resolve, reject) => { + let portal = document.createElement('portal'); + portal.src = 'simple-portal.html'; + portal.onload = resolve; + document.body.appendChild(portal); +}); +</script> +</body> diff --git a/testing/web-platform/tests/portals/resources/blank-host.html b/testing/web-platform/tests/portals/resources/blank-host.html new file mode 100644 index 0000000000..d9f3a61eb8 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/blank-host.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<!-- + This is a blank page used when a test needs a new window to host and activate + a portal. Tests cannot simply use window.open() without a URL as about:blank + may not host a portal. +--> +<body> +</body> diff --git a/testing/web-platform/tests/portals/resources/eval-portal.html b/testing/web-platform/tests/portals/resources/eval-portal.html new file mode 100644 index 0000000000..a473501b01 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/eval-portal.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<script> +let logic = new Function('event', (new URL(location)).searchParams.get('logic')); +onload = () => window.portalHost.postMessage('ready'); +onportalactivate = event => { + Promise.resolve(event) + .then(logic) + .then(reply => event.data.replyPort.postMessage(reply)); +}; +</script> diff --git a/testing/web-platform/tests/portals/resources/focus-page-with-autofocus.html b/testing/web-platform/tests/portals/resources/focus-page-with-autofocus.html new file mode 100644 index 0000000000..d498ef6335 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/focus-page-with-autofocus.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<body> + <button id="one">one</button> + <button id="two" autofocus>two</button> + <button id="three">three</button> + <script> + function messageHandler(e) { + if (e.data === 'check-active-element') { + window.requestAnimationFrame(() => { + let autofocusedButton = document.querySelector('#two'); + e.source.postMessage(document.activeElement === autofocusedButton); + }); + } + } + + window.portalHost.onmessage = messageHandler; + window.onportalactivate = e => { + let portal = e.adoptPredecessor(); + portal.onmessage = messageHandler; + document.body.appendChild(portal); + } + </script> +</body> diff --git a/testing/web-platform/tests/portals/resources/focus-page-with-button.html b/testing/web-platform/tests/portals/resources/focus-page-with-button.html new file mode 100644 index 0000000000..81ed5465ab --- /dev/null +++ b/testing/web-platform/tests/portals/resources/focus-page-with-button.html @@ -0,0 +1,35 @@ +<!DOCTYPE html> +<body> + <script> + function handleMessage(e) { + if (e.data == "focus") { + let button = document.querySelector("button"); + button.onfocus = () => e.source.postMessage({focused: true}, {targetOrigin: "*"}); + button.focus(); + } + + if (e.data == "focus-update-active-element") { + let button = document.querySelector("button"); + button.focus(); + e.source.postMessage({activeElementUpdated: document.activeElement === button}, {targetOrigin: "*"}); + } + } + + if (window.portalHost) + window.portalHost.onmessage = handleMessage; + + window.onmessage = handleMessage; + + window.onportalactivate = e => { + let portal = e.adoptPredecessor(); + document.body.appendChild(portal); + portal.onmessage = handleMessage; + }; + + window.onfocus = () => { + if (window.portalHost) + window.portalHost.postMessage("window focused"); + }; + </script> + <button>A</button> +</body> diff --git a/testing/web-platform/tests/portals/resources/focus-page-with-x-origin-iframe.sub.html b/testing/web-platform/tests/portals/resources/focus-page-with-x-origin-iframe.sub.html new file mode 100644 index 0000000000..df7974e75b --- /dev/null +++ b/testing/web-platform/tests/portals/resources/focus-page-with-x-origin-iframe.sub.html @@ -0,0 +1,28 @@ +<!DOCTYPE html> +<body> + <script> + async function handleMessage(e) { + if (e.data == "focus" || e.data == "focus-update-active-element") { + let iframe = document.querySelector("iframe"); + iframe.contentWindow.postMessage(e.data, "*"); + } + } + + if (window.portalHost) + window.portalHost.onmessage = handleMessage; + + window.onportalactivate = e => { + var portal = e.adoptPredecessor(); + document.body.appendChild(portal); + portal.onmessage = handleMessage; + } + + window.onmessage = e => { + if (window.portalHost) + window.portalHost.postMessage(e.data); + else + document.querySelector("portal").postMessage(e.data); + } + </script> + <iframe src="http://{{hosts[alt][www]}}:{{ports[http][0]}}/portals/resources/focus-page-with-button.html"></iframe> +</body> diff --git a/testing/web-platform/tests/portals/resources/invalid.asis b/testing/web-platform/tests/portals/resources/invalid.asis new file mode 100644 index 0000000000..20f7c7f7e5 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/invalid.asis @@ -0,0 +1 @@ +This is an invalid HTTP response used to produce a network error. diff --git a/testing/web-platform/tests/portals/resources/open-blank-host.js b/testing/web-platform/tests/portals/resources/open-blank-host.js new file mode 100644 index 0000000000..f7580bd152 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/open-blank-host.js @@ -0,0 +1,14 @@ +// Portal tests often need to create portals in a context other than the one +// in which the tests are running. This is because the host context may be +// discarded during the course of the test. + +// Opens a blank page for use as a portal host. +// Tests cannot simply use window.open() without a URL as about:blank may not +// host a portal. +async function openBlankPortalHost() { + let hostWindow = window.open('/portals/resources/blank-host.html'); + await new Promise((resolve) => { + hostWindow.addEventListener('load', resolve, {once: true}); + }); + return hostWindow; +} diff --git a/testing/web-platform/tests/portals/resources/portal-activate-broadcastchannel.html b/testing/web-platform/tests/portals/resources/portal-activate-broadcastchannel.html new file mode 100644 index 0000000000..b922afaec2 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-activate-broadcastchannel.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<script> +onportalactivate = e => { + let bc = new BroadcastChannel(new URL(location).searchParams.get('bc')); + bc.postMessage({event: 'portalactivate', data: e.data}); + bc.close(); +}; +</script> diff --git a/testing/web-platform/tests/portals/resources/portal-activate-data-portal.html b/testing/web-platform/tests/portals/resources/portal-activate-data-portal.html new file mode 100644 index 0000000000..0842ad82ef --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-activate-data-portal.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<script> +let logic = new Function('event', (new URL(location)).searchParams.get('logic')); +onload = () => window.portalHost.postMessage('ready'); +onportalactivate = event => { + var portal = event.adoptPredecessor(); + portal.postMessage(logic(event)); +}; +</script> diff --git a/testing/web-platform/tests/portals/resources/portal-activate-event-portal.html b/testing/web-platform/tests/portals/resources/portal-activate-event-portal.html new file mode 100644 index 0000000000..6de5aafca7 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-activate-event-portal.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<title>Tests that the PortalActivateEvent is dispatched when a portal is activated</title> +<script> + var test = (new URL(location)).searchParams.get("test"); + + function portalActivate(e) { + var bc = new BroadcastChannel("test-" + test); + bc.postMessage("passed"); + bc.close(); + } + + if (test == "bodyeventhandler") { + document.write('<body onportalactivate="portalActivate()"></body>'); + } else if (test == "eventhandler") { + window.onportalactivate = portalActivate; + } else if (test == "eventlistener") { + window.addEventListener("portalactivate", portalActivate); + } + + window.portalHost.postMessage("loaded"); +</script> diff --git a/testing/web-platform/tests/portals/resources/portal-activate-in-handler.html b/testing/web-platform/tests/portals/resources/portal-activate-in-handler.html new file mode 100644 index 0000000000..746ffa2b39 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-activate-in-handler.html @@ -0,0 +1,51 @@ +<!DOCTYPE html> +<html> + <head> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <script src="/resources/testdriver.js"></script> + <script src="/resources/testdriver-vendor.js"></script> + </head> + <body> + </body> + <script> + // This page is reused with a different query parameter indicating which + // handler to register and activate a portal from. + const handler_name = window.location.search.substring(1); + + const portal_element = document.createElement('portal'); + portal_element.src = 'simple-portal.html'; + document.body.appendChild(portal_element); + + let page_loaded = false; + let portal_loaded = false; + + function notifyReady() { + if (page_loaded && portal_loaded) { + window.opener.postMessage('done', '*'); + } + } + + portal_element.addEventListener('load', () => { + portal_loaded = true; + notifyReady(); + }); + + window.addEventListener('load', () => { + page_loaded = true; + notifyReady(); + }); + + // This will be used to let the parent page know the handler has run and + // |portal_promise| is now valid. + window.opener.handler_called_promise = new Promise((resolve) => { + window.addEventListener(handler_name, () => { + window.opener.portal_promise = portal_element.activate(); + + // Let the parent page know it can now look at |portal_promise|. + resolve(); + }, {once: true}); + }); + + </script> +</html> diff --git a/testing/web-platform/tests/portals/resources/portal-activate-inside-portal.html b/testing/web-platform/tests/portals/resources/portal-activate-inside-portal.html new file mode 100644 index 0000000000..ff8bead324 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-activate-inside-portal.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<body> + <script> + var portal = document.createElement("portal"); + portal.src = "simple-portal.html"; + portal.onload = () => { + portal.activate().catch(e => window.portalHost.postMessage(e.name)); + } + document.body.appendChild(portal); + </script> +</body> diff --git a/testing/web-platform/tests/portals/resources/portal-activate-twice-window-1.html b/testing/web-platform/tests/portals/resources/portal-activate-twice-window-1.html new file mode 100644 index 0000000000..fbc5a6e93d --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-activate-twice-window-1.html @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<body> + <script> + var portal = document.createElement("portal"); + portal.src = "simple-portal.html" + portal.onload = () => { + portal.activate(); + portal.activate().catch(e => window.opener.postMessage(e.name, "*")); + } + document.body.append(portal); + </script> +</body> diff --git a/testing/web-platform/tests/portals/resources/portal-activate-twice-window-2.html b/testing/web-platform/tests/portals/resources/portal-activate-twice-window-2.html new file mode 100644 index 0000000000..6ba8dc5839 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-activate-twice-window-2.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<body> + <script> + var portal1 = document.createElement("portal"); + portal1.src = "simple-portal.html" + var portal2 = document.createElement("portal"); + portal2.src = "simple-portal.html" + + var waitForPortalToLoad = portal => new Promise((resolve, reject) => { + portal.onload = resolve; + }); + + Promise.all([waitForPortalToLoad(portal1), + waitForPortalToLoad(portal2)]).then(() => { + portal1.activate(); + portal2.activate().catch(e => window.opener.postMessage(e.name, "*")); + }); + + document.body.append(portal1); + document.body.append(portal2); + </script> +</body> diff --git a/testing/web-platform/tests/portals/resources/portal-close-window.html b/testing/web-platform/tests/portals/resources/portal-close-window.html new file mode 100644 index 0000000000..a12af3cd7a --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-close-window.html @@ -0,0 +1,7 @@ +<!DOCTYPE html> +<script> +onload = () => { + window.close(); + window.portalHost.postMessage(window.closed); +}; +</script> diff --git a/testing/web-platform/tests/portals/resources/portal-embed-and-activate.html b/testing/web-platform/tests/portals/resources/portal-embed-and-activate.html new file mode 100644 index 0000000000..04f15b7fda --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-embed-and-activate.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<!-- + Embeds a portal (src specified by query parameter "url") and activates it after + receiving a message from the portal. +--> +</title> +<body> + <script> + var searchParams = new URL(location).searchParams; + let portal = document.createElement("portal"); + portal.src = searchParams.get("url"); + portal.onmessage = () => { portal.activate(); } + document.body.appendChild(portal); + </script> +</body> diff --git a/testing/web-platform/tests/portals/resources/portal-host-cross-origin-navigate.sub.html b/testing/web-platform/tests/portals/resources/portal-host-cross-origin-navigate.sub.html new file mode 100644 index 0000000000..26f655a0db --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-host-cross-origin-navigate.sub.html @@ -0,0 +1,7 @@ +<!DOCTYPE html> +<body> + <script> + let key = (new URLSearchParams(window.location.search)).get('key'); + window.location.href = `http://{{hosts[alt][www]}}:{{ports[http][0]}}/portals/resources/portal-host.html?key=${key}`; + </script> +</body> diff --git a/testing/web-platform/tests/portals/resources/portal-host-hidden-after-activation-portal.html b/testing/web-platform/tests/portals/resources/portal-host-hidden-after-activation-portal.html new file mode 100644 index 0000000000..491d184f97 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-host-hidden-after-activation-portal.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<script> + window.addEventListener("portalactivate", function(e) { + var bc = new BroadcastChannel("portals-host-hidden-after-activation"); + bc.postMessage({ hasHost: !!window.portalHost }); + bc.close(); + }); + + var bc = new BroadcastChannel("portals-host-hidden-after-activation"); + bc.postMessage({hasHost: !!window.portalHost }); + bc.close(); + + window.portalHost.postMessage("loaded"); +</script> diff --git a/testing/web-platform/tests/portals/resources/portal-host-post-message-after-activate.html b/testing/web-platform/tests/portals/resources/portal-host-post-message-after-activate.html new file mode 100644 index 0000000000..7b03ac0294 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-host-post-message-after-activate.html @@ -0,0 +1,19 @@ +<!DOCTYPE html> +<script> + window.portalHost.postMessage("loaded"); + + var ph = window.portalHost; + + window.onportalactivate = e => { + var exception_name = "" + try { + ph.postMessage("message"); + } + catch (error) { + exception_name = error.name; + } + bc = new BroadcastChannel("portal-host-post-message-after-activate"); + bc.postMessage(exception_name, "*"); + bc.close(); + }; +</script> diff --git a/testing/web-platform/tests/portals/resources/portal-host-post-message-navigate-1.html b/testing/web-platform/tests/portals/resources/portal-host-post-message-navigate-1.html new file mode 100644 index 0000000000..a59144e7e1 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-host-post-message-navigate-1.html @@ -0,0 +1,5 @@ +<!DOCTYPE html> +<script> + window.portalHost.postMessage("loaded"); + window.location.href = "portal-host-post-message-navigate-2.html" +</script> diff --git a/testing/web-platform/tests/portals/resources/portal-host-post-message-navigate-2.html b/testing/web-platform/tests/portals/resources/portal-host-post-message-navigate-2.html new file mode 100644 index 0000000000..571c4f122e --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-host-post-message-navigate-2.html @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<script> + window.portalHost.postMessage("loaded"); +</script> diff --git a/testing/web-platform/tests/portals/resources/portal-host-post-message-x-origin.html b/testing/web-platform/tests/portals/resources/portal-host-post-message-x-origin.html new file mode 100644 index 0000000000..6cbc7f4b88 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-host-post-message-x-origin.html @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<script> + window.portalHost.postMessage('test message'); +</script> diff --git a/testing/web-platform/tests/portals/resources/portal-host-post-message.html b/testing/web-platform/tests/portals/resources/portal-host-post-message.html new file mode 100644 index 0000000000..1935ee898e --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-host-post-message.html @@ -0,0 +1,51 @@ +<!DOCTYPE html> +<script> + function postMessageWithMessagePorts() { + var channel = new MessageChannel(); + channel.port1.onmessage = e => { + e.ports[0].postMessage("received"); + } + window.portalHost.postMessage("sending port", {transfer: [channel.port2]}); + } + + function postMessageWithArrayBuffer(array, withTransfer) { + var arrayBuffer = new Int8Array(array).buffer; + if (withTransfer) { + window.portalHost.postMessage({arrayBuffer}, {transfer: [arrayBuffer]}); + } else { + window.portalHost.postMessage({arrayBuffer}); + } + } + + function postMessageAndCatchException(...params) { + try { + window.portalHost.postMessage(...params); + } catch (e) { + window.portalHost.postMessage({errorType: e.name}); + } + } + + window.portalHost.addEventListener("message", e => { + if (e.data.type) { + var type = e.data.type; + switch (type) { + case "message-port": + postMessageWithMessagePorts(); + return; + case "array-buffer-without-transfer": + postMessageWithArrayBuffer(e.data.array, false); + return; + case "array-buffer-with-transfer": + postMessageWithArrayBuffer(e.data.array, true); + return; + case "invalid-message": + postMessageAndCatchException(document.body); + return; + case "invalid-port": + postMessageAndCatchException("", {transfer: [null]}); + return; + } + } + window.portalHost.postMessage(...e.data); + }); +</script> diff --git a/testing/web-platform/tests/portals/resources/portal-host.html b/testing/web-platform/tests/portals/resources/portal-host.html new file mode 100644 index 0000000000..e577208236 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-host.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<script src="stash-utils.sub.js"></script> +<body> + <script> + let queryParams = new URLSearchParams(window.location.search); + let key = queryParams.get('key'); + if (key) { + StashUtils.putValue(key, window.portalHost ? "passed" : "failed"); + } + </script> +</body> diff --git a/testing/web-platform/tests/portals/resources/portal-inside-iframe.html b/testing/web-platform/tests/portals/resources/portal-inside-iframe.html new file mode 100644 index 0000000000..5db75d5b5f --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-inside-iframe.html @@ -0,0 +1,4 @@ +<!DOCTYPE html> +<body> + <portal id="portal" /> +</body> diff --git a/testing/web-platform/tests/portals/resources/portal-post-message-after-activate-window.html b/testing/web-platform/tests/portals/resources/portal-post-message-after-activate-window.html new file mode 100644 index 0000000000..73d2c11558 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-post-message-after-activate-window.html @@ -0,0 +1,23 @@ +<!DOCTYPE html> +<body> + <script> + var portal = document.createElement("portal"); + portal.src = "portal-post-message-portal.html"; + document.body.appendChild(portal); + + portal.onload = () => { + portal.activate().then(() => { + error = ""; + try { + portal.postMessage("message"); + } + catch(err) { + error = err.name; + } + bc = new BroadcastChannel("portals-post-message-after-activate"); + bc.postMessage(error); + bc.close(); + }); + } + </script> +</body> diff --git a/testing/web-platform/tests/portals/resources/portal-post-message-before-activate-portal.html b/testing/web-platform/tests/portals/resources/portal-post-message-before-activate-portal.html new file mode 100644 index 0000000000..d34875f981 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-post-message-before-activate-portal.html @@ -0,0 +1,24 @@ +<!DOCTYPE html> +<script> + var postMessagePromise = new Promise((resolve, reject) => { + window.portalHost.addEventListener("message", () => { + resolve(performance.now()); + }); + }); + + var activatePromise = new Promise((resolve, reject) => { + window.onportalactivate = () => { + resolve(performance.now()); + } + }); + + Promise.all([postMessagePromise, activatePromise]) + .then(values => { + bc = new BroadcastChannel("portals-post-message-before-activate"); + bc.postMessage({ + postMessageTS: values[0], + activateTS: values[1] + }); + bc.close(); + }); +</script> diff --git a/testing/web-platform/tests/portals/resources/portal-post-message-before-activate-window.html b/testing/web-platform/tests/portals/resources/portal-post-message-before-activate-window.html new file mode 100644 index 0000000000..6389829c7c --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-post-message-before-activate-window.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<body> + <script> + var portal = document.createElement("portal"); + portal.src = "portal-post-message-before-activate-portal.html"; + document.body.appendChild(portal); + + portal.onload = () => { + portal.postMessage("message"); + portal.activate(); + } + </script> +</body> diff --git a/testing/web-platform/tests/portals/resources/portal-post-message-during-activate-window.html b/testing/web-platform/tests/portals/resources/portal-post-message-during-activate-window.html new file mode 100644 index 0000000000..6e220277d9 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-post-message-during-activate-window.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<body> + <script> + var portal = document.createElement("portal"); + portal.src = "simple-portal.html"; + document.body.appendChild(portal); + + portal.onload = () => { + portal.activate(); + error = ""; + try { + portal.postMessage("message"); + } catch (err) { + error = err.name; + } + bc = new BroadcastChannel("portals-post-message-during-activate"); + bc.postMessage(error); + bc.close(); + } + </script> +</body> diff --git a/testing/web-platform/tests/portals/resources/portal-post-message-portal.html b/testing/web-platform/tests/portals/resources/portal-post-message-portal.html new file mode 100644 index 0000000000..e83ae56e08 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-post-message-portal.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<script> + window.portalHost.onmessage = e => { + var message = { + origin: e.origin, + data: e.data, + sourceIsPortalHost: e.source === window.portalHost, + gotUserActivation: !!e.userActivation, + userActivation: { + isActive: e.userActivation && e.userActivation.isActive, + hasBeenActive: e.userActivation && e.userActivation.hasBeenActive + } + }; + + if (e.data.arrayBuffer) { + message.data = { + array: Array.from(new Uint8Array(e.data.arrayBuffer)) + }; + } + + if (e.ports.length > 0) { + e.ports[0].postMessage(message); + e.ports[0].close(); + return; + } + + window.portalHost.postMessage(message); + }; +</script> diff --git a/testing/web-platform/tests/portals/resources/portal-post-message-x-origin-portal.html b/testing/web-platform/tests/portals/resources/portal-post-message-x-origin-portal.html new file mode 100644 index 0000000000..57631f385c --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-post-message-x-origin-portal.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<script src="stash-utils.sub.js"></script> +<script> + const queryParams = new URLSearchParams(window.location.search); + const key = queryParams.get('key'); + if (key) { + window.portalHost.onmessage = () => { + StashUtils.putValue(key, 'failed'); + }; + } +</script> diff --git a/testing/web-platform/tests/portals/resources/portal-repeated-activate-window.html b/testing/web-platform/tests/portals/resources/portal-repeated-activate-window.html new file mode 100644 index 0000000000..e716034eff --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portal-repeated-activate-window.html @@ -0,0 +1,20 @@ +<!DOCTYPE html> +<body> + <portal src="simple-portal-adopts-and-activates-predecessor.html"> + <script> + function activate() { + var portal = document.querySelector("portal"); + portal.activate().then(() => document.body.removeChild(portal)); + } + + var count = 0; + window.onportalactivate = e => { + ++count; + if (count == 1) { + e.adoptPredecessor().activate(); + } else { + window.opener.postMessage("done", "*"); + } + }; + </script> +</body> diff --git a/testing/web-platform/tests/portals/resources/portals-adopt-predecessor-portal.html b/testing/web-platform/tests/portals/resources/portals-adopt-predecessor-portal.html new file mode 100644 index 0000000000..b838b38be1 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portals-adopt-predecessor-portal.html @@ -0,0 +1,77 @@ +<!doctype html> +<script> + var searchParams = new URL(location).searchParams; + var test = searchParams.get("test"); + + window.onportalactivate = function(e) { + if (test == "adopt-once") { + var portal = e.adoptPredecessor(); + document.body.appendChild(portal); + + if (portal instanceof HTMLPortalElement) { + portal.postMessage("adopted"); + } + } + if (test == "adopt-twice") { + var portal = e.adoptPredecessor(); + document.body.appendChild(portal); + + try { + e.adoptPredecessor(); + } catch(e) { + if (e.name == "InvalidStateError") { + portal.postMessage("passed"); + } + } + } + if (test == "adopt-after-event") { + setTimeout(function() { + try { + e.adoptPredecessor(); + } catch(e) { + if (e.name == "InvalidStateError") { + var bc_test = new BroadcastChannel(`test-${test}`); + bc_test.postMessage("passed"); + bc_test.close(); + } + } + }); + } + if (test == "adopt-and-activate") { + var portal = e.adoptPredecessor(); + portal.activate(); + } + if (test == "adopt-attach-remove") { + var portal = e.adoptPredecessor(); + document.body.appendChild(portal); + setTimeout(() => { + document.body.removeChild(portal); + var bc_test = new BroadcastChannel(`test-${test}`); + bc_test.postMessage("passed"); + bc_test.close(); + }); + } + if (test == "adopt-and-discard") { + var portal = e.adoptPredecessor(); + setTimeout(() => { + // portal should be inactive and activate should fail. + portal.activate().catch(e => { + if (e.name == "InvalidStateError") { + var bc_test = new BroadcastChannel(`test-${test}`); + bc_test.postMessage("passed"); + bc_test.close(); + } + }); + }); + } + if (test == "adopt-to-disconnected-node") { + var portal = e.adoptPredecessor(); + document.body.appendChild(portal); + var node = document.createElement("div"); + node.appendChild(portal); + var bc_test = new BroadcastChannel(`test-${test}`); + bc_test.postMessage("passed"); + bc_test.close(); + } + } +</script> diff --git a/testing/web-platform/tests/portals/resources/portals-adopt-predecessor.html b/testing/web-platform/tests/portals/resources/portals-adopt-predecessor.html new file mode 100644 index 0000000000..66d47d12ac --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portals-adopt-predecessor.html @@ -0,0 +1,20 @@ +<!doctype html> +<body> +</body> +<script> + var searchParams = new URL(location).searchParams; + var test = searchParams.get("test"); + var portal = document.createElement("portal"); + portal.src = `portals-adopt-predecessor-portal.html?test=${test}`; + portal.onload = () => { + portal.activate().then(() => { + window.addEventListener("portalactivate", e => { + window.opener.postMessage({test, message: "passed"}, "*"); + }); + window.portalHost.addEventListener("message", e => { + window.opener.postMessage({test, message: e.data}, "*"); + }); + }); + } + document.body.appendChild(portal); +</script> diff --git a/testing/web-platform/tests/portals/resources/portals-nested-portal.html b/testing/web-platform/tests/portals/resources/portals-nested-portal.html new file mode 100644 index 0000000000..278b32eea0 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portals-nested-portal.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<body> + <script> + var portal = document.createElement("portal"); + portal.src = "simple-portal.html"; + portal.onload = e => window.portalHost.postMessage(e.data); + document.body.appendChild(portal); + </script> +</body> diff --git a/testing/web-platform/tests/portals/resources/portals-rendering-portal.html b/testing/web-platform/tests/portals/resources/portals-rendering-portal.html new file mode 100644 index 0000000000..31b3f4a990 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/portals-rendering-portal.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<body style="background-color: green"> + <script> + window.requestAnimationFrame(function(ts) { + window.portalHost.postMessage("loaded"); + }); + </script> +</body> diff --git a/testing/web-platform/tests/portals/resources/postmessage-referrer.sub.html b/testing/web-platform/tests/portals/resources/postmessage-referrer.sub.html new file mode 100644 index 0000000000..c3837dc79d --- /dev/null +++ b/testing/web-platform/tests/portals/resources/postmessage-referrer.sub.html @@ -0,0 +1,8 @@ +<!DOCTYPE html> +<script> + let message = { + httpReferrer: '{{header_or_default(Referer, no-http-referrer)}}', + documentReferrer: document.referrer || 'no-document-referrer', + }; + window.portalHost.postMessage(message); +</script> diff --git a/testing/web-platform/tests/portals/resources/predecessor-fires-unload-watch-unload.html b/testing/web-platform/tests/portals/resources/predecessor-fires-unload-watch-unload.html new file mode 100644 index 0000000000..f58da48ca1 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/predecessor-fires-unload-watch-unload.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<body> +<script> +function nextEvent(target, type) { + return new Promise((resolve, reject) => target.addEventListener(type, e => resolve(e), {once: true})); +} + +onload = async function() { + const portal = document.createElement('portal'); + portal.src = new URL('simple-portal.html', location.href); + document.body.appendChild(portal); + await nextEvent(portal, 'load'); + + let firedEvents = []; + for (let type of ['pagehide', 'unload']) { + nextEvent(window, type).then(() => { + firedEvents.push(type); + localStorage.setItem('predecessor-fires-unload-events', firedEvents.join(' ')); + }); + } + + portal.activate(); +}; +</script> +</body> diff --git a/testing/web-platform/tests/portals/resources/simple-portal-adopts-and-activates-predecessor.html b/testing/web-platform/tests/portals/resources/simple-portal-adopts-and-activates-predecessor.html new file mode 100644 index 0000000000..56bfd10f64 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/simple-portal-adopts-and-activates-predecessor.html @@ -0,0 +1,6 @@ +<!DOCTYPE html> +<body> + <script> + window.onportalactivate = e => e.adoptPredecessor().activate(); + </script> +</body> diff --git a/testing/web-platform/tests/portals/resources/simple-portal-adopts-predecessor.html b/testing/web-platform/tests/portals/resources/simple-portal-adopts-predecessor.html new file mode 100644 index 0000000000..b5ea9f029d --- /dev/null +++ b/testing/web-platform/tests/portals/resources/simple-portal-adopts-predecessor.html @@ -0,0 +1,7 @@ +<!DOCTYPE html> +<body> + <script> + window.portalHost.postMessage("ready"); + onportalactivate = e => document.body.appendChild(e.adoptPredecessor()); + </script> +</body> diff --git a/testing/web-platform/tests/portals/resources/simple-portal.html b/testing/web-platform/tests/portals/resources/simple-portal.html new file mode 100644 index 0000000000..7d7b678cad --- /dev/null +++ b/testing/web-platform/tests/portals/resources/simple-portal.html @@ -0,0 +1,6 @@ +<!DOCTYPE html> +<body> + <script> + window.portalHost.postMessage("ready"); + </script> +</body> diff --git a/testing/web-platform/tests/portals/resources/stash-utils.sub.js b/testing/web-platform/tests/portals/resources/stash-utils.sub.js new file mode 100644 index 0000000000..30efe83633 --- /dev/null +++ b/testing/web-platform/tests/portals/resources/stash-utils.sub.js @@ -0,0 +1,43 @@ +const STASH_RESPONDER = "wss://{{host}}:{{ports[wss][0]}}/stash_responder_blocking"; + +class StashUtils { + /** + * Sends a request to store (|key|, |tuple|) in Stash + * (https://web-platform-tests.org/tools/wptserve/docs/stash.html). + * @param {string} key A UUID that acts as a key that can be used to retrieve |value| later. + * @param {string} value Value to be stored in Stash. + * @returns {Promise} Promise that resolves once the server responds. + */ + static putValue(key, value) { + return new Promise(resolve => { + const ws = new WebSocket(STASH_RESPONDER); + ws.onopen = () => { + ws.send(JSON.stringify({action: 'set', key: key, value: value})); + }; + ws.onmessage = e => { + ws.close(); + resolve(); + }; + }); + } + + /** + * Retrieves value associated with |key| in Stash. If no value has been + * associated with |key| yet, the method waits for putValue to be called with + * |key|, and a value to be associated, before resolving the return promise. + * @param {string} key A UUID that uniquely identifies the value to retrieve. + * @returns {Promise<string>} A promise that resolves with the value associated with |key|. + */ + static takeValue(key) { + return new Promise(resolve => { + const ws = new WebSocket(STASH_RESPONDER); + ws.onopen = () => { + ws.send(JSON.stringify({action: 'get', key: key})); + }; + ws.onmessage = e => { + ws.close(); + resolve(JSON.parse(e.data).value); + }; + }); + } +} |