Fullscreen Capability Delegation: Refine activation consumption & tests
Consume source_frame transient user activation on delegation attempts.
Add same-origin subframe and same/cross-origin popup WPT coverage files.
Refactor the existing WPT so the new tests share and use similar code.
Move and rename WPTs to a new html/capability-delegation folder.
Bug: 1293083, 1326575
Change-Id: I0a232fb58e2b8c575e3afa8b6e76f3650a56b505
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3688764
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Mustaq Ahmed <mustaq@chromium.org>
Auto-Submit: Mike Wasserman <msw@chromium.org>
Commit-Queue: Mike Wasserman <msw@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1011876}
diff --git a/fullscreen/api/delegate-request.https.sub.tentative.html b/fullscreen/api/delegate-request.https.sub.tentative.html
deleted file mode 100644
index 37e0099..0000000
--- a/fullscreen/api/delegate-request.https.sub.tentative.html
+++ /dev/null
@@ -1,88 +0,0 @@
-<!DOCTYPE html>
-<!--
- Tentative due to:
- https://github.com/WICG/capability-delegation/issues/10
--->
-<title>Fullscreen request delegation test</title>
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/testdriver.js"></script>
-<script src="/resources/testdriver-actions.js"></script>
-<script src="/resources/testdriver-vendor.js"></script>
-
-<div>
- Verifies that element.requestFullscreen() call from a cross-origin subframe without user
- activation works if and only if the top frame has user activation and it delegates the capability
- to the subframe.
-
- https://wicg.github.io/capability-delegation/spec.html
-
- See wpt/html/user-activation/propagation*.html for child->parent user activation visibility tests.
- TODO: Check same-origin iframes, sibling frames, and popup<->opener delegation.
-</div>
-
-<iframe allow="fullscreen" width="300px" height="50px"
- src="https://{{hosts[alt][www]}}:{{ports[https][0]}}/fullscreen/api/resources/delegate-request-subframe.html">
-</iframe>
-
-<script>
- // Returns a |Promise| that gets resolved with |event.data| when |window|
- // receives from |source| a "message" event whose |event.data.type| matches the string
- // |message_data_type|.
- function getMessageData(message_data_type, source) {
- return new Promise(resolve => {
- function waitAndRemove(e) {
- if (e.source != source || !e.data || e.data.type != message_data_type)
- return;
- window.removeEventListener("message", waitAndRemove);
- resolve(e.data);
- }
- window.addEventListener("message", waitAndRemove);
- });
- }
-
- promise_setup(async () => {
- // Make sure the iframe has loaded.
- await getMessageData("subframe-loaded", frames[0]);
- });
-
- const target_origin = "https://{{hosts[alt][www]}}:{{ports[https][0]}}";
- const request = {"type": "make-fullscreen-request"};
-
- promise_test(async () => {
- let result_promise = getMessageData("result", frames[0]);
- frames[0].postMessage(request, {targetOrigin: target_origin});
- let data = await result_promise;
-
- assert_equals(data.result, "failure");
- }, "Fullscreen-request from a subframe fails without delegation when the top frame has no user activation");
-
- promise_test(async () => {
- let result_promise = getMessageData("result", frames[0]);
- frames[0].postMessage(request, {targetOrigin: target_origin,
- delegate: "fullscreen"});
- let data = await result_promise;
-
- assert_equals(data.result, "failure");
- }, "Fullscreen-request from a subframe fails with delegation when the top frame has no user activation");
-
- promise_test(async () => {
- let result_promise = getMessageData("result", frames[0]);
- await test_driver.bless();
- frames[0].postMessage(request, {targetOrigin: target_origin});
- let data = await result_promise;
-
- assert_equals(data.result, "failure");
- }, "Fullscreen-request from a subframe fails without delegation when the top frame has user activation");
-
- promise_test(async () => {
- let result_promise = getMessageData("result", frames[0]);
- await test_driver.bless();
- frames[0].postMessage(request, {targetOrigin: target_origin,
- delegate: "fullscreen"});
- let data = await result_promise;
-
- assert_equals(data.result, "success");
- }, "Fullscreen-request from a subframe succeeds with delegation when the top frame has user activation");
-
-</script>
diff --git a/fullscreen/api/resources/delegate-request-subframe.html b/fullscreen/api/resources/delegate-request-subframe.html
deleted file mode 100644
index 9bb9d78..0000000
--- a/fullscreen/api/resources/delegate-request-subframe.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE html>
-<title>Fullscreen request delegation test: subframe</title>
-<body>Subframe body</body>
-
-<script>
- function reportResult(msg) {
- window.top.postMessage({"type": "result", "result": msg}, "*");
- }
-
- document.addEventListener('fullscreenchange', () => {
- if (document.fullscreenElement) {
- reportResult("success");
- document.exitFullscreen();
- }
- });
-
- document.addEventListener('fullscreenerror', () => {
- reportResult("failure");
- });
-
- window.addEventListener("message", e => {
- if (e.data.type == "make-fullscreen-request") {
- document.body.requestFullscreen();
- }
- });
-
- window.top.postMessage({"type": "subframe-loaded"}, "*");
-</script>
diff --git a/html/capability-delegation/delegate-fullscreen-request-popup-cross-origin.https.sub.tentative.html b/html/capability-delegation/delegate-fullscreen-request-popup-cross-origin.https.sub.tentative.html
new file mode 100644
index 0000000..2d531a5
--- /dev/null
+++ b/html/capability-delegation/delegate-fullscreen-request-popup-cross-origin.https.sub.tentative.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<!--
+ Tentative due to:
+ https://github.com/WICG/capability-delegation/issues/10
+-->
+<title>Capability Delegation of Fullscreen Requests: Popup Cross-Origin</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/utils.js"></script>
+
+<div>
+ Verifies that element.requestFullscreen() calls from a cross-origin popup without user activation
+ work if and only if the opener has user activation and it delegates the capability.
+
+ https://wicg.github.io/capability-delegation/spec.html
+</div>
+
+<script>
+ let popup = null;
+
+ function testCrossOriginPopupFullscreenDelegation(capability, activate, expectation) {
+ const message = {"type": "make-fullscreen-request"};
+ const origin = "https://{{hosts[alt][www]}}:{{ports[https][0]}}";
+ const expectationType = expectation ? "succeeds" : "fails";
+ const delegationType = capability ? "with delegation" : "without delegation";
+ const activationType = activate ? "with user activation" : "with no user activation";
+
+ promise_test(async () => {
+ const data = await postCapabilityDelegationMessage(popup, message, origin, capability, activate);
+ assert_equals(data.result, expectation ? "success" : "failure");
+ }, `Fullscreen requests from a cross-origin popup ${expectationType} ${delegationType} from an opener ${activationType}`);
+ }
+
+ promise_setup(async () => {
+ // Make sure the recipient popup has loaded.
+ popup = window.open("https://{{hosts[alt][www]}}:{{ports[https][0]}}/html/capability-delegation/resources/delegate-fullscreen-request-recipient.html",
+ "", "width=300,height=200");
+ return getMessageData("recipient-loaded", popup);
+ });
+
+ testCrossOriginPopupFullscreenDelegation(/*capability=*/"", /*activate=*/false, /*expectation=*/false);
+ testCrossOriginPopupFullscreenDelegation(/*capability=*/"fullscreen", /*activate=*/false, /*expectation=*/false);
+ testCrossOriginPopupFullscreenDelegation(/*capability=*/"", /*activate=*/true, /*expectation=*/false);
+ testCrossOriginPopupFullscreenDelegation(/*capability=*/"fullscreen", /*activate=*/true, /*expectation=*/true);
+</script>
diff --git a/html/capability-delegation/delegate-fullscreen-request-popup-same-origin.https.tentative.html b/html/capability-delegation/delegate-fullscreen-request-popup-same-origin.https.tentative.html
new file mode 100644
index 0000000..d429095
--- /dev/null
+++ b/html/capability-delegation/delegate-fullscreen-request-popup-same-origin.https.tentative.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<!--
+ Tentative due to:
+ https://github.com/WICG/capability-delegation/issues/10
+-->
+<title>Capability Delegation of Fullscreen Requests: Popup Same-Origin</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/utils.js"></script>
+
+<div>
+ Verifies that element.requestFullscreen() calls from a same-origin popup without user activation
+ work if and only if the opener has user activation and it delegates the capability.
+
+ https://wicg.github.io/capability-delegation/spec.html
+</div>
+
+<script>
+ let popup = null;
+
+ function testSameOriginPopupFullscreenDelegation(capability, activate, expectation) {
+ const message = {"type": "make-fullscreen-request"};
+ const expectationType = expectation ? "succeeds" : "fails";
+ const delegationType = capability ? "with delegation" : "without delegation";
+ const activationType = activate ? "with user activation" : "with no user activation";
+
+ promise_test(async () => {
+ const data = await postCapabilityDelegationMessage(popup, message, location.origin, capability, activate);
+ assert_equals(data.result, expectation ? "success" : "failure");
+ }, `Fullscreen requests from a same-origin popup ${expectationType} ${delegationType} from an opener ${activationType}`);
+ }
+
+ promise_setup(async () => {
+ // Make sure the recipient popup has loaded.
+ popup = window.open("./resources/delegate-fullscreen-request-recipient.html",
+ "", "width=300,height=200");
+ return getMessageData("recipient-loaded", popup);
+ });
+
+ testSameOriginPopupFullscreenDelegation(/*capability=*/"", /*activate=*/false, /*expectation=*/false);
+ testSameOriginPopupFullscreenDelegation(/*capability=*/"fullscreen", /*activate=*/false, /*expectation=*/false);
+ testSameOriginPopupFullscreenDelegation(/*capability=*/"", /*activate=*/true, /*expectation=*/false);
+ testSameOriginPopupFullscreenDelegation(/*capability=*/"fullscreen", /*activate=*/true, /*expectation=*/true);
+</script>
diff --git a/html/capability-delegation/delegate-fullscreen-request-subframe-cross-origin.https.sub.tentative.html b/html/capability-delegation/delegate-fullscreen-request-subframe-cross-origin.https.sub.tentative.html
new file mode 100644
index 0000000..5f2d2f6
--- /dev/null
+++ b/html/capability-delegation/delegate-fullscreen-request-subframe-cross-origin.https.sub.tentative.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<!--
+ Tentative due to:
+ https://github.com/WICG/capability-delegation/issues/10
+-->
+<title>Capability Delegation of Fullscreen Requests: Subframe Cross-Origin</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/utils.js"></script>
+
+<div>
+ Verifies that element.requestFullscreen() calls from a cross-origin subframe without user
+ activation work if and only if the top frame has user activation and it delegates the capability.
+
+ https://wicg.github.io/capability-delegation/spec.html
+
+ See wpt/html/user-activation/propagation*.html for frame tree user activation visibility tests.
+</div>
+
+<iframe allow="fullscreen" width="300px" height="50px"
+ src="https://{{hosts[alt][www]}}:{{ports[https][0]}}/html/capability-delegation/resources/delegate-fullscreen-request-recipient.html">
+</iframe>
+
+<script>
+ function testCrossOriginSubframeFullscreenDelegation(capability, activate, expectation) {
+ const message = {"type": "make-fullscreen-request"};
+ const origin = "https://{{hosts[alt][www]}}:{{ports[https][0]}}";
+ const expectationType = expectation ? "succeeds" : "fails";
+ const delegationType = capability ? "with delegation" : "without delegation";
+ const activationType = activate ? "with user activation" : "with no user activation";
+
+ promise_test(async () => {
+ const data = await postCapabilityDelegationMessage(frames[0], message, origin, capability, activate);
+ assert_equals(data.result, expectation ? "success" : "failure");
+ }, `Fullscreen requests from a cross-origin subframe ${expectationType} ${delegationType} from an opener ${activationType}`);
+ }
+
+ promise_setup(async () => {
+ // Make sure the recipient iframe has loaded.
+ return getMessageData("recipient-loaded", frames[0]);
+ });
+
+ testCrossOriginSubframeFullscreenDelegation(/*capability=*/"", /*activate=*/false, /*expectation=*/false);
+ testCrossOriginSubframeFullscreenDelegation(/*capability=*/"fullscreen", /*activate=*/false, /*expectation=*/false);
+ testCrossOriginSubframeFullscreenDelegation(/*capability=*/"", /*activate=*/true, /*expectation=*/false);
+ testCrossOriginSubframeFullscreenDelegation(/*capability=*/"fullscreen", /*activate=*/true, /*expectation=*/true);
+</script>
diff --git a/html/capability-delegation/delegate-fullscreen-request-subframe-same-origin.https.tentative.html b/html/capability-delegation/delegate-fullscreen-request-subframe-same-origin.https.tentative.html
new file mode 100644
index 0000000..9e5482d
--- /dev/null
+++ b/html/capability-delegation/delegate-fullscreen-request-subframe-same-origin.https.tentative.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<!--
+ Tentative due to:
+ https://github.com/WICG/capability-delegation/issues/10
+-->
+<title>Capability Delegation of Fullscreen Requests: Subframe Same-Origin</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/utils.js"></script>
+
+<div>
+ Verifies that element.requestFullscreen() calls from a same-origin subframe without user
+ activation work if and only if the top frame has user activation, regardless of whether it
+ delegates the capability or not.
+
+ https://wicg.github.io/capability-delegation/spec.html
+
+ See wpt/html/user-activation/propagation*.html for frame tree user activation visibility tests.
+</div>
+
+<iframe allow="fullscreen" width="300px" height="50px"
+ src="./resources/delegate-fullscreen-request-recipient.html">
+</iframe>
+
+<script>
+ function testSameOriginSubframeFullscreenDelegation(capability, activate, expectation) {
+ const message = {"type": "make-fullscreen-request"};
+ const expectationType = expectation ? "succeeds" : "fails";
+ const delegationType = capability ? "with delegation" : "without delegation";
+ const activationType = activate ? "with user activation" : "with no user activation";
+
+ promise_test(async () => {
+ const data = await postCapabilityDelegationMessage(frames[0], message, window.location, capability, activate);
+ assert_equals(data.result, expectation ? "success" : "failure");
+ }, `Fullscreen requests from a same-origin subframe ${expectationType} ${delegationType} from an opener ${activationType}`);
+ }
+
+ promise_setup(async () => {
+ // Make sure the recipient iframe has loaded.
+ return getMessageData("recipient-loaded", frames[0]);
+ });
+
+ testSameOriginSubframeFullscreenDelegation(/*capability=*/"", /*activate=*/false, /*expectation=*/false);
+ testSameOriginSubframeFullscreenDelegation(/*capability=*/"fullscreen", /*activate=*/false, /*expectation=*/false);
+ testSameOriginSubframeFullscreenDelegation(/*capability=*/"", /*activate=*/true, /*expectation=*/true);
+ testSameOriginSubframeFullscreenDelegation(/*capability=*/"fullscreen", /*activate=*/true, /*expectation=*/true);
+</script>
diff --git a/html/capability-delegation/delegation-consumes-activation.https.tentative.html b/html/capability-delegation/delegation-consumes-activation.https.tentative.html
new file mode 100644
index 0000000..1a8805d
--- /dev/null
+++ b/html/capability-delegation/delegation-consumes-activation.https.tentative.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<!--
+ Tentative due to:
+ https://github.com/whatwg/html/issues/4008
+-->
+<title>Capability Delegation: Consumes User Activation</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/utils.js"></script>
+
+<div>
+ Test that capability delegation consumes transient user activation.
+
+ https://wicg.github.io/capability-delegation/spec.html
+</div>
+
+<iframe allow="payment" width="300px" height="50px" src="about:blank"></iframe>
+
+<script>
+ promise_test(async () => {
+ assert_false(navigator.userActivation.isActive);
+ await test_driver.bless();
+ assert_true(navigator.userActivation.isActive);
+ frames[0].postMessage({"type": "none"}, {targetOrigin: location.origin, delegate: ""});
+ assert_true(navigator.userActivation.isActive);
+ frames[0].postMessage({"type": "none"}, {targetOrigin: location.origin, delegate: "payment"});
+ assert_false(navigator.userActivation.isActive);
+ }, `capability delegation consumes transient user activation`);
+</script>
diff --git a/html/capability-delegation/resources/delegate-fullscreen-request-recipient.html b/html/capability-delegation/resources/delegate-fullscreen-request-recipient.html
new file mode 100644
index 0000000..11daf73
--- /dev/null
+++ b/html/capability-delegation/resources/delegate-fullscreen-request-recipient.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<title>Capability Delegation of Fullscreen Requests test recipient</title>
+<body>Capability Delegation of Fullscreen Requests test recipient body</body>
+
+<script>
+ const initiator = window.opener ? window.opener : window.top;
+ initiator.postMessage({"type": "recipient-loaded"}, "*");
+
+ function reportResult(msg) {
+ initiator.postMessage({"type": "result", "result": msg}, "*");
+ }
+
+ document.addEventListener('fullscreenchange', async () => {
+ if (document.fullscreenElement) {
+ await document.exitFullscreen();
+ reportResult("success");
+ }
+ });
+
+ document.addEventListener('fullscreenerror', () => {
+ reportResult("failure");
+ });
+
+ window.addEventListener("message", e => {
+ if (e.data.type == "make-fullscreen-request") {
+ document.body.requestFullscreen();
+ }
+ });
+</script>
diff --git a/html/capability-delegation/resources/utils.js b/html/capability-delegation/resources/utils.js
new file mode 100644
index 0000000..3add3eb
--- /dev/null
+++ b/html/capability-delegation/resources/utils.js
@@ -0,0 +1,24 @@
+// Returns a Promise that gets resolved with `event.data` when `window` receives from `source` a
+// "message" event whose `event.data.type` matches the string `message_data_type`.
+function getMessageData(message_data_type, source) {
+ return new Promise(resolve => {
+ function waitAndRemove(e) {
+ if (e.source != source || !e.data || e.data.type != message_data_type)
+ return;
+ window.removeEventListener("message", waitAndRemove);
+ resolve(e.data);
+ }
+ window.addEventListener("message", waitAndRemove);
+ });
+}
+
+// A helper that simulates user activation on the current frame if `activate` is true, then posts
+// `message` to `frame` with the target `origin` and specified `capability` to delegate. This helper
+// awaits and returns the result message sent in reply from `frame`.
+async function postCapabilityDelegationMessage(frame, message, origin, capability, activate) {
+ let result_promise = getMessageData("result", frame);
+ if (activate)
+ await test_driver.bless();
+ frame.postMessage(message, {targetOrigin: origin, delegate: capability});
+ return await result_promise;
+}