diff options
Diffstat (limited to 'testing/web-platform/tests/fenced-frame')
7 files changed, 415 insertions, 0 deletions
diff --git a/testing/web-platform/tests/fenced-frame/notify-event-iframe.https.html b/testing/web-platform/tests/fenced-frame/notify-event-iframe.https.html new file mode 100644 index 0000000000..854db2f303 --- /dev/null +++ b/testing/web-platform/tests/fenced-frame/notify-event-iframe.https.html @@ -0,0 +1,102 @@ +<!DOCTYPE html> +<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="/common/utils.js"></script> +<script src="/common/dispatcher/dispatcher.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/utils.js"></script> +<title>Test fenced frame notifyEvent() functionality with iframes</title> + +<body> + <script> + async function runNestedIFrameTest(frame_type) { + // Create a fenced frame that will respond to window.fence.notifyEvent(). + const fencedframe = await attachFencedFrameContext( + {generator_api: 'fledge'}); + let notified = false; + fencedframe.element.addEventListener('fencedtreeclick', () => notified = true); + + await fencedframe.execute(async (frame_type) => { + window.addEventListener('message', (event) => { + window.click_error = event.data; + }); + + let iframe = null; + if (frame_type === 'same-origin') { + iframe = await attachIFrameContext({ + origin: get_host_info().HTTPS_ORIGIN + }); + } else if (frame_type === 'cross-origin') { + iframe = await attachIFrameContext({ + origin: get_host_info().HTTPS_REMOTE_ORIGIN + }); + } + + // Calling notifyEvent() on click in the iframe should fail, but we need + // to move the exception out of the click handler to assert on it. + await iframe.execute(() => { + document.addEventListener('click', (e) => { + try { + window.fence.notifyEvent(e); + } catch (err) { + window.parent.postMessage(err, '*'); + return; + } + window.parent.postMessage(new TypeError('No exception'), '*'); + }); + }); + }, [frame_type]); + + await multiClick(10, 10, fencedframe.element); + + // Ensure the correct exception was thrown. + await fencedframe.execute(() => { + assert_equals(window.click_error.name, 'SecurityError'); + assert_equals(window.click_error.message, + "Failed to execute 'notifyEvent' on 'Fence': notifyEvent is only available in fenced frame roots."); + }); + + // Because the notifyEvent() call failed, no event was sent to the + // top-level fenced frame. + assert_false(notified); + } + + promise_test(async (t) => { + return runNestedIFrameTest('same-origin'); + }, "Test that fenced frame notifyEvent() fails in a nested same-origin iframe."); + + promise_test(async (t) => { + return runNestedIFrameTest('cross-origin'); + }, "Test that fenced frame notifyEvent() fails in a nested cross-origin iframe."); + + promise_test(async (t) => { + window.addEventListener('message', (event) => { + window.click_error = event.data; + }); + + const urn_iframe = await attachIFrameContext( + {generator_api: 'fledge'}); + + await urn_iframe.execute(() => { + document.addEventListener('click', (e) => { + try { + window.fence.notifyEvent(e); + } catch (err) { + window.parent.postMessage(err, '*'); + return; + } + window.parent.postMessage(new TypeError('No exception'), '*'); + }); + }); + + await multiClick(10, 10, urn_iframe.element); + + assert_equals(window.click_error.name, 'SecurityError'); + assert_equals(window.click_error.message, + "Failed to execute 'notifyEvent' on 'Fence': notifyEvent is only available in fenced frame roots."); + }, "Test that notifyEvent() fails in a URN iframe."); + </script> +</body> diff --git a/testing/web-platform/tests/fenced-frame/notify-event-invalid.https.html b/testing/web-platform/tests/fenced-frame/notify-event-invalid.https.html new file mode 100644 index 0000000000..7695f49e0b --- /dev/null +++ b/testing/web-platform/tests/fenced-frame/notify-event-invalid.https.html @@ -0,0 +1,96 @@ +<!DOCTYPE html> +<meta name="timeout" content="long"> +<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="/common/utils.js"></script> +<script src="/common/dispatcher/dispatcher.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/utils.js"></script> +<title>Test that fenced frame notifyEvent() fails with invalid event parameters</title> + +<body> + <script> + promise_test(async (t) => { + const fencedframe = await attachFencedFrameContext( + {generator_api: 'fledge'}); + let notified = false; + fencedframe.element.addEventListener('fencedtreeclick', () => notified = true); + + // Only "click" is supported for now, so any other type of event should + // fail to notify. + await fencedframe.execute(() => { + document.addEventListener('mousedown', (e) => { + try { + window.fence.notifyEvent(e); + } catch (err) { + window.click_error = err; + return; + } + window.click_error = new TypeError('No exception'); + }); + }); + + await multiClick(10, 10, fencedframe.element); + + await fencedframe.execute(() => { + assert_equals(window.click_error.name, 'SecurityError'); + assert_equals(window.click_error.message, + "Failed to execute 'notifyEvent' on 'Fence': notifyEvent called with an unsupported event type."); + }); + + assert_false(notified); + }, "Test that fenced frame notifyEvent() fails using the incorrect event type."); + + promise_test(async (t) => { + const fencedframe = await attachFencedFrameContext( + {generator_api: 'fledge'}); + let notified = false; + fencedframe.element.addEventListener('fencedtreeclick', () => notified = true); + + await fencedframe.execute(() => { + // Event objects constructed manually are not "trusted", so this event + // should fail to notify. "Trusted" means that the event was created by + // the user agent itself. + let fake_click = new Event('click'); + try { + window.fence.notifyEvent(fake_click); + } catch (err) { + assert_equals(err.name, 'SecurityError'); + assert_equals(err.message, "Failed to execute 'notifyEvent' on 'Fence': The triggering_event object is in an invalid state."); + return; + } + assert_unreached('An untrusted event must cause a SecurityError.'); + }); + + assert_false(notified); + }, "Test that fenced frame notifyEvent() fails using an untrusted event."); + + promise_test(async (t) => { + const fencedframe = await attachFencedFrameContext( + {generator_api: 'fledge'}); + let notified = false; + fencedframe.element.addEventListener('fencedtreemousedown', () => { + notified = true; + }); + + // This click handler should not trigger the above handler on the + // HTMLFencedFrameElement, because its type is not 'fencedtreeclick'. + await fencedframe.execute(() => { + document.addEventListener('click', (e) => { + window.fence.notifyEvent(e); + }); + }); + + await multiClick(10, 10, fencedframe.element); + + // Wait 2s to let any event handling code settle. + await new Promise((resolve) => t.step_timeout( + () => resolve(), 2000)); + + assert_false(notified); + }, "Test that fenced frame notifyEvent() only invokes 'fencedtreeclick'."); + </script> +</body> diff --git a/testing/web-platform/tests/fenced-frame/notify-event-nested-fenced-frames.https.html b/testing/web-platform/tests/fenced-frame/notify-event-nested-fenced-frames.https.html new file mode 100644 index 0000000000..d435cbc009 --- /dev/null +++ b/testing/web-platform/tests/fenced-frame/notify-event-nested-fenced-frames.https.html @@ -0,0 +1,41 @@ +<!DOCTYPE html> +<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="/common/utils.js"></script> +<script src="/common/dispatcher/dispatcher.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/utils.js"></script> +<title>Test that notifyEvent() in a nested fenced frame only notifies the immediate parent.</title> + +<body> + <script> + promise_test(async (t) => { + const fencedframe = await attachFencedFrameContext(); + let topmost_notified = false; + fencedframe.element.addEventListener('fencedtreeclick', () => topmost_notified = true); + + await fencedframe.execute(async () => { + const innerframe = await attachFencedFrameContext(); + window.parent_notified = false; + innerframe.element.addEventListener('fencedtreeclick', () => window.parent_notified = true); + + await innerframe.execute(() => { + document.addEventListener('click', (e) => { + window.fence.notifyEvent(e); + }); + }); + }); + + await multiClick(10, 10, fencedframe.element); + + await fencedframe.execute(() => { + assert_true(window.parent_notified); + }); + + assert_false(topmost_notified); + }, "Test that notifyEvent() in a nested fenced frame only notifies the immediate parent."); + </script> +</body> diff --git a/testing/web-platform/tests/fenced-frame/notify-event-success.https.html b/testing/web-platform/tests/fenced-frame/notify-event-success.https.html new file mode 100644 index 0000000000..76ed9abbfa --- /dev/null +++ b/testing/web-platform/tests/fenced-frame/notify-event-success.https.html @@ -0,0 +1,55 @@ +<!DOCTYPE html> +<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="/common/utils.js"></script> +<script src="/common/dispatcher/dispatcher.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/utils.js"></script> +<title>Test that fenced frame notifyEvent() succeeds on click</title> + +<body> + <script> + promise_test(async (t) => { + const fencedframe = await attachFencedFrameContext( + {generator_api: 'fledge'}); + let notified = false; + fencedframe.element.addEventListener('fencedtreeclick', () => notified = true); + + // Add a click handler to the fenced frame's content, which will + // trigger the fenced handler registered above on the fencedframe + // element. + await fencedframe.execute(() => { + document.addEventListener('click', (e) => { + window.fence.notifyEvent(e); + }); + }); + + await multiClick(10, 10, fencedframe.element); + + assert_true(notified); + }, "Test that fenced frame notifyEvent() succeeds on click"); + + promise_test(async (t) => { + const fencedframe = await attachFencedFrameContext( + {generator_api: 'fledge'}); + let notified = false; + fencedframe.element.onfencedtreeclick = () => notified = true; + + // Add a click handler to the fenced frame's content, which will + // trigger the fenced handler registered above on the fencedframe + // element. + await fencedframe.execute(() => { + document.addEventListener('click', (e) => { + window.fence.notifyEvent(e); + }); + }); + + await multiClick(10, 10, fencedframe.element); + + assert_true(notified); + }, "Test that fenced frame notifyEvent() succeeds on click when using the 'onfencedtreeclick' attribute."); + </script> +</body> diff --git a/testing/web-platform/tests/fenced-frame/notify-event-transient-user-activation.https.html b/testing/web-platform/tests/fenced-frame/notify-event-transient-user-activation.https.html new file mode 100644 index 0000000000..ebf93940e5 --- /dev/null +++ b/testing/web-platform/tests/fenced-frame/notify-event-transient-user-activation.https.html @@ -0,0 +1,53 @@ +<!DOCTYPE html> +<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="/common/utils.js"></script> +<script src="/common/dispatcher/dispatcher.js"></script> +<script src="/common/get-host-info.sub.js"></script> +<script src="resources/utils.js"></script> +<title>Test that fenced frame notifyEvent() requires transient activation</title> + +<body> + <script> + promise_test(async (t) => { + const fencedframe = await attachFencedFrameContext( + {generator_api: 'fledge'}); + let notified = false; + fencedframe.element.addEventListener('fencedtreeclick', () => notified = true); + + await fencedframe.execute(() => { + window.retained_activation = false; + document.addEventListener('click', async (e) => { + // Opening a new window consumes transient activation here, but that + // is *not explicitly stated in the spec.* However, we can't rely + // on other APIs to consume activation for us, since most of them are + // gated by permissions policies that fenced frames will not inherit. + // This call will just open a blank page, which is sufficient for + // this test. + window.open(); + await new Promise((resolve) => t.step_timeout( + () => resolve(), 1000)); + if (navigator.userActivation.isActive) { + window.retained_activation = true; + } + window.fence.notifyEvent(e); + }); + }); + + await multiClick(10, 10, fencedframe.element); + + // Wait 3s to let any event handling code settle. + await new Promise((resolve) => t.step_timeout( + () => resolve(), 3000)); + + await fencedframe.execute(() => { + assert_false(window.retained_activation); + }); + + assert_false(notified); + }, "Test that fenced frame notifyEvent() requires transient activation"); + </script> +</body> diff --git a/testing/web-platform/tests/fenced-frame/resources/utils.js b/testing/web-platform/tests/fenced-frame/resources/utils.js index cbea173f17..d6cca91437 100644 --- a/testing/web-platform/tests/fenced-frame/resources/utils.js +++ b/testing/web-platform/tests/fenced-frame/resources/utils.js @@ -250,6 +250,11 @@ function buildRemoteContextForObject(object, uuid, html) { } }; + // If `object` is null (e.g. a window created with noopener), set it to a + // dummy value so that the Proxy constructor won't fail. + if (object == null) { + object = {}; + } const proxy = new Proxy(object, handler); return proxy; } @@ -646,3 +651,19 @@ function setupCSP(csp, second_csp=null) { document.head.appendChild(second_meta); } } + +// Clicking in WPT tends to be flaky (https://crbug.com/1066891), so you may +// need to click multiple times to have an effect. This function clicks at +// coordinates `{x, y}` relative to `click_origin`, by default 3 times. Should +// not be used for tests where multiple clicks have distinct impact on the state +// of the page, but rather to bruteforce through flakes that rely on only one +// click. +async function multiClick(x, y, click_origin, times = 3) { + for (let i = 0; i < times; i++) { + let actions = new test_driver.Actions(); + await actions.pointerMove(x, y, {origin: click_origin}) + .pointerDown() + .pointerUp() + .send(); + } +} diff --git a/testing/web-platform/tests/fenced-frame/revoke-popup.https.html b/testing/web-platform/tests/fenced-frame/revoke-popup.https.html new file mode 100644 index 0000000000..e4a2bb26ad --- /dev/null +++ b/testing/web-platform/tests/fenced-frame/revoke-popup.https.html @@ -0,0 +1,47 @@ +<!DOCTYPE html> +<title>Test that window.fence.disableUntrustedNetwork disables + popup navigations.</title> +<meta name="timeout" content="long"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/utils.js"></script> +<script src="/common/dispatcher/dispatcher.js"></script> +<script src="resources/utils.js"></script> +<script src="/resources/testdriver.js"></script> +<script src="/resources/testdriver-actions.js"></script> +<script src="/resources/testdriver-vendor.js"></script> + +<body> +<script> + +promise_test(async(t) => { + const fencedframe = await attachFencedFrameContext({generator_api: 'fledge'}); + await fencedframe.execute(() => {}); + + const actions = new test_driver.Actions(); + await actions.setContext(window) + .pointerMove(0, 0, {origin: fencedframe.element}) + .pointerDown() + .pointerUp() + .send(); + + await fencedframe.execute(async () => { + await window.fence.disableUntrustedNetwork(); + // After disabling network, popup navigations should not work. + assert_true(navigator.userActivation.isActive, + 'The frame should have user activation.'); + window.popup = attachWindowContext(); + }); + + const result = await Promise.race([ + fencedframe.execute(async () => { + return await window.popup.execute(() => { return 'popup_loaded'; }); + }), + new Promise((resolve) => t.step_timeout( + () => resolve('timeout'), 2000)) + ]); + assert_equals(result, 'timeout'); +}, 'window.fence.disableUntrustedNetwork disables popup navigations'); + +</script> +</body> |