summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/fullscreen
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/fullscreen')
-rw-r--r--testing/web-platform/tests/fullscreen/META.yml5
-rw-r--r--testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-active-document.html27
-rw-r--r--testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-nested-in-iframe.html35
-rw-r--r--testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-nested-shadow-dom.html69
-rw-r--r--testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-nested.html47
-rw-r--r--testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-timing.html46
-rw-r--r--testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-twice.html54
-rw-r--r--testing/web-platform/tests/fullscreen/api/document-exit-fullscreen.html28
-rw-r--r--testing/web-platform/tests/fullscreen/api/document-fullscreen-element.html47
-rw-r--r--testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled-active-document.html19
-rw-r--r--testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled-cross-origin.sub.html37
-rw-r--r--testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled-removing-allowfullscreen.sub.html63
-rw-r--r--testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled-setting-allowfullscreen-timing.sub.html30
-rw-r--r--testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled-setting-allowfullscreen.sub.html37
-rw-r--r--testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled.html17
-rw-r--r--testing/web-platform/tests/fullscreen/api/document-onfullscreenchange.html26
-rw-r--r--testing/web-platform/tests/fullscreen/api/document-onfullscreenerror.html24
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-ready-allowed.html33
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-ready-check-allowed-cross-origin.sub.html31
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-ready-check-containing-iframe.html40
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-ready-check-fullscreen-element-sibling.html25
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-ready-check-fullscreen-iframe-child.html32
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-ready-check-iframe-child.html23
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-ready-check-not-allowed-cross-origin.sub.html42
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-ready-check-not-in-document.html26
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-active-document.html43
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-after-error.html40
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-and-exit-iframe.html97
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-and-move-to-iframe.html61
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-and-move.html26
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-and-remove-iframe.html49
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-and-remove.html24
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-consume-user-activation.html25
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-cross-origin.sub.html143
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-dialog.html24
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-namespaces.html37
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-non-top.html28
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-not-allowed.html24
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-options.html28
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-options.tentative.html27
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-same-element.html27
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-same.html34
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-svg-rect.html31
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-svg-svg.html20
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-timing.html48
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-top.html34
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-twice.html36
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen-two-elements.html30
-rw-r--r--testing/web-platform/tests/fullscreen/api/element-request-fullscreen.html19
-rw-r--r--testing/web-platform/tests/fullscreen/api/fullscreen-display-contents.html56
-rw-r--r--testing/web-platform/tests/fullscreen/api/historical.html38
-rw-r--r--testing/web-platform/tests/fullscreen/api/promises-reject.html22
-rw-r--r--testing/web-platform/tests/fullscreen/api/promises-resolve.html31
-rw-r--r--testing/web-platform/tests/fullscreen/api/resources/attempt-fullscreen.html48
-rw-r--r--testing/web-platform/tests/fullscreen/api/resources/echo-fullscreenEnabled.html11
-rw-r--r--testing/web-platform/tests/fullscreen/api/resources/recursive-iframe-fullscreen.html86
-rw-r--r--testing/web-platform/tests/fullscreen/api/resources/report-fullscreen-enabled.html11
-rw-r--r--testing/web-platform/tests/fullscreen/api/shadowroot-fullscreen-element.html47
-rw-r--r--testing/web-platform/tests/fullscreen/crashtests/backdrop-list-item.html13
-rw-r--r--testing/web-platform/tests/fullscreen/crashtests/chrome-1312699.html21
-rw-r--r--testing/web-platform/tests/fullscreen/crashtests/content-visibility-crash.html31
-rw-r--r--testing/web-platform/tests/fullscreen/idlharness.window.js16
-rw-r--r--testing/web-platform/tests/fullscreen/model/move-to-fullscreen-iframe.html65
-rw-r--r--testing/web-platform/tests/fullscreen/model/move-to-iframe.html44
-rw-r--r--testing/web-platform/tests/fullscreen/model/move-to-inactive-document.html40
-rw-r--r--testing/web-platform/tests/fullscreen/model/remove-child.html33
-rw-r--r--testing/web-platform/tests/fullscreen/model/remove-first.html45
-rw-r--r--testing/web-platform/tests/fullscreen/model/remove-last.html47
-rw-r--r--testing/web-platform/tests/fullscreen/model/remove-parent.html34
-rw-r--r--testing/web-platform/tests/fullscreen/model/remove-single.html34
-rw-r--r--testing/web-platform/tests/fullscreen/rendering/backdrop-iframe-ref.html2
-rw-r--r--testing/web-platform/tests/fullscreen/rendering/backdrop-iframe.html22
-rw-r--r--testing/web-platform/tests/fullscreen/rendering/backdrop-object-ref.html14
-rw-r--r--testing/web-platform/tests/fullscreen/rendering/backdrop-object.html23
-rw-r--r--testing/web-platform/tests/fullscreen/rendering/fullscreen-css-invalidation.html28
-rw-r--r--testing/web-platform/tests/fullscreen/rendering/fullscreen-css-transition.html27
-rw-r--r--testing/web-platform/tests/fullscreen/rendering/fullscreen-pseudo-class-support.html21
-rw-r--r--testing/web-platform/tests/fullscreen/rendering/fullscreen-pseudo-class.html46
-rw-r--r--testing/web-platform/tests/fullscreen/rendering/fullscreen-root-block-scroll.html34
-rw-r--r--testing/web-platform/tests/fullscreen/rendering/fullscreen-root-block-size.html33
-rw-r--r--testing/web-platform/tests/fullscreen/rendering/fullscreen-root-fills-page-ref.html18
-rw-r--r--testing/web-platform/tests/fullscreen/rendering/fullscreen-root-fills-page.html47
-rw-r--r--testing/web-platform/tests/fullscreen/rendering/ua-style-iframe.html80
-rw-r--r--testing/web-platform/tests/fullscreen/trusted-click.js65
84 files changed, 3051 insertions, 0 deletions
diff --git a/testing/web-platform/tests/fullscreen/META.yml b/testing/web-platform/tests/fullscreen/META.yml
new file mode 100644
index 0000000000..fbdb76390c
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/META.yml
@@ -0,0 +1,5 @@
+spec: https://fullscreen.spec.whatwg.org/
+suggested_reviewers:
+ - aliams
+ - foolip
+ - upsuper
diff --git a/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-active-document.html b/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-active-document.html
new file mode 100644
index 0000000000..c96a56f352
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-active-document.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<title>
+ Document#exitFullscreen() when the document is not the active document
+</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<iframe allowfullscreen></iframe>
+<script>
+ promise_test(async (t) => {
+ const iframe = document.querySelector("iframe");
+ const stolenTypeError = iframe.contentWindow.TypeError;
+ const documentBeforeNav = iframe.contentDocument;
+
+ await new Promise((resolve) => {
+ iframe.onload = resolve;
+ iframe.src = "about:blank";
+ });
+
+ await promise_rejects_js(
+ t,
+ stolenTypeError,
+ documentBeforeNav.documentElement.requestFullscreen(),
+ "Promise should be undefined after navigation"
+ );
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-nested-in-iframe.html b/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-nested-in-iframe.html
new file mode 100644
index 0000000000..893814dec3
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-nested-in-iframe.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<title>Document#exitFullscreen() for nested fullscreen inside an iframe</title>
+<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>
+<script src="../trusted-click.js"></script>
+<iframe allowfullscreen></iframe>
+<script>
+ promise_test(async (t) => {
+ const iframe = document.querySelector("iframe");
+ await new Promise((resolve) => {
+ iframe.onload = resolve;
+ iframe.srcdoc = "<div id='outer'><div id='inner'></div></div>";
+ });
+ const iframeDoc = iframe.contentDocument;
+ const outer = iframeDoc.getElementById("outer");
+ const inner = iframeDoc.getElementById("inner");
+
+ // First request fullscreen for the outer element.
+ await Promise.all([fullScreenChange(), trusted_request(outer)]);
+ assert_equals(document.fullscreenElement, iframe);
+ assert_equals(iframeDoc.fullscreenElement, outer);
+
+ // Then request fullscreen for the inner element.
+ await Promise.all([fullScreenChange(), trusted_request(inner)]);
+ assert_equals(document.fullscreenElement, iframe);
+ assert_equals(iframeDoc.fullscreenElement, inner);
+
+ // Now exit fullscreen for the iframe's content document.
+ await Promise.all([fullScreenChange(), iframeDoc.exitFullscreen()]);
+ assert_equals(document.fullscreenElement, null);
+ assert_equals(iframeDoc.fullscreenElement, null);
+ }, "Exit fullscreen for nested fullscreen inside an iframe");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-nested-shadow-dom.html b/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-nested-shadow-dom.html
new file mode 100644
index 0000000000..695ae00322
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-nested-shadow-dom.html
@@ -0,0 +1,69 @@
+<!doctype html>
+<title>Exiting fullscreen from a nested shadow root should work correctly.</title>
+<link rel="author" title="Mozilla" href="https://mozilla.org">
+<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
+<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1652155">
+<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>
+<div id="host">
+ <button>
+ <!--
+ This is gross, but testdriver doesn't let us click stuff in shadow
+ DOM, so here we are instead, using nested slots.
+ -->
+ fullscreen
+ </button>
+</div>
+<script>
+promise_test(async function() {
+ let host = document.getElementById("host");
+ host.attachShadow({ mode: "open" }).innerHTML = `
+ <style>
+ #outer { width: 200px; height: 200px; background: blue }
+ </style>
+ <div id="outer">
+ <slot></slot>
+ </div>
+ `;
+
+ let outer = host.shadowRoot.getElementById("outer");
+ outer.attachShadow({ mode: "open" }).innerHTML = `
+ <style>
+ #inner { width: 100px; height: 100px; background: purple }
+ </style>
+ <div id="inner"></div>
+ <slot></slot>
+ `;
+
+ let button = document.querySelector("button");
+
+ let inner = outer.shadowRoot.getElementById("inner");
+ let finished = new Promise(resolve => {
+ button.addEventListener("click", async function() {
+ await outer.requestFullscreen();
+ assert_equals(outer.getRootNode().fullscreenElement, outer);
+ assert_equals(document.fullscreenElement, host);
+
+ button.addEventListener("click", async function() {
+ await inner.requestFullscreen();
+ assert_equals(inner.getRootNode().fullscreenElement, inner);
+ assert_equals(document.fullscreenElement, host);
+ await document.exitFullscreen();
+ assert_equals(inner.getRootNode().fullscreenElement, null);
+ assert_equals(outer.getRootNode().fullscreenElement, outer);
+ assert_equals(document.fullscreenElement, host);
+ resolve();
+ }, { once: true });
+
+ requestAnimationFrame(() => requestAnimationFrame(() => {
+ test_driver.click(button);
+ }));
+ }, { once: true });
+ });
+
+ test_driver.click(button);
+ await finished;
+}, "Exiting fullscreen from a nested shadow root works correctly.");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-nested.html b/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-nested.html
new file mode 100644
index 0000000000..37332b9b8f
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-nested.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<title>Document#exitFullscreen() for nested fullscreen</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div><div></div></div>
+<script>
+ promise_test(async (t) => {
+ const outer = document.querySelector("div");
+ const inner = outer.firstChild;
+
+ document.onfullscreenerror = t.unreached_func("fullscreenerror event");
+
+ // First request fullscreen for the outer element.
+ await Promise.all([
+ fullScreenChange(),
+ trusted_request(outer),
+ ]);
+
+ assert_equals(document.fullscreenElement, outer);
+
+ // Then request fullscreen for the inner element.
+ const p = trusted_request(inner);
+
+ // Even though we are already in fullscreen, the change in
+ // document.fullscreenElement should not happen synchronously.
+ assert_equals(document.fullscreenElement, outer);
+ await Promise.all([
+ fullScreenChange(),
+ p,
+ ]);
+ assert_equals(document.fullscreenElement, inner);
+
+ // Now exit fullscreen.
+ const exitP = document.exitFullscreen();
+ // Even though we don't need to exit fullscreen, the change in
+ // document.fullscreenElement should not happen synchronously.
+ assert_equals(document.fullscreenElement, inner);
+ await Promise.all([
+ exitP,
+ fullScreenChange(),
+ ]);
+ assert_equals(document.fullscreenElement, outer);
+ }, "Exit fullscreen for nested fullscreen");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-timing.html b/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-timing.html
new file mode 100644
index 0000000000..43e01743b9
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-timing.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<title>Document#exitFullscreen() timing</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<script>
+ promise_test(async (t) => {
+ const div = document.querySelector("div");
+ await trusted_request(div);
+
+ await Promise.all([
+ new Promise((r) => (document.onfullscreenchange = r)),
+ document.exitFullscreen(),
+ ]);
+
+ // If fullscreenchange is an animation frame event, then animation frame
+ // callbacks should be run after it is fired, before the timer callback.
+ // The resize event should fire before the fullscreenchange event.
+ const events = [];
+ const callback = t.step_func((event) => {
+ // fullscreenElement should have changed before either event is fired.
+ assert_equals(
+ document.fullscreenElement,
+ null,
+ `fullscreenElement in ${event.type} event`
+ );
+ events.push(event.type);
+ if (event.type == "fullscreenchange") {
+ step_timeout(t.unreached_func("timer callback"));
+ requestAnimationFrame(
+ t.step_func_done(() => {
+ assert_array_equals(
+ events,
+ ["resize", "fullscreenchange"],
+ "event order"
+ );
+ })
+ );
+ }
+ });
+ document.onfullscreenchange = window.onresize = callback;
+ }, "Timing of fullscreenchange and resize events");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-twice.html b/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-twice.html
new file mode 100644
index 0000000000..aa8538cce4
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen-twice.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<title>Document#exitFullscreen() called twice</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<script>
+ promise_test(async (t) => {
+ const once = { once: true };
+ const div = document.querySelector("div");
+ document.onfullscreenerror = t.unreached_func("fullscreenerror event");
+
+ await Promise.all([
+ fullScreenChange(),
+ trusted_request(div),
+ ]);
+
+ // We are now in fullscreen.
+ assert_equals(document.fullscreenElement, div);
+
+ // Exit fullscreen twice.
+ const firstPromise = document.exitFullscreen();
+ assert_equals(
+ document.fullscreenElement,
+ div,
+ "fullscreenElement after first exitFullscreen()"
+ );
+
+ const secondPromise = document.exitFullscreen();
+ assert_equals(
+ document.fullscreenElement,
+ div,
+ "fullscreenElement after second exitFullscreen()"
+ );
+ const eventChange = new Promise((resolve) => {
+ document.addEventListener("fullscreenchange", resolve, once);
+ document.addEventListener(
+ "fullscreenchange",
+ t.unreached_func("second event fired"),
+ once
+ );
+ });
+
+ await Promise.all([
+ fullScreenChange,
+ firstPromise,
+ secondPromise,
+ eventChange,
+ ]);
+ assert_equals(document.fullscreenElement, null);
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen.html b/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen.html
new file mode 100644
index 0000000000..666950ff55
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/document-exit-fullscreen.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>Document#exitFullscreen()</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<body></body>
+<script>
+ promise_test(async function (t) {
+ const div = document.querySelector("div");
+ // enter fullscreen
+ await trusted_request(div);
+
+ // Exit fullscreen
+ const [event] = await Promise.all([
+ fullScreenChange(),
+ document.exitFullscreen(),
+ ]);
+
+ // Check event from exiting fullscreen
+ assert_equals(event.target, div, "event.target");
+ assert_true(event.bubbles, "event.bubbles");
+ assert_false(event.cancelable, "event.cancelable");
+ assert_true(event.composed, "event.composed");
+ }, "Checks that the fullscreenchange event is fired when exiting fullscreen");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/document-fullscreen-element.html b/testing/web-platform/tests/fullscreen/api/document-fullscreen-element.html
new file mode 100644
index 0000000000..8b3a16a2a8
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/document-fullscreen-element.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<title>Document#fullscreenElement</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<script>
+ promise_test(async function (t) {
+ const div = document.querySelector("div");
+
+ await trusted_click();
+
+ assert_equals(
+ document.fullscreenElement,
+ null,
+ "fullscreenElement before requestFullscreen()"
+ );
+
+ const fsPromise = div.requestFullscreen();
+ assert_equals(
+ document.fullscreenElement,
+ null,
+ "fullscreenElement after requestFullscreen()"
+ );
+ await fsPromise;
+ assert_equals(
+ document.fullscreenElement,
+ div,
+ "fullscreenElement before exitFullscreen()"
+ );
+ const exitPromise = document.exitFullscreen();
+ assert_equals(
+ document.fullscreenElement,
+ div,
+ "fullscreenElement after exitFullscreen()"
+ );
+ await Promise.all([fullScreenChange(), exitPromise]);
+
+ assert_equals(
+ document.fullscreenElement,
+ null,
+ "fullscreenElement after exiting fullscreen"
+ );
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled-active-document.html b/testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled-active-document.html
new file mode 100644
index 0000000000..360982c4a5
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled-active-document.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>
+ Document#fullscreenEnabled when the document is not the active document
+</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<iframe allowfullscreen></iframe>
+<script>
+ promise_test(async (t) => {
+ const iframe = document.querySelector("iframe");
+ const documentBeforeNav = iframe.contentDocument;
+ await new Promise((resolve) => {
+ iframe.onload = resolve;
+ iframe.src = "/common/blank.html";
+ });
+ assert_false(documentBeforeNav.fullscreenEnabled)
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled-cross-origin.sub.html b/testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled-cross-origin.sub.html
new file mode 100644
index 0000000000..bcfc98bbca
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled-cross-origin.sub.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>Document#fullscreenEnabled</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<iframe src="resources/report-fullscreen-enabled.html" name="same-origin-default"></iframe>
+<iframe src="resources/report-fullscreen-enabled.html" allowfullscreen name="same-origin-allow"></iframe>
+<iframe src="http://{{hosts[][]}}:{{ports[http][0]}}/fullscreen/api/resources/report-fullscreen-enabled.html" name="cross-origin-default"></iframe>
+<iframe src="http://{{hosts[][]}}:{{ports[http][1]}}/fullscreen/api/resources/report-fullscreen-enabled.html" allowfullscreen name="cross-origin-allow"></iframe>
+<script>
+var expectations = {
+ "same-origin-default": true,
+ "same-origin-allow": true,
+ "cross-origin-default": false,
+ "cross-origin-allow": true
+};
+
+var tests = {};
+for (var name in expectations) {
+ tests[name] = async_test( 'Fullscreen enabled test: ' + name);
+}
+
+// When a message is received from a child frame, ensure that the report
+// matches the expectations.
+window.addEventListener('message', e => {
+ if (e.data.report && e.data.report.api == "fullscreen") {
+ if (e.data.report.frame in expectations) {
+ tests[e.data.report.frame].step(() => {
+ assert_equals(e.data.report.enabled, expectations[e.data.report.frame],
+ e.data.report.frame + " frame fullscreenEnabled");
+ });
+ delete expectations[e.data.report.frame];
+ tests[e.data.report.frame].done();
+ }
+ }
+});
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled-removing-allowfullscreen.sub.html b/testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled-removing-allowfullscreen.sub.html
new file mode 100644
index 0000000000..687a4ff1e4
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled-removing-allowfullscreen.sub.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<title>
+ Document#fullscreenEnabled removing allowfullscreen after load and then
+ navigating
+</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<iframe></iframe>
+<script>
+ function requestStatus(iframe) {
+ iframe.contentWindow.postMessage(
+ "What is document.fullscreenEnabled?",
+ "*"
+ );
+ return new Promise((resolve) => {
+ window.addEventListener("message", function listener(e) {
+ window.removeEventListener("message", listener);
+ resolve(event.data);
+ });
+ });
+ }
+
+ promise_test(async (t) => {
+ const iframe = document.querySelector("iframe");
+ iframe.allowFullscreen = true;
+ assert_true(iframe.allowFullscreen, "allowFullscreen is false");
+ assert_true(
+ iframe.hasAttribute("allowfullscreen"),
+ "allowFullscreen attribute is present"
+ );
+ await new Promise((resolve) => {
+ iframe.onload = resolve;
+ const path = location.pathname.substring(
+ 0,
+ location.pathname.lastIndexOf("/") + 1
+ );
+ iframe.src = `http://{{hosts[][]}}:{{ports[http][0]}}${path}resources/echo-fullscreenEnabled.html`;
+ });
+
+ assert_true(
+ await requestStatus(iframe),
+ "document.fullscreenEnabled in the iframe, before navigation"
+ );
+
+ iframe.allowFullscreen = false;
+ assert_false(iframe.allowFullscreen, "allowFullscreen is false");
+ assert_false(
+ iframe.hasAttribute("allowfullscreen"),
+ "allowFullscreen attribute is not present"
+ );
+
+ await new Promise((resolve) => {
+ iframe.onload = resolve;
+ iframe.contentWindow.location.href = iframe.src + "?2";
+ });
+
+ assert_false(
+ await requestStatus(iframe),
+ "document.fullscreenEnabled in the iframe, after navigation"
+ );
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled-setting-allowfullscreen-timing.sub.html b/testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled-setting-allowfullscreen-timing.sub.html
new file mode 100644
index 0000000000..49d91c8501
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled-setting-allowfullscreen-timing.sub.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>Document#fullscreenEnabled setting allowfullscreen after document creation, before response</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+// Set allowfullscreen attribute in a timeout after <iframe> has been inserted to the document.
+// The iframe's response is delayed so it happens after the attribute is set.
+
+async_test((t) => {
+ const iframe = document.createElement('iframe');
+ // no allowfullscreen attribute
+
+ const path = location.pathname.substring(0, location.pathname.lastIndexOf('/') + 1);
+ iframe.src = "http://{{hosts[][]}}:{{ports[http][0]}}" + path + "resources/echo-fullscreenEnabled.html?pipe=trickle(d1)";
+ iframe.onload = t.step_func(() => {
+ iframe.contentWindow.postMessage('What is document.fullscreenEnabled?', '*');
+ });
+
+ window.onmessage = t.step_func_done((e) => {
+ assert_false(e.data, 'document.fullscreenEnabled in the iframe');
+ });
+
+ document.body.appendChild(iframe);
+
+ t.step_timeout(() => {
+ iframe.allowFullscreen = true;
+ }, 10);
+});
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled-setting-allowfullscreen.sub.html b/testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled-setting-allowfullscreen.sub.html
new file mode 100644
index 0000000000..4894fa0663
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled-setting-allowfullscreen.sub.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>Document#fullscreenEnabled setting allowfullscreen after load and then navigating</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test((t) => {
+ const iframe = document.createElement('iframe');
+ // no allowfullscreen attribute
+
+ let i = 0;
+
+ const path = location.pathname.substring(0, location.pathname.lastIndexOf('/') + 1);
+ iframe.src = "http://{{hosts[][]}}:{{ports[http][0]}}" + path + "resources/echo-fullscreenEnabled.html";
+ iframe.onload = t.step_func(() => {
+ if (i === 0) {
+ iframe.allowFullscreen = true;
+ }
+ iframe.contentWindow.postMessage('What is document.fullscreenEnabled?', '*');
+ });
+
+ window.onmessage = t.step_func((e) => {
+ i++;
+ if (i === 1) {
+ assert_false(e.data, 'document.fullscreenEnabled in the iframe, before navigation');
+
+ // Navigate the iframe. This will fire a second 'load' event on the iframe.
+ iframe.contentWindow.location.href = iframe.src + '?2';
+ } else {
+ assert_true(e.data, 'document.fullscreenEnabled in the iframe, after navigation');
+ t.done();
+ }
+ });
+
+ document.body.appendChild(iframe);
+});
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled.html b/testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled.html
new file mode 100644
index 0000000000..40430d7bbf
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/document-fullscreen-enabled.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>Document#fullscreenEnabled</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<iframe></iframe>
+<script>
+test(function()
+{
+ assert_true(document.fullscreenEnabled, "top-level document");
+ const iframe = document.querySelector("iframe");
+ assert_true(iframe.contentDocument.fullscreenEnabled, "same-origin iframe");
+});
+
+// The cross-origin iframe case is tested in
+// /html/semantics/embedded-content/the-iframe-element/iframe-allowfullscreen.html
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/document-onfullscreenchange.html b/testing/web-platform/tests/fullscreen/api/document-onfullscreenchange.html
new file mode 100644
index 0000000000..10503c6ccb
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/document-onfullscreenchange.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<title>Document#onfullscreenchange</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<script>
+ promise_test(async (t) => {
+ const div = document.querySelector("div");
+ assert_equals(
+ document.onfullscreenchange,
+ null,
+ "initial onfullscreenchange"
+ );
+ const [, event] = await Promise.all([
+ trusted_request(div),
+ new Promise((r) =>
+ document.addEventListener("fullscreenchange", r)
+ ),
+ ]);
+ assert_true(event instanceof Event);
+ assert_equals(event.target, div);
+ }, "Checks that the fullscreenchange event is fired when entering fullscreen");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/document-onfullscreenerror.html b/testing/web-platform/tests/fullscreen/api/document-onfullscreenerror.html
new file mode 100644
index 0000000000..ac92a9c24b
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/document-onfullscreenerror.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>Document#onfullscreenerror</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+ promise_test(async (t) => {
+ assert_equals(
+ document.onfullscreenerror,
+ null,
+ "initial onfullscreenerror"
+ );
+ const [, event] = await Promise.all([
+ promise_rejects_js(
+ t,
+ TypeError,
+ document.documentElement.requestFullscreen()
+ ),
+ new Promise((r) => document.addEventListener("fullscreenerror", r)),
+ ]);
+ assert_equals(event.target, document.documentElement);
+ assert_true(event instanceof Event);
+ }, "Checks that the fullscreenerror event is fired when entering fullscreen fails");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-ready-allowed.html b/testing/web-platform/tests/fullscreen/api/element-ready-allowed.html
new file mode 100644
index 0000000000..79890fa82f
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-ready-allowed.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<title>Element ready check with enabled flag not set</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<iframe></iframe>
+<script>
+ promise_test(async function (t) {
+ const iframe = document.querySelector("iframe");
+ await new Promise((r) => {
+ iframe.onload = r;
+ iframe.src = "about:blank";
+ });
+ document.onfullscreenchange = t.unreached_func(
+ "document fullscreenchange event"
+ );
+ document.onfullscreenerror = t.unreached_func(
+ "document fullscreenerror event"
+ );
+ iframe.contentDocument.onfullscreenchange = t.unreached_func(
+ "iframe fullscreenchange event"
+ );
+ assert_false(iframe.allowFullscreen, "fullscreen enabled flag");
+ assert_true(
+ iframe.contentDocument.fullscreenEnabled,
+ "fullscreen enabled flag"
+ );
+ return trusted_request(iframe.contentDocument.body, document.body);
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-ready-check-allowed-cross-origin.sub.html b/testing/web-platform/tests/fullscreen/api/element-ready-check-allowed-cross-origin.sub.html
new file mode 100644
index 0000000000..9c93ed006b
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-ready-check-allowed-cross-origin.sub.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<title>Element ready check with allowfullscreen attribute</title>
+<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>
+<script src="../trusted-click.js"></script>
+<iframe name="cross-origin-allowed" allowfullscreen></iframe>
+<script>
+ promise_test(async (t) => {
+ // Trigger the child frame to report as soon as its content is loaded.
+ const iframe = document.querySelector("iframe");
+ await new Promise((resolve) => {
+ iframe.onload = resolve;
+ iframe.src =
+ "http://{{hosts[][]}}:{{ports[http][0]}}/fullscreen/api/resources/attempt-fullscreen.html";
+ });
+
+ // Activate the child frame.
+ await test_driver.click(iframe);
+
+ // When a message is received from a child frame, ensure that the report
+ // matches the expectations.
+ const messagePromise = promiseMessage(iframe);
+ const data = await messagePromise;
+ assert_true(
+ data.report.result,
+ `${data.report.frame} frame did enter fullscreen`
+ );
+ }, "Element ready check with allowfullscreen attribute");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-ready-check-containing-iframe.html b/testing/web-platform/tests/fullscreen/api/element-ready-check-containing-iframe.html
new file mode 100644
index 0000000000..8d55aea563
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-ready-check-containing-iframe.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<title>Element ready check for containing iframe</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<iframe allowfullscreen></iframe>
+<iframe allowfullscreen></iframe>
+<script>
+ // wait for load event to avoid https://bugzil.la/1493878
+ window.onload = function () {
+ promise_test(async function (t) {
+ const [iframe1, iframe2] = document.getElementsByTagName("iframe");
+
+ iframe2.contentDocument.onfullscreenerror = t.unreached_func(
+ "fullscreenerror event"
+ );
+
+ await Promise.all([
+ trusted_request(
+ iframe1.contentDocument.body,
+ iframe1.contentDocument.body
+ ),
+ fullScreenChange(),
+ ]);
+
+ assert_equals(document.fullscreenElement, iframe1);
+
+ await Promise.all([
+ trusted_request(
+ iframe2.contentDocument.body,
+ iframe1.contentDocument.body
+ ),
+ fullScreenChange(iframe2.contentDocument),
+ ]);
+ }, "Element ready check for containing iframe");
+ };
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-ready-check-fullscreen-element-sibling.html b/testing/web-platform/tests/fullscreen/api/element-ready-check-fullscreen-element-sibling.html
new file mode 100644
index 0000000000..6394c13ee3
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-ready-check-fullscreen-element-sibling.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<title>Element ready check for sibling of fullscreen element</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<div id="a"></div>
+<div id="b"></div>
+<script>
+ promise_test(async (t) => {
+ document.onfullscreenerror = t.unreached_func(
+ "second fullscreenchange event"
+ );
+ const a = document.getElementById("a");
+ const b = document.getElementById("b");
+ await Promise.all([trusted_request(a), fullScreenChange()]);
+
+ assert_equals(document.fullscreenElement, a, "fullscreen element is a");
+
+ await Promise.all([trusted_request(b, a), fullScreenChange()]);
+ assert_equals(document.fullscreenElement, b, "fullscreen element is b");
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-ready-check-fullscreen-iframe-child.html b/testing/web-platform/tests/fullscreen/api/element-ready-check-fullscreen-iframe-child.html
new file mode 100644
index 0000000000..77aad41e7d
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-ready-check-fullscreen-iframe-child.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<title>Element ready check for child of a fullscreen iframe</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<iframe><!-- script inserts div here --></iframe>
+<script>
+ // Verify that an iframe can itself go fullscreen, and that this doesn't
+ // influence the iframe ancestor test of the element ready check.
+ promise_test(async (t) => {
+ document.onfullscreenerror = t.unreached_func("fullscreenerror event");
+ const iframe = document.querySelector("iframe");
+ await Promise.all([trusted_request(iframe), fullScreenChange()]);
+
+ assert_equals(document.fullscreenElement, iframe, "fullscreen element");
+
+ // This adds the div to the iframe element itself, not to the iframe's
+ // contentDocument. It's done here because the HTML parser treats the
+ // content of iframe as a text node.
+ var div = document.createElement("div");
+ iframe.appendChild(div);
+
+ await Promise.all([
+ trusted_request(div, iframe.contentDocument.body),
+ fullScreenChange(),
+ ]);
+ assert_equals(document.fullscreenElement, div);
+ }, "Element ready check for child of a fullscreen iframe");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-ready-check-iframe-child.html b/testing/web-platform/tests/fullscreen/api/element-ready-check-iframe-child.html
new file mode 100644
index 0000000000..9b9d06ad75
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-ready-check-iframe-child.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<title>Element ready check for child of iframe</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<iframe><!-- script inserts child here --></iframe>
+<script>
+ promise_test(async (t) => {
+ document.onfullscreenerror = t.unreached_func("fullscreenerror event");
+ const div = document.createElement("div");
+ document.querySelector("iframe").appendChild(div);
+
+ await Promise.all([
+ trusted_request(div, document.body),
+ fullScreenChange(),
+ ]);
+
+ assert_equals(document.fullscreenElement, div);
+ }, "Element ready check for child of iframe");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-ready-check-not-allowed-cross-origin.sub.html b/testing/web-platform/tests/fullscreen/api/element-ready-check-not-allowed-cross-origin.sub.html
new file mode 100644
index 0000000000..a59906ba9f
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-ready-check-not-allowed-cross-origin.sub.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<title>Element ready check with no allowfullscreen attribute</title>
+<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>
+<script src="../trusted-click.js"></script>
+<body>
+ <iframe name="cross-origin-default"></iframe>
+</body>
+
+<script>
+ // Allow the time bomb to be triggered.
+ setup({ allow_uncaught_exception: true });
+
+ promise_test(async (t) => {
+ t.add_cleanup(() => {
+ if (document.fullscreenElement) return document.exitFullscreen();
+ });
+ const iframe = document.querySelector("iframe");
+ await new Promise((resolve) => {
+ iframe.onload = resolve;
+ iframe.src =
+ "http://{{hosts[][]}}:{{ports[http][0]}}/fullscreen/api/resources/attempt-fullscreen.html";
+ });
+ // Trigger the child frame to report as soon as its content is loaded.
+ await trusted_click();
+ const timeBomb = new Promise((resolve, reject) => {
+ t.step_timeout(() => {
+ const error = new Error("Timed out waiting for message");
+ reject(error);
+ }, 5000);
+ });
+ const data = await Promise.race([promiseMessage(iframe), timeBomb]);
+ // When a message is received from a child frame, ensure that the report
+ // matches the expectations.
+ assert_false(
+ data.report.result,
+ `${data.report.frame} frame entered fullscreen, but allowfullscreen was not set`
+ );
+ }, "Cross-origin element ready check with no allowfullscreen or allow attribute");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-ready-check-not-in-document.html b/testing/web-platform/tests/fullscreen/api/element-ready-check-not-in-document.html
new file mode 100644
index 0000000000..210ccc2ace
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-ready-check-not-in-document.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<title>Element ready check for element not in a document</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<script>
+ promise_test(async function (t) {
+ const div = document.createElement("div");
+ document.onfullscreenchange = t.unreached_func(
+ "fullscreenchange event"
+ );
+ await Promise.all([
+ promise_rejects_js(
+ t,
+ TypeError,
+ trusted_request(div, document.body)
+ ),
+ new Promise((resolve) => {
+ document.onfullscreenerror = resolve;
+ }),
+ ]);
+ }, "Element ready check for element not in a document");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-active-document.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-active-document.html
new file mode 100644
index 0000000000..bac8631059
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-active-document.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<title>
+ Element#requestFullscreen() when the document is not the active document
+</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<iframe allowfullscreen></iframe>
+<script>
+ promise_test(async (t) => {
+ const iframe = document.querySelector("iframe");
+ const typeErrorConstructor = iframe.contentWindow.TypeError;
+ const documentBeforeNav = iframe.contentDocument;
+
+ documentBeforeNav.onfullscreenchange = t.unreached_func(
+ "fullscreenchange event"
+ );
+ documentBeforeNav.onfullscreenerror = t.unreached_func(
+ "fullscreenerror event"
+ );
+
+ await new Promise((r) => {
+ iframe.src = "/common/blank.html";
+ iframe.onload = r;
+ });
+
+ await promise_rejects_js(
+ t,
+ typeErrorConstructor,
+ documentBeforeNav.documentElement.requestFullscreen()
+ );
+
+ // Per spec the fullscreenerror event should be fired at the next animation
+ // frame, but at least Gecko and WebKit will instead effectively do "queue a
+ // task to fire ...". Use both rAF and setTimeout to fail even if the timing
+ // of the (unexpected) event isn't as expected.
+ await new Promise((resolve) => {
+ requestAnimationFrame(() => {
+ t.step_timeout(resolve);
+ });
+ });
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-after-error.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-after-error.html
new file mode 100644
index 0000000000..4278382770
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-after-error.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<title>Element#requestFullscreen() after error</title>
+<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>
+<div id="log"></div>
+<script>
+promise_test(async t => {
+ await new Promise(r => window.onload = r);
+
+ const element1 = document.createElement("div");
+ document.body.appendChild(element1);
+
+ await test_driver.bless("request full screen");
+ let promise = element1.requestFullscreen()
+ await new Promise(r => t.step_timeout(r, 0))
+ document.body.removeChild(element1);
+ try {
+ await promise;
+ assert_unreached("requestFullscreen shouldn't be successful");
+ } catch (e) {
+ }
+ try {
+ await document.exitFullscreen();
+ } catch (e) {
+ }
+
+ const element2 = document.createElement("div");
+ document.body.appendChild(element2);
+
+ await test_driver.bless("request full screen");
+ try {
+ await element2.requestFullscreen();
+ } catch (e) {
+ assert_unreached("requestFullscreen shouldn't throw an error - " + e.message);
+ }
+ await document.exitFullscreen();
+}, "requestFullscreen works even if previous requestFullscreen causes an error");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-and-exit-iframe.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-and-exit-iframe.html
new file mode 100644
index 0000000000..f0bf5f6bac
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-and-exit-iframe.html
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<title>
+ Element#requestFullscreen() and Document#exitFullscreen() in iframe
+</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<iframe allowfullscreen></iframe>
+<script>
+ const iframe = document.querySelector("iframe");
+ let iframeDoc;
+ let iframeBody;
+
+ promise_setup(async () => {
+ const iframe = document.querySelector("iframe");
+ await new Promise((resolve) => {
+ iframe.onload = resolve;
+ iframe.src = "about:blank";
+ });
+ iframeDoc = iframe.contentDocument;
+ iframeBody = iframeDoc.body;
+ });
+ /**
+ *
+ * @param {Document} doc
+ * @param {HTMLElement} value
+ * @returns {Promise<Event>}
+ */
+ function makeChangeListener(doc) {
+ return new Promise((resolve) => {
+ doc.addEventListener("fullscreenchange", resolve, { once: true });
+ });
+ }
+
+ // Both when entering and exiting, the fullscreenchange event is fired first
+ // on the outer document and then on the iframe's document. This is because
+ // the events are fired in animation frame tasks, which run in "frame tree"
+ // order.
+ promise_test(async (t) => {
+ document.onfullscreenerror = t.unreached_func(
+ "document fullscreenerror event"
+ );
+ iframeDoc.onfullscreenerror = t.unreached_func(
+ "iframe fullscreenerror event"
+ );
+ const outerPromise = makeChangeListener(document);
+ const innerPromise = makeChangeListener(iframeDoc);
+ const request = trusted_request(iframeBody, iframeBody);
+
+ const winningEvent = await Promise.race([outerPromise, innerPromise]);
+ assert_equals(winningEvent.target, iframe);
+
+ await Promise.allSettled([outerPromise, innerPromise, request]);
+
+ assert_equals(
+ document.fullscreenElement,
+ iframe,
+ "outer fullscreenElement"
+ );
+
+ assert_equals(
+ iframeDoc.fullscreenElement,
+ iframeBody,
+ "inner fullscreenElement"
+ );
+ }, "Checks that the fullscreenchange events fire in right order when entering fullscreen");
+
+ promise_test(async (t) => {
+ document.onfullscreenerror = t.unreached_func(
+ "document fullscreenerror event"
+ );
+ iframeDoc.onfullscreenerror = t.unreached_func(
+ "iframe fullscreenerror event"
+ );
+ const outerPromise = makeChangeListener(document);
+ const innerPromise = makeChangeListener(iframeDoc);
+ const exitPromise = iframeDoc.exitFullscreen();
+
+ const winningEvent = await Promise.race([outerPromise, innerPromise]);
+ assert_equals(winningEvent.target, iframe);
+
+ await Promise.allSettled([outerPromise, innerPromise, exitPromise]);
+ assert_equals(
+ document.fullscreenElement,
+ null,
+ "outer fullscreenElement"
+ );
+ assert_equals(
+ iframeDoc.fullscreenElement,
+ null,
+ "inner fullscreenElement"
+ );
+ }, "Checks that the fullscreenchange events fire in right order when exiting fullscreen");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-and-move-to-iframe.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-and-move-to-iframe.html
new file mode 100644
index 0000000000..f758835012
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-and-move-to-iframe.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<title>
+ Element#requestFullscreen() followed by moving the element into an iframe
+</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<div id="target"></div>
+<iframe allowfullscreen></iframe>
+<script>
+ // rfsPromise will be uncaught
+ setup({ allow_uncaught_exception: true });
+
+ promise_test(async (t) => {
+ const iframe = document.querySelector("iframe");
+ await new Promise((r) => {
+ iframe.onload = r;
+ iframe.src = "about:blank";
+ });
+ const target = document.getElementById("target");
+ const iframeDoc = iframe.contentDocument;
+
+ iframeDoc.onfullscreenchange = t.unreached_func(
+ "fullscreenchange event in iframe"
+ );
+ iframeDoc.onfullscreenerror = t.unreached_func(
+ "fullscreenerror event in iframe"
+ );
+ document.onfullscreenchange = t.unreached_func(
+ "fullscreenchange event"
+ );
+
+ const errorPromise = new Promise(
+ (resolve) => (document.onfullscreenerror = resolve)
+ );
+ await trusted_click(document.body);
+ const rfsPromise = target.requestFullscreen();
+ iframeDoc.body.appendChild(target);
+ const event = await errorPromise;
+ assert_equals(
+ iframeDoc.fullscreenElement,
+ null,
+ "inner fullscreen element"
+ );
+ assert_equals(
+ document.fullscreenElement,
+ null,
+ "outer fullscreen element"
+ );
+ assert_equals(event.target, document, "event target");
+ await promise_rejects_js(
+ t,
+ TypeError,
+ rfsPromise,
+ "requestFullscreen promise"
+ );
+ }, "Element#requestFullscreen() followed by moving the element into an iframe");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-and-move.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-and-move.html
new file mode 100644
index 0000000000..f031461ce5
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-and-move.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<title>
+ Element#requestFullscreen() followed by moving the element within the
+ document
+</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<div id="target"></div>
+<div id="moveto"></div>
+<script>
+ promise_test(async (t) => {
+ document.onfullscreenerror = t.unreached_func("fullscreenerror event");
+ const target = document.getElementById("target");
+ const moveTo = document.getElementById("moveto");
+ await trusted_click(document.body);
+ const p = target.requestFullscreen();
+ moveTo.appendChild(target);
+ await Promise.all([p, fullScreenChange()]);
+ assert_equals(document.fullscreenElement, target);
+ assert_equals(target.parentNode, moveTo);
+ }, "Element#requestFullscreen() followed by moving the element within the document");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-and-remove-iframe.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-and-remove-iframe.html
new file mode 100644
index 0000000000..991799a48d
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-and-remove-iframe.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<title>
+ Element#requestFullscreen() in iframe followed by removing the iframe
+</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<iframe allowfullscreen></iframe>
+<script>
+ promise_test(async (t) => {
+ const iframe = document.querySelector("iframe");
+ await new Promise((resolve) => {
+ iframe.onload = resolve;
+ iframe.src = "about:blank";
+ });
+
+ const iframeDocument = iframe.contentDocument;
+ document.onfullscreenchange = t.unreached_func(
+ "fullscreenchange event"
+ );
+ document.onfullscreenerror = t.unreached_func("fullscreenerror event");
+ iframeDocument.onfullscreenchange = t.unreached_func(
+ "iframe fullscreenchange event"
+ );
+ iframeDocument.onfullscreenerror = t.unreached_func(
+ "iframe fullscreenerror event"
+ );
+ await trusted_click(document.body);
+ const p = iframeDocument.body.requestFullscreen();
+ const typeErrorConstructor = iframe.contentWindow.TypeError;
+ iframe.remove();
+ // Prevent the tests from hanging if the promise never rejects.
+ const errorPromise = new Promise((_, reject) =>
+ t.step_timeout(() => {
+ assert_unreached("Promise didn't reject.");
+ reject(new Error("Promise didn't reject."));
+ }, 1000)
+ );
+ await Promise.race([
+ promise_rejects_js(t, typeErrorConstructor, p),
+ errorPromise,
+ ]);
+ assert_equals(document.fullscreenElement, null);
+ assert_equals(iframeDocument.fullscreenElement, null);
+ }, "requestFullscreen() in iframe followed by removing the iframe");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-and-remove.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-and-remove.html
new file mode 100644
index 0000000000..436a61b6e1
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-and-remove.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>Element#requestFullscreen() followed by removing the element</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<div id="target"></div>
+<script>
+ promise_test(async (t) => {
+ const target = document.getElementById("target");
+ document.onfullscreenchange = t.unreached_func(
+ "fullscreenchange event"
+ );
+ const errorEventPromise = new Promise(
+ (resolve) => (document.onfullscreenerror = resolve)
+ );
+ await trusted_click(document.body);
+ const p = target.requestFullscreen();
+ target.remove();
+ Promise.all([promise_rejects_js(t, TypeError, p), errorEventPromise]);
+ }, "requestFullscreen() followed by removing the element");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-consume-user-activation.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-consume-user-activation.html
new file mode 100644
index 0000000000..cc4806711d
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-consume-user-activation.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<title>Element#requestFullscreen() 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-vendor.js"></script>
+<div id="log"></div>
+<script>
+promise_test(async (t) => {
+ t.add_cleanup(() => {
+ if (document.fullscreenElement) return document.exitFullscreen();
+ });
+ const div = document.querySelector("div");
+
+ await test_driver.bless("fullscreen");
+ assert_true(navigator.userActivation.isActive, "Activation must be active");
+ // Request fullscreen twice in a row. The first request should consume the
+ // user activation and succeed, and the second request should fail because
+ // of the user activation requirement.
+ const p1 = div.requestFullscreen();
+ assert_false(navigator.userActivation.isActive, "Transient activation is consumed");
+ const p2 = promise_rejects_js(t, TypeError, div.requestFullscreen());
+ await Promise.all([p1, p2]);
+});
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-cross-origin.sub.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-cross-origin.sub.html
new file mode 100644
index 0000000000..5f3a397bbc
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-cross-origin.sub.html
@@ -0,0 +1,143 @@
+<!DOCTYPE html>
+<title>
+ Element#requestFullscreen() works properly with a tree of cross-origin iframes
+</title>
+<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>
+
+<body>
+ <script>
+ function waitFor(action, frameName) {
+ return new Promise((resolve) => {
+ window.addEventListener("message", function listener(e) {
+ if (e.data.action === action && e.data.name === frameName) {
+ window.removeEventListener("message", listener);
+ resolve(event.data);
+ }
+ });
+ });
+ }
+
+ function compare_report(report, expectedEvents) {
+ assert_equals(
+ report.events.length,
+ expectedEvents.length,
+ `Expected report for iframe "${report.frame}" to have ${expectedEvents.length} events: [${expectedEvents}]`
+ );
+ report.events.forEach((value, i) => {
+ assert_equals(
+ value,
+ expectedEvents[i],
+ "Event type matches in order expected"
+ );
+ });
+
+ report.events.length
+ ? assert_false(
+ report.fullscreenElementIsNull,
+ "Event fired, fullscreenElement is set"
+ )
+ : assert_true(
+ report.fullscreenElementIsNull,
+ "No event fired, fullscreenElement is null"
+ );
+ }
+
+ const iframes = [
+ {
+ name: "A",
+ src: "http://{{hosts[][]}}:{{ports[http][0]}}/fullscreen/api/resources/recursive-iframe-fullscreen.html?a",
+ allow_fullscreen: true,
+ expectedEvents: ["fullscreenchange"],
+ },
+ {
+ name: "B",
+ src: "http://{{hosts[][]}}:{{ports[http][1]}}/fullscreen/api/resources/recursive-iframe-fullscreen.html?b",
+ allow_fullscreen: true,
+ expectedEvents: ["fullscreenchange"],
+ },
+ {
+ name: "C",
+ src: "http://{{hosts[alt][]}}:{{ports[http][0]}}/fullscreen/api/resources/recursive-iframe-fullscreen.html?c",
+ allow_fullscreen: true,
+ expectedEvents: ["fullscreenchange"],
+ },
+ {
+ name: "D",
+ src: "http://{{hosts[alt][]}}:{{ports[http][1]}}/fullscreen/api/resources/recursive-iframe-fullscreen.html?d",
+ allow_fullscreen: true,
+ expectedEvents: ["fullscreenchange"],
+ },
+ {
+ name: "E",
+ src: "http://{{hosts[][]}}:{{ports[http][0]}}/fullscreen/api/resources/recursive-iframe-fullscreen.html?e",
+ allow_fullscreen: true,
+ expectedEvents: [],
+ },
+ ];
+
+ promise_setup(async () => {
+ // Add the first iframe.
+ const iframeDetails = iframes[0];
+ const child_frame = document.createElement("iframe");
+ child_frame.allow = iframeDetails.allow_fullscreen ? "fullscreen" : "";
+ child_frame.name = iframeDetails.name;
+ child_frame.style.width = "100%";
+ child_frame.style.height = "100%";
+ child_frame.src = iframeDetails.src;
+ await new Promise((resolve) => {
+ child_frame.onload = resolve;
+ document.body.appendChild(child_frame);
+ });
+
+ // Create the nested iframes.
+ for (let i = 1; i < iframes.length; i++) {
+ const parentName = iframes[i - 1].name;
+ const details = iframes[i];
+ child_frame.contentWindow.postMessage(
+ { action: "addIframe", iframe: details, name: parentName },
+ "*"
+ );
+ await waitFor("load", details.name);
+ }
+ });
+
+ promise_test(async (t) => {
+ t.add_cleanup(() => {
+ if (document.fullscreenElement) {
+ return document.exitFullscreen();
+ }
+ });
+ document.onfullscreenerror = t.unreached_func(
+ "fullscreenerror event fired"
+ );
+ const fsChangeFiredPromise = new Promise((resolve) => {
+ document.onfullscreenchange = resolve;
+ });
+
+ const child_frame = document.querySelector("iframe[name=A]");
+ child_frame.contentWindow.postMessage(
+ {
+ action: "requestFullscreen",
+ name: "D",
+ },
+ "*"
+ );
+
+ await waitFor("requestFullscreen", "D");
+
+ for (const frame of iframes.slice(1)) {
+ const data = {
+ action: "requestReport",
+ name: frame.name,
+ };
+ child_frame.contentWindow.postMessage(data, "*");
+ const { report } = await waitFor("report", frame.name);
+ compare_report(report, frame.expectedEvents);
+ }
+ await fsChangeFiredPromise;
+ }, "Element#requestFullscreen() works properly with a tree of cross-origin iframes");
+ </script>
+</body>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-dialog.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-dialog.html
new file mode 100644
index 0000000000..ee5e21306a
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-dialog.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>Element#requestFullscreen() for dialog element</title>
+<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>
+<div id="log"></div>
+<dialog></dialog>
+<script>
+ promise_test(async (t) => {
+ const dialog = document.querySelector("dialog");
+ assert_true(dialog instanceof HTMLDialogElement);
+ document.onfullscreenchange = t.unreached_func(
+ "fullscreenchange event"
+ );
+ const errorEventPromise = new Promise(
+ (resolve) => (document.onfullscreenerror = resolve)
+ );
+ Promise.all([
+ promise_rejects_js(t, TypeError, dialog.requestFullscreen()),
+ errorEventPromise,
+ ]);
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-namespaces.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-namespaces.html
new file mode 100644
index 0000000000..dffa8dbc90
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-namespaces.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<title>Element#requestFullscreen() for an element in null namespace</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<script>
+ const supportedNS = [
+ { ns: "http://www.w3.org/1999/xhtml", elemName: "div" },
+ { ns: "http://www.w3.org/2000/svg", elemName: "svg" },
+ { ns: "http://www.w3.org/1998/Math/MathML", elemName: "math" },
+ ];
+
+ const unsupportedNS = [null, "https://unknown.namespace", ""];
+
+ for (const ns of unsupportedNS) {
+ promise_test(async (t) => {
+ const element = document.createElementNS(ns, "element");
+ document.body.appendChild(element);
+ document.onfullscreenchange = t.unreached_func(
+ "fullscreenchange event"
+ );
+ await promise_rejects_js(t, TypeError, trusted_request(element));
+ }, `requestFullscreen() fails for an element in ${ns} namespace`);
+ }
+
+ for (const { ns, elemName } of supportedNS) {
+ promise_test(async (t) => {
+ const element = document.createElementNS(ns, elemName);
+ document.body.appendChild(element);
+ await Promise.all([trusted_request(element), fullScreenChange()]);
+ await document.exitFullscreen();
+ }, `requestFullscreen() succeed for an element in ${ns} namespace`);
+ }
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-non-top.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-non-top.html
new file mode 100644
index 0000000000..9bed70d695
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-non-top.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>
+ Element#requestFullscreen() for non-top element in fullscreen element stack
+</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<div id="first">
+ <div id="last"></div>
+</div>
+<script>
+ promise_test(async (t) => {
+ const first = document.getElementById("first");
+ const last = document.getElementById("last");
+
+ await Promise.all([trusted_request(first), fullScreenChange()]);
+ assert_equals(document.fullscreenElement, first);
+
+ await Promise.all([trusted_request(last), fullScreenChange()]);
+ assert_equals(document.fullscreenElement, last);
+
+ await Promise.all([trusted_request(first, last), fullScreenChange()]);
+ assert_equals(document.fullscreenElement, first);
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-not-allowed.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-not-allowed.html
new file mode 100644
index 0000000000..e52895ad7e
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-not-allowed.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<title>
+ Element#requestFullscreen() when not allowed to request fullscreen
+</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+ promise_test(async (t) => {
+ const div = document.querySelector("div");
+ const errorEventPromise = new Promise(
+ (resolve) => (document.onfullscreenerror = resolve)
+ );
+ const [, event] = await Promise.all([
+ promise_rejects_js(t, TypeError, div.requestFullscreen()),
+ errorEventPromise,
+ ]);
+ assert_equals(event.type, "fullscreenerror");
+ assert_equals(event.target, div, "event.target");
+ assert_true(event.bubbles, "event.bubbles");
+ assert_false(event.cancelable, "event.cancelable");
+ assert_true(event.composed, "event.composed");
+ }, "requestFullscreen() when not allowed to request fullscreen");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-options.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-options.html
new file mode 100644
index 0000000000..c11f54f7b5
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-options.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>Element#requestFullscreen({ navigationUI }) support</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body></body>
+<script>
+ // Tests for https://github.com/whatwg/fullscreen/pull/129. Because there are
+ // no normative requirements on what navigationUI should do, just test for
+ // basic support. (One could also check that the three allowed enum valid are
+ // supported and no others, but that would overlap with UA-specific tests.)
+ promise_test(async (t) => {
+ const invalidDict = {
+ get navigationUI() {
+ return "invalid-value";
+ },
+ };
+ await promise_rejects_js(
+ t,
+ TypeError,
+ document.body.requestFullscreen(invalidDict)
+ );
+ await promise_rejects_js(
+ t,
+ TypeError,
+ document.body.requestFullscreen({ navigationUI: "other-invalid-value" })
+ );
+ }, "requestFullscreen() with invalid navigationUI values");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-options.tentative.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-options.tentative.html
new file mode 100644
index 0000000000..b2eb60088a
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-options.tentative.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<title>Element#requestFullscreen({ screen }) tentative support</title>
+<link rel="help" href="https://w3c.github.io/window-placement/" />
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+ promise_test(async (t) => {
+ await test_driver.set_permission(
+ { name: "window-placement" },
+ "granted"
+ );
+
+ const options = {
+ get screen() {
+ return undefined;
+ },
+ };
+
+ await promise_rejects_js(
+ t,
+ TypeError,
+ document.body.requestFullscreen(options)
+ );
+ }, "fullscreenOptions.screen getter is invoked on requestFullscreen");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-same-element.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-same-element.html
new file mode 100644
index 0000000000..a2b04dd173
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-same-element.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<title>Element#requestFullscreen() on the current fullscreen element</title>
+<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>
+<div id="log"></div>
+<script>
+promise_test(async (t) => {
+ t.add_cleanup(() => {
+ if (document.fullscreenElement) return document.exitFullscreen();
+ });
+
+ // Use the body element as the fullscreen element, because the second
+ // test_driver.bless() call needs to insert a button inside of it, which
+ // can't be clicked if another element is already fullscreen.
+ const target = document.body;
+
+ // First enter fullscreen.
+ await test_driver.bless("fullscreen", () => target.requestFullscreen());
+ assert_equals(document.fullscreenElement, target, "fullscreen element after first request");
+
+ // Now request fullscreen again, which should be a no-op.
+ await test_driver.bless("fullscreen", () => target.requestFullscreen());
+ assert_equals(document.fullscreenElement, target, "fullscreen element after second request");
+});
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-same.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-same.html
new file mode 100644
index 0000000000..8569c4df79
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-same.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>Element#requestFullscreen() on the current fullscreen element</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<div id="target"></div>
+<script>
+ promise_test(async (t) => {
+ const target = document.getElementById("target");
+ document.onfullscreenerror = t.unreached_func("fullscreenerror event");
+
+ await Promise.all([
+ fullScreenChange(),
+ trusted_request(target),
+ ]);
+
+ assert_equals(document.fullscreenElement, target);
+
+ // The next requestFullscreen() should fire no events due to "If element is
+ // doc's fullscreen element, terminate these subsubsteps."
+ document.onfullscreenchange = t.unreached_func(
+ "fullscreenchange event"
+ );
+
+ await trusted_click(target);
+ await target.requestFullscreen();
+ assert_equals(document.fullscreenElement, target);
+ // Wait until after the next animation frame.
+ await new Promise((r) => requestAnimationFrame(r));
+ }, "Element#requestFullscreen() on the current fullscreen element");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-svg-rect.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-svg-rect.html
new file mode 100644
index 0000000000..44adfa6898
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-svg-rect.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<title>Element#requestFullscreen() for SVG rect element</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<svg>
+ <rect
+ width="300"
+ height="300"
+ style="fill: rgb(0, 255, 153)"
+ />
+</svg>
+<script>
+ promise_test(async (t) => {
+ const rect = document.querySelector("rect");
+ assert_true(rect instanceof SVGRectElement);
+ document.onfullscreenchange = t.unreached_func(
+ "fullscreenchange event"
+ );
+ await trusted_click(document.body);
+ await Promise.all([
+ promise_rejects_js(t, TypeError, rect.requestFullscreen()),
+ new Promise((resolve) => {
+ document.onfullscreenerror = resolve;
+ }),
+ ]);
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-svg-svg.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-svg-svg.html
new file mode 100644
index 0000000000..e579f6e7d7
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-svg-svg.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<title>Element#requestFullscreen() for SVG svg element</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<svg></svg>
+<script>
+ promise_test(async (t) => {
+ const svg = document.querySelector("svg");
+ assert_true(svg instanceof SVGSVGElement);
+ document.onfullscreenerror = t.unreached_func("fullscreenerror event");
+ await Promise.all([
+ fullScreenChange(),
+ trusted_request(svg),
+ ]);
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-timing.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-timing.html
new file mode 100644
index 0000000000..b7986575ff
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-timing.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<title>Element#requestFullscreen() timing</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<script>
+promise_test(async t => {
+ const div = document.querySelector('div');
+
+ // If fullscreenchange is an animation frame event, then animation frame
+ // callbacks should be run after it is fired, before the timer callback.
+ // The resize event should fire before the fullscreenchange event.
+ const events = [];
+ const callback = t.step_func(event => {
+ // fullscreenElement should have changed before either event is fired.
+ assert_equals(document.fullscreenElement, div, `fullscreenElement in {event.type} event`);
+ events.push(event.type);
+ if (event.type == 'fullscreenchange') {
+ step_timeout(t.unreached_func('timer callback'));
+ requestAnimationFrame(t.step_func_done(() => {
+ assert_array_equals(events, ['resize', 'fullscreenchange'], 'event order');
+ }));
+ }
+ });
+ document.onfullscreenchange = window.onresize = callback;
+ await trusted_request(div);
+}, 'Timing of fullscreenchange and resize events');
+
+async_test(t => {
+ // Gecko throttles requestAnimationFrame before the first paint, so
+ // wrap the test to work around that.
+ requestAnimationFrame(t.step_func(() => {
+ var promise = document.createElement('a').requestFullscreen();
+ var promise_executed = false;
+ promise.catch(()=>{promise_executed = true; });
+ // If fullscreenerror is an animation frame event, then animation frame
+ // callbacks should be run after it is fired, before the timer callback.
+ document.onfullscreenerror = t.step_func(() => {
+ assert_true(promise_executed, "promise executed");
+ step_timeout(t.unreached_func('timer callback'));
+ requestAnimationFrame(t.step_func_done());
+ });
+ }));
+}, 'Timing of fullscreenerror event');
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-top.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-top.html
new file mode 100644
index 0000000000..59211856ab
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-top.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>
+ Element#requestFullscreen() for top element in fullscreen element stack
+</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<div id="top"></div>
+<script>
+ promise_test(async function (t) {
+ const top = document.getElementById("top");
+ document.onfullscreenerror = t.unreached_func("fullscreenerror event");
+
+ await Promise.all([
+ trusted_request(top),
+ new Promise((r) =>
+ document.addEventListener("fullscreenchange", r)
+ ),
+ ]);
+ assert_equals(document.fullscreenElement, top);
+ await trusted_click(top);
+ await top.requestFullscreen();
+ // A fullscreenerror event would be fired after an async section
+ // and an animation frame task, so wait until after that.
+ await new Promise((resolve) => {
+ t.step_timeout(() => {
+ requestAnimationFrame(resolve);
+ });
+ });
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-twice.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-twice.html
new file mode 100644
index 0000000000..db53aec544
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-twice.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>Element#requestFullscreen() twice</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<script>
+ promise_test(async (t) => {
+ const div = document.querySelector("div");
+ await trusted_click(document.body);
+ const p = div.requestFullscreen();
+ assert_equals(
+ document.fullscreenElement,
+ null,
+ "fullscreenElement after first requestFullscreen()"
+ );
+ const rejectedPromises = [
+ promise_rejects_js(t, TypeError, div.requestFullscreen()),
+ promise_rejects_js(t, TypeError, div.requestFullscreen()),
+ ];
+ await Promise.all([p, fullScreenChange()]);
+ assert_equals(
+ document.fullscreenElement,
+ div,
+ "fullscreenElement after entering fullscreen"
+ );
+ // Ensure that there's are not more changes fullscreenchange event.
+ document.onfullscreenchange = t.unreached_func(
+ "second fullscreenchange event"
+ );
+ await Promise.all(rejectedPromises);
+ await new Promise((r) => requestAnimationFrame(r));
+ }, "requestFullscreen() multiple times after going fullscreen");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-two-elements.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-two-elements.html
new file mode 100644
index 0000000000..54419ea8fd
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen-two-elements.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>Element#requestFullscreen() on two elements in the same document</title>
+<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>
+<script src="../trusted-click.js"></script>
+<body>
+ <div id="a"></div>
+ <div id="b"></div>
+</body>
+<script>
+ promise_test(async (t) => {
+ document.onfullscreenerror = t.unreached_func("fullscreenerror event");
+
+ // Request fullscreen on both elements, but in reverse tree order.
+ const a = document.getElementById("a");
+ const b = document.getElementById("b");
+
+ // Expect two fullscreenchange events, with document.fullscreenElement
+ // changing in the same order as the requests.
+ await trusted_click(b);
+ await Promise.all([b.requestFullscreen(), fullScreenChange()]);
+ assert_equals(document.fullscreenElement, b);
+
+ await trusted_click(b);
+ await Promise.all([a.requestFullscreen(), fullScreenChange()]);
+ assert_equals(document.fullscreenElement, a);
+ }, "Element#requestFullscreen() on two elements in the same document");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/element-request-fullscreen.html b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen.html
new file mode 100644
index 0000000000..fd9f249551
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/element-request-fullscreen.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>Element#requestFullscreen()</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<script>
+ promise_test(async function (t) {
+ const div = document.querySelector("div");
+ await Promise.all([fullScreenChange(), trusted_request(div)]);
+ assert_equals(event.target, div, "event.target");
+ assert_true(event.bubbles, "event.bubbles");
+ assert_false(event.cancelable, "event.cancelable");
+ assert_true(event.composed, "event.composed");
+ await document.exitFullscreen();
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/fullscreen-display-contents.html b/testing/web-platform/tests/fullscreen/api/fullscreen-display-contents.html
new file mode 100644
index 0000000000..fc6f232747
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/fullscreen-display-contents.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+ <title>
+ Test that display:contents on fullscreen elements acts like
+ display:block
+ </title>
+ <meta charset="utf-8" />
+ <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>
+ <script src="../trusted-click.js"></script>
+ <link rel="author" href="mailto:masonf@chromium.org" />
+ <link
+ rel="help"
+ href="https://fullscreen.spec.whatwg.org/#new-stacking-layer"
+ />
+ <div id="target"></div>
+ <style>
+ #target {
+ display: contents;
+ background-color: green;
+ }
+ #target::backdrop {
+ display: contents;
+ }
+ </style>
+
+ <script>
+ promise_test(async (t) => {
+ const target = document.querySelector("#target");
+ await test_driver.bless("fullscreen");
+ await target.requestFullscreen();
+ await new Promise((resolve) => requestAnimationFrame(resolve));
+ assert_equals(document.fullscreenElement, target);
+ assert_equals(
+ getComputedStyle(target).display,
+ "block",
+ "fullscreen element should have display:block"
+ );
+ assert_equals(
+ getComputedStyle(target, "::backdrop").display,
+ "block",
+ "fullscreen element's ::backdrop should have display:block"
+ );
+ await document.exitFullscreen();
+ new Promise((resolve) => requestAnimationFrame(resolve));
+ assert_equals(document.fullscreenElement, null);
+ assert_equals(
+ getComputedStyle(target).display,
+ "contents",
+ "fullscreen element should have display:contents after exiting fullscreen"
+ );
+ });
+ </script>
+</html>
diff --git a/testing/web-platform/tests/fullscreen/api/historical.html b/testing/web-platform/tests/fullscreen/api/historical.html
new file mode 100644
index 0000000000..8b3e3c03e9
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/historical.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<title>Historical Fullscreen features</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+[
+ "onwebkitfullscreenchange",
+ "onwebkitfullscreenerror",
+ "webkitCurrentFullScreenElement",
+ "webkitFullscreenElement",
+ "webkitFullscreenEnabled",
+ "webkitIsFullScreen",
+ "webkitRequestFullScreen",
+ "webkitRequestFullscreen",
+ "webkitDisplayingFullscreen",
+ "webkitEnterFullScreen",
+ "webkitEnterFullscreen",
+ "webkitExitFullScreen",
+ "webkitExitFullscreen",
+ "webkitSupportsFullscreen",
+].forEach(function(member) {
+ ["webkit", "moz", "ms"].forEach(function(prefix) {
+ var alias = member.replace("webkit", prefix);
+ var clarifyTestName = (alias.indexOf('FullScreen') != -1 ? ' (uppercase S)' : '');
+
+ test(function() {
+ assert_false(alias in document.createElement('video'));
+ }, '<video> member must not be supported: ' + alias + clarifyTestName);
+
+ test(function() {
+ assert_false(alias in document);
+ }, 'Document member must not be supported: ' + alias + clarifyTestName);
+
+ // Some of the combinations tested here have never been supported, but
+ // it is convenient to just test all names on both <video> and document.
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/promises-reject.html b/testing/web-platform/tests/fullscreen/api/promises-reject.html
new file mode 100644
index 0000000000..4385b1646d
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/promises-reject.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<title>Promises#reject</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+ promise_test(async (t) => {
+ const e = document.createElement("span");
+ await promise_rejects_js(
+ t,
+ TypeError,
+ e.requestFullscreen(),
+ "Rejects if the element is not connected"
+ );
+ await promise_rejects_js(
+ t,
+ TypeError,
+ document.exitFullscreen(),
+ "Not in fullscreen"
+ );
+ }, "Rejects if the element is not connected");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/promises-resolve.html b/testing/web-platform/tests/fullscreen/api/promises-resolve.html
new file mode 100644
index 0000000000..5b8a090628
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/promises-resolve.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<title>Promises#resolve</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<script>
+ promise_test(async function (t) {
+ const div = document.querySelector("div");
+ await trusted_request(div, document.body);
+ assert_equals(
+ document.fullscreenElement,
+ div,
+ "fullscreenElement before exitFullscreen()"
+ );
+ const p = document.exitFullscreen();
+ assert_equals(
+ document.fullscreenElement,
+ div,
+ "fullscreenElement after exitFullscreen()"
+ );
+ await p;
+ assert_equals(
+ document.fullscreenElement,
+ null,
+ "fullscreenElement after exiting fullscreen"
+ );
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/resources/attempt-fullscreen.html b/testing/web-platform/tests/fullscreen/api/resources/attempt-fullscreen.html
new file mode 100644
index 0000000000..98cca04516
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/resources/attempt-fullscreen.html
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>IFrame Fullscreen API success reporter</title>
+<body></body>
+<script>
+ window.addEventListener("message", async (e) => {
+ switch (e.data.action) {
+ case "report":
+ await sendReport();
+ break;
+ default:
+ parent.postMessage(
+ {
+ report: {
+ api: "fullscreen",
+ result: `Unknown action ${e.data.action}`,
+ frame: window.name,
+ },
+ },
+ "*"
+ );
+ }
+ });
+
+ async function sendReport() {
+ let didSucceed = true;
+ let error;
+ let errorMessage;
+ try {
+ await document.body.requestFullscreen();
+ } catch (e) {
+ didSucceed = false;
+ error = e.name;
+ errorMessage = e.message;
+ } finally {
+ const data = {
+ report: {
+ api: "fullscreen",
+ result: didSucceed,
+ frame: window.name,
+ error,
+ errorMessage,
+ },
+ };
+ parent.postMessage(data, "*");
+ }
+ }
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/resources/echo-fullscreenEnabled.html b/testing/web-platform/tests/fullscreen/api/resources/echo-fullscreenEnabled.html
new file mode 100644
index 0000000000..ad5edf7986
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/resources/echo-fullscreenEnabled.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<script>
+window.onmessage = (e) => {
+ if (e.data === 'What is document.fullscreenEnabled?') {
+ e.source.postMessage(document.fullscreenEnabled, '*');
+ } else {
+ e.source.postMessage('Incorrect message', '*');
+ }
+}
+</script>
+<p>This page echos document.fullscreenEnabled.</p>
diff --git a/testing/web-platform/tests/fullscreen/api/resources/recursive-iframe-fullscreen.html b/testing/web-platform/tests/fullscreen/api/resources/recursive-iframe-fullscreen.html
new file mode 100644
index 0000000000..d242a3b3e6
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/resources/recursive-iframe-fullscreen.html
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<meta charset="utf-8" />
+<title>Recursive IFrame Fullscreen API success reporter</title>
+<body>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <script src="../../trusted-click.js"></script>
+ <script>
+ let child_frame = null;
+ const events = [];
+
+ document.onfullscreenchange = () => {
+ events.push("fullscreenchange");
+ };
+
+ document.onfullscreenerror = () => {
+ events.push("fullscreenerror");
+ };
+
+ function send_report() {
+ window.top.postMessage(
+ {
+ name: window.name,
+ action: "report",
+ report: {
+ api: "fullscreen",
+ frame: window.name,
+ fullscreenElementIsNull: document.fullscreenElement === null,
+ events,
+ },
+ },
+ "*"
+ );
+ }
+
+ async function create_child_frame({ src, name, allow_fullscreen }) {
+ child_frame = document.createElement("iframe");
+ child_frame.allow = allow_fullscreen ? "fullscreen" : "";
+ child_frame.name = name;
+ child_frame.style.width = "100%";
+ child_frame.style.height = "100%";
+ document.body.appendChild(child_frame);
+ await new Promise((resolve) => {
+ child_frame.addEventListener("load", resolve, { once: true });
+ child_frame.src = src;
+ });
+ window.top.postMessage({ action: "load", name }, "*");
+ }
+
+ async function go_fullscreen() {
+ await trusted_click(document.body);
+ let error;
+ try {
+ await document.body.requestFullscreen();
+ } catch (err) {
+ error = err.name;
+ } finally {
+ window.top.postMessage(
+ { action: "requestFullscreen", name: window.name, error },
+ "*"
+ );
+ }
+ }
+
+ window.addEventListener("message", async (e) => {
+ // Massage is not for us, try to pass it on...
+ if (e.data.name !== window.name) {
+ child_frame?.contentWindow.postMessage(e.data, "*");
+ return;
+ }
+ switch (e.data.action) {
+ case "requestReport":
+ send_report();
+ break;
+ case "requestFullscreen":
+ await go_fullscreen();
+ break;
+ case "addIframe":
+ await create_child_frame(e.data.iframe);
+ break;
+ default:
+ window.top.postMessage(e.data, "*");
+ }
+ });
+ </script>
+</body>
diff --git a/testing/web-platform/tests/fullscreen/api/resources/report-fullscreen-enabled.html b/testing/web-platform/tests/fullscreen/api/resources/report-fullscreen-enabled.html
new file mode 100644
index 0000000000..ee8d4cfab7
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/resources/report-fullscreen-enabled.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>IFrame fullscreenEnabled attribute reporter</title>
+<body>
+<script>
+parent.postMessage({"report": {
+ "api": "fullscreen",
+ "enabled": document.fullscreenEnabled,
+ "frame": window.name
+}}, "*");
+</script>
diff --git a/testing/web-platform/tests/fullscreen/api/shadowroot-fullscreen-element.html b/testing/web-platform/tests/fullscreen/api/shadowroot-fullscreen-element.html
new file mode 100644
index 0000000000..5e605f00aa
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/api/shadowroot-fullscreen-element.html
@@ -0,0 +1,47 @@
+<!doctype html>
+<html>
+<head>
+ <title>shadowRoot.fullscreenElement works correctly</title>
+ <link rel="author" title="Tim Nguyen" href="https://github.com/nt1m">
+ <link rel="help" href="https://fullscreen.spec.whatwg.org/#dom-document-fullscreenelement">
+</head>
+<div id="host">
+ <button onclick="document.exitFullscreen()" id="exitButton">Exit fullscreen</button>
+</div>
+<button id="requestButton">Go fullscreen</button>
+
+<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>
+<script>
+promise_test(async function() {
+ let host = document.getElementById("host");
+ host.attachShadow({ mode: "open" }).innerHTML = `
+ <style>
+ #outer { width: 200px; height: 200px; background: blue }
+ </style>
+ <div id="outer">
+ <slot></slot>
+ </div>
+ `;
+ let outer = host.shadowRoot.querySelector("#outer");
+ await new Promise((resolve) => {
+ addEventListener("fullscreenchange", resolve, { once: true });
+ requestButton.addEventListener("click", () => outer.requestFullscreen());
+ test_driver.click(requestButton);
+ });
+
+ assert_equals(outer.getRootNode().fullscreenElement, outer, "Correct shadowRoot.fullscreenElement after entering");
+ assert_equals(document.fullscreenElement, host, "Correct document.fullscreenElement after entering");
+
+ await new Promise((resolve) => {
+ addEventListener("fullscreenchange", resolve, { once: true });
+ test_driver.click(exitButton);
+ });
+
+ assert_equals(outer.getRootNode().fullscreenElement, null, "Correct shadowRoot.fullscreenElement after exiting");
+ assert_equals(document.fullscreenElement, null, "Correct document.fullscreenElement after exiting");
+}, "shadowRoot.fullscreenElement works correctly");
+</script>
+</html>
diff --git a/testing/web-platform/tests/fullscreen/crashtests/backdrop-list-item.html b/testing/web-platform/tests/fullscreen/crashtests/backdrop-list-item.html
new file mode 100644
index 0000000000..c5f58263ff
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/crashtests/backdrop-list-item.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<link rel="author" title="Oriol Brufau" href="mailto:obrufau@igalia.com" />
+<link rel="help" href="https://crbug.com/1371331">
+<style>
+dialog::backdrop {
+ display: list-item;
+}
+</style>
+<dialog></dialog>
+<script>
+document.querySelector("dialog").showModal();
+</script>
diff --git a/testing/web-platform/tests/fullscreen/crashtests/chrome-1312699.html b/testing/web-platform/tests/fullscreen/crashtests/chrome-1312699.html
new file mode 100644
index 0000000000..c783b0d9cc
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/crashtests/chrome-1312699.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<html class="reftest-wait">
+<link rel="help" href="https://crbug.com/1312699">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<video></video>
+<script>
+ async function crash() {
+ let video = document.querySelector("video");
+ await video.requestFullscreen();
+ video.width = null;
+ document.documentElement.classList.remove("reftest-wait");
+ }
+ document.addEventListener("click", () => crash(), false);
+
+ requestAnimationFrame(() => requestAnimationFrame(() => {
+ test_driver.click(document.body);
+ }));
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/fullscreen/crashtests/content-visibility-crash.html b/testing/web-platform/tests/fullscreen/crashtests/content-visibility-crash.html
new file mode 100644
index 0000000000..63111d03e3
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/crashtests/content-visibility-crash.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html class=test-wait>
+<link rel=author href="mailto:m.cooolie@gmail.com">
+<link rel=author href="mailto:jarhar@chromium.org">
+<link rel=help href="https://bugs.chromium.org/p/chromium/issues/detail?id=1338135">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<body>
+<script>
+async function crash() {
+ const col = document.createElement("col");
+ document.body.appendChild(col);
+
+ let fullscreenPromise = null;
+ await test_driver.bless('open fullscreen', () => {
+ fullscreenPromise = col.requestFullscreen({navigationUI: 'hide'});
+ });
+ await fullscreenPromise;
+
+ const a = document.createElement("a");
+ document.body.appendChild(a);
+
+ document.body.style.all = 'unset';
+ document.body.style.contentVisibility = 'hidden';
+
+ a.offsetParent;
+
+ document.documentElement.classList.remove('test-wait');
+}
+crash();
+</script>
diff --git a/testing/web-platform/tests/fullscreen/idlharness.window.js b/testing/web-platform/tests/fullscreen/idlharness.window.js
new file mode 100644
index 0000000000..ddcc59c403
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/idlharness.window.js
@@ -0,0 +1,16 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+// META: timeout=long
+
+'use strict';
+
+idl_test(
+ ['fullscreen'],
+ ['dom', 'html'],
+ idl_array => {
+ idl_array.add_objects({
+ Document: ['new Document'],
+ Element: ['document.createElementNS(null, "test")'],
+ });
+ }
+);
diff --git a/testing/web-platform/tests/fullscreen/model/move-to-fullscreen-iframe.html b/testing/web-platform/tests/fullscreen/model/move-to-fullscreen-iframe.html
new file mode 100644
index 0000000000..0103b2979f
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/model/move-to-fullscreen-iframe.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<title>Moving fullscreen document's body into a fullscreen iframe</title>
+<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>
+<script src="../trusted-click.js"></script>
+<iframe allowfullscreen></iframe>
+<script>
+ promise_test(async (t) => {
+ t.add_cleanup(() => {
+ if (document.fullscreenElement) {
+ return document.exitFullscreen();
+ }
+ });
+ const iframe = document.querySelector("iframe");
+ await new Promise((resolve) => {
+ iframe.onload = resolve;
+ iframe.src = "about:blank";
+ });
+ const iframeDoc = iframe.contentDocument;
+
+ // Enter fullscreen for the iframe's body element.
+ await Promise.all([
+ trusted_request(iframeDoc.body, iframeDoc.body),
+ fullScreenChange(),
+ ]);
+
+ assert_equals(
+ document.fullscreenElement,
+ iframe,
+ "document's initial fullscreen element"
+ );
+ assert_equals(
+ iframeDoc.fullscreenElement,
+ iframeDoc.body,
+ "iframe's initial fullscreen element"
+ );
+
+ // Then, move the outer document's body into the iframe. This is an unusual
+ // thing to do, but means that the iframe is removed from its document and
+ // should trigger fullscreen exit.
+ iframeDoc.documentElement.appendChild(document.body);
+
+ // If we exit in an orderly fashion, that's all one can ask for.
+ await fullScreenChange();
+ assert_equals(
+ document.fullscreenElement,
+ null,
+ "document's final fullscreen element"
+ );
+
+ // Because the iframe was removed, its browsing context was discarded and
+ // its contentDocument has become null. Because that browsing context was
+ // neither a descendant browsing context nor had an active document,
+ // nothing at all was done with it in the exit fullscreen algorithm, so
+ // its fullscreenElement is unchanged.
+ assert_equals(iframe.contentDocument, null, "iframe's content document");
+ assert_equals(
+ iframeDoc.fullscreenElement,
+ iframeDoc.body,
+ "iframe's final fullscreen element"
+ );
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/model/move-to-iframe.html b/testing/web-platform/tests/fullscreen/model/move-to-iframe.html
new file mode 100644
index 0000000000..d3a7a67298
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/model/move-to-iframe.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<title>Move the fullscreen element to another document</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div></div>
+<iframe></iframe>
+<script>
+ promise_test(async (t) => {
+ t.add_cleanup(() => {
+ if (document.fullscreenElement) {
+ return document.exitFullscreen();
+ }
+ });
+ const div = document.querySelector("div");
+ const iframe = document.querySelector("iframe");
+ const [, event] = await Promise.all([
+ trusted_request(div),
+ fullScreenChange(),
+ ]);
+
+ assert_equals(document.fullscreenElement, div);
+ assert_equals(event.target, div);
+
+ assert_equals(div.ownerDocument, document);
+ iframe.contentDocument.body.appendChild(div);
+ assert_not_equals(div.ownerDocument, document);
+ // Moving /div/ removes it from the top layer and thus the fullscreen
+ // element synchronously becomes null.
+ assert_equals(document.fullscreenElement, null);
+
+ div.onfullscreenchange = t.unreached_func(
+ "fullscreenchange fired on element"
+ );
+ iframe.contentDocument.onfullscreenchange = t.unreached_func(
+ "fullscreenchange fired on other document"
+ );
+ const secondEvent = await fullScreenChange();
+ assert_equals(document.fullscreenElement, null);
+ assert_equals(secondEvent.target, document);
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/model/move-to-inactive-document.html b/testing/web-platform/tests/fullscreen/model/move-to-inactive-document.html
new file mode 100644
index 0000000000..b9a95f2954
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/model/move-to-inactive-document.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<title>Move the fullscreen element to an inactive document</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div></div>
+<script>
+ promise_test(async (t) => {
+ t.add_cleanup(() => {
+ if (document.fullscreenElement) {
+ return document.exitFullscreen();
+ }
+ });
+ const div = document.querySelector("div");
+
+ // Go fullscreen...
+ await Promise.all([trusted_request(div), fullScreenChange()]);
+
+ const inactiveDocument = document.implementation.createDocument(null, "");
+
+ div.onfullscreenchange = t.unreached_func(
+ "fullscreenchange fired on element"
+ );
+ inactiveDocument.onfullscreenchange = t.unreached_func(
+ "fullscreenchange fired on other document"
+ );
+
+ // Transplant element to inactive document...
+ inactiveDocument.appendChild(div);
+
+ // Fullscreen exits...
+ await fullScreenChange();
+ // Make sure no other events fire...
+ await new Promise((resolve) => {
+ requestAnimationFrame(resolve);
+ });
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/model/remove-child.html b/testing/web-platform/tests/fullscreen/model/remove-child.html
new file mode 100644
index 0000000000..42355dc2da
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/model/remove-child.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<title>Remove the child of the fullscreen element</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<div id="parent">
+ <div></div>
+</div>
+<script>
+ promise_test(async (t) => {
+ t.add_cleanup(() => {
+ if (document.fullscreenElement) {
+ return document.exitFullscreen();
+ }
+ });
+ const parent = document.getElementById("parent");
+ await Promise.all([trusted_request(parent), fullScreenChange()]);
+
+ assert_equals(document.fullscreenElement, parent);
+ parent.textContent = ""; // removes all children
+ // The fullscreen element should not be affected.
+ assert_equals(document.fullscreenElement, parent);
+ document.onfullscreenchange = t.unreached_func("fullscreenchange event");
+ // A fullscreenchange event would be fired after an async section
+ // and an animation frame task, so wait until after that.
+ await new Promise((resolve) => {
+ requestAnimationFrame(resolve);
+ });
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/model/remove-first.html b/testing/web-platform/tests/fullscreen/model/remove-first.html
new file mode 100644
index 0000000000..b4058db320
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/model/remove-first.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<title>Remove the first element on the fullscreen element stack</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<div id="first">
+ <div id="last"></div>
+</div>
+<script>
+ promise_test(async (t) => {
+ t.add_cleanup(() => {
+ if (document.fullscreenElement) {
+ return document.exitFullscreen();
+ }
+ });
+ const first = document.getElementById("first");
+
+ const [, firstEvent] = await Promise.all([
+ trusted_request(first),
+ fullScreenChange(),
+ ]);
+ assert_equals(document.fullscreenElement, first);
+ assert_equals(firstEvent.target, first);
+
+ const last = document.getElementById("last");
+ const [, secondEvent] = await Promise.all([
+ trusted_request(last),
+ fullScreenChange(),
+ ]);
+ assert_equals(document.fullscreenElement, last);
+ assert_equals(event.target, last);
+ first.remove();
+
+ // Both /first/ and /last/ were removed from the top layer and
+ // thus the fullscreen element synchronously becomes null.
+ assert_equals(document.fullscreenElement, null);
+
+ const thirdEvent = await fullScreenChange();
+ assert_equals(document.fullscreenElement, null);
+ assert_equals(event.target, document);
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/model/remove-last.html b/testing/web-platform/tests/fullscreen/model/remove-last.html
new file mode 100644
index 0000000000..760ccaa0ba
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/model/remove-last.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<title>Remove the last element on the fullscreen element stack</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<div id="first">
+ <div id="last"></div>
+</div>
+<script>
+ promise_test(async (t) => {
+ t.add_cleanup(() => {
+ if (document.fullscreenElement) {
+ return document.exitFullscreen();
+ }
+ });
+ const first = document.getElementById("first");
+ const [, firstEvent] = await Promise.all([
+ trusted_request(first),
+ fullScreenChange(),
+ ]);
+
+ assert_equals(document.fullscreenElement, first);
+ assert_equals(firstEvent.target, first);
+
+ const last = document.getElementById("last");
+ const [, lastEvent] = await Promise.all([
+ trusted_request(last),
+ fullScreenChange(),
+ ]);
+
+ assert_equals(document.fullscreenElement, last);
+ assert_equals(event.target, last);
+ last.remove();
+ // Because /last/ was removed from the top layer, we exit
+ // fullscreen element synchronously.
+ assert_equals(document.fullscreenElement, first);
+
+ const finalEvent = await fullScreenChange();
+ // fullscreen change element should be queued against the
+ // document target.
+ assert_equals(document.fullscreenElement, null);
+ assert_equals(event.target, document);
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/model/remove-parent.html b/testing/web-platform/tests/fullscreen/model/remove-parent.html
new file mode 100644
index 0000000000..54ff5b8371
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/model/remove-parent.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>Remove the parent of the fullscreen element</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<div>
+ <div id="child"></div>
+</div>
+<script>
+ promise_test(async (t) => {
+ t.add_cleanup(() => {
+ if (document.fullscreenElement) {
+ return document.exitFullscreen();
+ }
+ });
+ const child = document.getElementById("child");
+ const [, event] = await Promise.all([
+ trusted_request(child),
+ fullScreenChange(),
+ ]);
+ assert_equals(document.fullscreenElement, child);
+ assert_equals(event.target, child);
+ child.parentNode.remove();
+ // Because /child/ was removed from the top layer, the fullscreen
+ // element becomes null synchronously.
+ assert_equals(document.fullscreenElement, null);
+ const secondEvent = await fullScreenChange();
+ assert_equals(document.fullscreenElement, null);
+ assert_equals(secondEvent.target, document);
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/model/remove-single.html b/testing/web-platform/tests/fullscreen/model/remove-single.html
new file mode 100644
index 0000000000..0401f77953
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/model/remove-single.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<title>Remove the single element on the fullscreen element stack</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div id="log"></div>
+<div id="single"></div>
+<script>
+ promise_test(async (t) => {
+ t.add_cleanup(() => {
+ if (document.fullscreenElement) {
+ return document.exitFullscreen();
+ }
+ });
+ const single = document.getElementById("single");
+ const [, event] = await Promise.all([
+ trusted_request(single),
+ fullScreenChange(),
+ ]);
+
+ assert_equals(document.fullscreenElement, single);
+ assert_equals(event.target, single);
+ single.remove();
+ // Because /single/ was removed from the top layer, the fullscreen
+ // element becomes null synchronously.
+ assert_equals(document.fullscreenElement, null);
+
+ const secondEvent = await fullScreenChange();
+ assert_equals(document.fullscreenElement, null);
+ assert_equals(event.target, single);
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/rendering/backdrop-iframe-ref.html b/testing/web-platform/tests/fullscreen/rendering/backdrop-iframe-ref.html
new file mode 100644
index 0000000000..3126fe1942
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/rendering/backdrop-iframe-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<body style="background: green"></body>
diff --git a/testing/web-platform/tests/fullscreen/rendering/backdrop-iframe.html b/testing/web-platform/tests/fullscreen/rendering/backdrop-iframe.html
new file mode 100644
index 0000000000..710d1b48f1
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/rendering/backdrop-iframe.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>::backdrop for a fullscreen iframe element</title>
+<link rel=match href="backdrop-iframe-ref.html">
+<link rel=help href="https://github.com/w3c/csswg-drafts/issues/6939">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<style>
+iframe::backdrop {
+ background: green;
+}
+</style>
+<iframe></iframe>
+<script>
+document.addEventListener('fullscreenchange', () => {
+ document.documentElement.classList.remove('reftest-wait');
+});
+test_driver.bless('fullscreen', () => {
+ document.querySelector('iframe').requestFullscreen();
+});
+</script>
diff --git a/testing/web-platform/tests/fullscreen/rendering/backdrop-object-ref.html b/testing/web-platform/tests/fullscreen/rendering/backdrop-object-ref.html
new file mode 100644
index 0000000000..6c7071a727
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/rendering/backdrop-object-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<style>
+body {
+ background: blue;
+ margin: 0;
+}
+div {
+ position: fixed;
+ width: 100px;
+ height: 100px;
+ background: green;
+}
+</style>
+<div></div>
diff --git a/testing/web-platform/tests/fullscreen/rendering/backdrop-object.html b/testing/web-platform/tests/fullscreen/rendering/backdrop-object.html
new file mode 100644
index 0000000000..be285b7612
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/rendering/backdrop-object.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html class=reftest-wait>
+<title>::backdrop for a fullscreen object element</title>
+<link rel=match href="backdrop-object-ref.html">
+<link rel=help href="https://github.com/w3c/csswg-drafts/issues/6939">
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<style>
+object::backdrop {
+ background: blue;
+}
+</style>
+<object width="200" type="image/svg+xml" data="../../images/100px-green-rect.svg"></object>
+<script>
+const object = document.querySelector("object");
+Promise.all([
+ new Promise((resolve, reject) => document.addEventListener("fullscreenchange", resolve)),
+ new Promise((resolve, reject) => object.addEventListener("load", resolve))
+]).then(() => document.documentElement.classList.remove('reftest-wait'));
+
+test_driver.bless('fullscreen', () => object.requestFullscreen());
+</script>
diff --git a/testing/web-platform/tests/fullscreen/rendering/fullscreen-css-invalidation.html b/testing/web-platform/tests/fullscreen/rendering/fullscreen-css-invalidation.html
new file mode 100644
index 0000000000..e855d0c193
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/rendering/fullscreen-css-invalidation.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<title>Invalidate :fullscreen based style</title>
+<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>
+<style>
+ #pass {
+ color: red;
+ }
+ :root:fullscreen #pass {
+ color: green;
+ }
+</style>
+<div id="pass">Should be green</div>
+<script>
+ async_test(t => {
+ document.onfullscreenchange = t.step_func_done(() => {
+ assert_equals(document.fullscreenElement, document.documentElement);
+ assert_equals(getComputedStyle(pass).color, "rgb(0, 128, 0)", "Green when :root is fullscreened.");
+ });
+ document.documentElement.addEventListener('click', t.step_func(() => {
+ document.documentElement.requestFullscreen();
+ }), {once: true});
+ assert_equals(getComputedStyle(pass).color, "rgb(255, 0, 0)", "Initially red.");
+ test_driver.click(document.documentElement);
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/rendering/fullscreen-css-transition.html b/testing/web-platform/tests/fullscreen/rendering/fullscreen-css-transition.html
new file mode 100644
index 0000000000..b494dc04e6
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/rendering/fullscreen-css-transition.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<title>Transitions should not be stopped by going fullscreen</title>
+<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>
+<style>
+ #trans {
+ transition: color steps(1, end) 100s;
+ color: green;
+ }
+</style>
+<div id="trans">Should be green</div>
+<script>
+ async_test(t => {
+ document.onfullscreenchange = t.step_func_done(() => {
+ assert_equals(document.fullscreenElement, trans);
+ assert_equals(getComputedStyle(trans).color, "rgb(0, 128, 0)", "Transition is in progress - still green");
+ });
+ trans.addEventListener('click', t.step_func(() => {
+ trans.style.color = "red";
+ trans.offsetTop;
+ trans.requestFullscreen();
+ }), {once: true});
+ test_driver.click(trans);
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/rendering/fullscreen-pseudo-class-support.html b/testing/web-platform/tests/fullscreen/rendering/fullscreen-pseudo-class-support.html
new file mode 100644
index 0000000000..fb2ff318b9
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/rendering/fullscreen-pseudo-class-support.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<title>:fullscreen pseudo-class support</title>
+<link rel="help" href="https://fullscreen.spec.whatwg.org/#:fullscreen-pseudo-class">
+<link rel="help" href="https://dom.spec.whatwg.org/#dom-element-matches">
+<link rel="help" href="https://dom.spec.whatwg.org/#dom-parentnode-queryselector">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+// This is a separate test so that support for :fullscreen can be detected
+// without actually going fullscreen. If it were not supported, then this test
+// would fail.
+test(t => {
+ // precondition is to throw for unknown pseudo-classes:
+ assert_throws_dom("SyntaxError", () => document.body.matches(':halfscreen'));
+ assert_throws_dom("SyntaxError", () => document.querySelector(':halfscreen'));
+ // the actual test:
+ assert_false(document.body.matches(':fullscreen'));
+ assert_equals(document.querySelector(':fullscreen'), null);
+});
+</script>
diff --git a/testing/web-platform/tests/fullscreen/rendering/fullscreen-pseudo-class.html b/testing/web-platform/tests/fullscreen/rendering/fullscreen-pseudo-class.html
new file mode 100644
index 0000000000..5b02c32ef3
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/rendering/fullscreen-pseudo-class.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<title>:fullscreen pseudo-class</title>
+<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>
+<script src="../trusted-click.js"></script>
+<div><div></div></div>
+<script>
+ promise_test(async (t) => {
+ t.add_cleanup(() => {
+ if (document.fullscreenElement) {
+ return document.exitFullscreen();
+ }
+ });
+ const outer = document.querySelector("div");
+ const inner = outer.firstChild;
+
+ // First request fullscreen for the outer element.
+ await trusted_request(outer);
+ await fullScreenChange();
+ assert_equals(document.fullscreenElement, outer);
+ assert_true(
+ outer.matches(":fullscreen"),
+ "outer:fullscreen in simple fullscreen"
+ );
+ assert_false(
+ inner.matches(":fullscreen"),
+ "inner:fullscreen in simple fullscreen"
+ );
+
+ // Then request fullscreen for the inner element.
+ await trusted_request(inner);
+ // Although inner is the fullscreen element, both elements match the
+ // selector, as both have their fullscreen flag set.
+ assert_equals(document.fullscreenElement, inner);
+ assert_true(
+ inner.matches(":fullscreen"),
+ "inner:fullscreen in nested fullscreen"
+ );
+ assert_true(
+ outer.matches(":fullscreen"),
+ "outer:fullscreen in nested fullscreen"
+ );
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/rendering/fullscreen-root-block-scroll.html b/testing/web-platform/tests/fullscreen/rendering/fullscreen-root-block-scroll.html
new file mode 100644
index 0000000000..87147b42e0
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/rendering/fullscreen-root-block-scroll.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<style>
+ body {
+ height: 10000px;
+ background: grey;
+ }
+</style>
+<title>fullscreen root block scrolling</title>
+<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>
+<script src="../trusted-click.js"></script>
+<body>
+<div>
+ This page tests that entering fullscreen doesn't adjust the scroll offset
+</div>
+<script>
+ promise_test(async (t) => {
+ t.add_cleanup(() => {
+ if (document.fullscreenElement) {
+ return document.exitFullscreen();
+ }
+ });
+ await trusted_click();
+ document.scrollingElement.scrollTop = 300;
+ await document.documentElement.requestFullscreen();
+ await fullScreenChange();
+
+ assert_equals(document.fullscreenElement, document.documentElement);
+ assert_not_equals(document.scrollingElement.scrollTop, 0);
+ document.scrollingElement.scrollTop = 0;
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/rendering/fullscreen-root-block-size.html b/testing/web-platform/tests/fullscreen/rendering/fullscreen-root-block-size.html
new file mode 100644
index 0000000000..5138494d5d
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/rendering/fullscreen-root-block-size.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<style>
+ html,
+ body {
+ margin: 0px;
+ }
+</style>
+<title>fullscreen root block sizing</title>
+<!-- This page intentionally has no content. It needs to have
+no width or height. This is to ensure that the root element
+gets sizing in fullscreen mode as it does in as it does not
+in fullscreen mode.
+-->
+<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>
+<script src="../trusted-click.js"></script>
+<body></body>
+<script>
+ promise_test(async (t) => {
+ t.add_cleanup(() => {
+ if (document.fullscreenElement) {
+ return document.exitFullscreen();
+ }
+ });
+ await trusted_click();
+ await document.documentElement.requestFullscreen();
+ await fullScreenChange();
+ assert_equals(document.fullscreenElement, document.documentElement);
+ assert_true(document.documentElement.getBoundingClientRect().width > 0);
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/rendering/fullscreen-root-fills-page-ref.html b/testing/web-platform/tests/fullscreen/rendering/fullscreen-root-fills-page-ref.html
new file mode 100644
index 0000000000..b2bf13557a
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/rendering/fullscreen-root-fills-page-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <style>
+ html, body {
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ padding: 0;
+ }
+
+ body {
+ background-color: green;
+ }
+ </style>
+</head>
+<body></body>
+</html>
diff --git a/testing/web-platform/tests/fullscreen/rendering/fullscreen-root-fills-page.html b/testing/web-platform/tests/fullscreen/rendering/fullscreen-root-fills-page.html
new file mode 100644
index 0000000000..f122e678f3
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/rendering/fullscreen-root-fills-page.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<head>
+ <link rel="author" href="https://github.com/nt1m">
+ <link rel="match" href="fullscreen-root-fills-page-ref.html">
+ <style>
+ html {
+ background-color: red;
+ height: 100%;
+ overflow: hidden;
+
+ /* These should be no-op */
+ top: 200px;
+ left: 200px;
+ right: 200px;
+ bottom: 200px;
+ }
+
+ html, body {
+ margin: 0;
+ padding: 0;
+ }
+
+ body, #cover {
+ height: 100%;
+ width: 100%;
+ }
+
+ #cover {
+ background-color: green;
+ }
+ </style>
+</head>
+
+<body>
+ <div id="cover"></div>
+ <script src="/resources/testdriver.js"></script>
+ <script src="/resources/testdriver-vendor.js"></script>
+ <script>
+ document.addEventListener("fullscreenchange", () => {
+ document.documentElement.classList.remove("reftest-wait");
+ });
+ test_driver.bless("fullscreen")
+ .then(() => document.documentElement.requestFullscreen())
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/fullscreen/rendering/ua-style-iframe.html b/testing/web-platform/tests/fullscreen/rendering/ua-style-iframe.html
new file mode 100644
index 0000000000..dcf1656e00
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/rendering/ua-style-iframe.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<title>User-agent levels style sheet defaults for iframe</title>
+<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>
+<script src="../trusted-click.js"></script>
+<style>
+ iframe {
+ border: 1px solid blue;
+ padding: 1px;
+ /* transform is also tested because of https://crbug.com/662393 */
+ transform: scale(0.5);
+ }
+</style>
+<div id="log"></div>
+<div id="ancestor"><iframe></iframe></div>
+<script>
+ function assert_dir_properties(style, propBase, value, state) {
+ for (let dir of ["Top", "Right", "Bottom", "Left"]) {
+ let prop = propBase.replace("{}", dir);
+ assert_equals(style[prop], value, `${state} ${prop} style`);
+ }
+ }
+
+ promise_test(async (t) => {
+ t.add_cleanup(() => {
+ if (document.fullscreenElement) {
+ return document.exitFullscreen();
+ }
+ });
+ const ancestor = document.getElementById("ancestor");
+ const iframe = ancestor.firstChild;
+
+ const initialStyle = getComputedStyle(iframe);
+ assert_dir_properties(initialStyle, "border{}Width", "1px", "initial");
+ assert_dir_properties(initialStyle, "border{}Style", "solid", "initial");
+ assert_dir_properties(
+ initialStyle,
+ "border{}Color",
+ "rgb(0, 0, 255)",
+ "initial"
+ );
+ assert_dir_properties(initialStyle, "padding{}", "1px", "initial");
+ assert_equals(
+ initialStyle.transform,
+ "matrix(0.5, 0, 0, 0.5, 0, 0)",
+ "initial transform style"
+ );
+
+ await trusted_request(iframe);
+ await fullScreenChange();
+
+ const fullscreenStyle = getComputedStyle(iframe);
+ assert_dir_properties(
+ fullscreenStyle,
+ "border{}Width",
+ "0px",
+ "fullscreen"
+ );
+ assert_dir_properties(
+ fullscreenStyle,
+ "border{}Style",
+ "none",
+ "fullscreen"
+ );
+ assert_dir_properties(
+ fullscreenStyle,
+ "border{}Color",
+ "rgb(0, 0, 0)",
+ "fullscreen"
+ );
+ assert_dir_properties(fullscreenStyle, "padding{}", "0px", "fullscreen");
+ assert_equals(
+ fullscreenStyle.transform,
+ "none",
+ "fullscreen transform style"
+ );
+ });
+</script>
diff --git a/testing/web-platform/tests/fullscreen/trusted-click.js b/testing/web-platform/tests/fullscreen/trusted-click.js
new file mode 100644
index 0000000000..51fbce7ee4
--- /dev/null
+++ b/testing/web-platform/tests/fullscreen/trusted-click.js
@@ -0,0 +1,65 @@
+/**
+ * Invokes callback from a trusted click event, avoiding interception by fullscreen element.
+ *
+ * @param {Element} container - Element where button will be created and clicked.
+ */
+function trusted_click(container = document.body) {
+ var document = container.ownerDocument;
+ var button = document.createElement("button");
+ button.textContent = "click to continue test";
+ button.style.display = "block";
+ button.style.fontSize = "20px";
+ button.style.padding = "10px";
+ button.addEventListener("click", () => {
+ button.remove();
+ });
+ container.appendChild(button);
+ if (window.top !== window) test_driver.set_test_context(window.top);
+ // Race them for manually testing...
+ return Promise.race([
+ test_driver.click(button),
+ new Promise((resolve) => {
+ button.addEventListener("click", resolve);
+ }),
+ ]);
+}
+
+// Invokes element.requestFullscreen() from a trusted click.
+async function trusted_request(element = document.body, whereToCreateButton = null) {
+ await trusted_click(whereToCreateButton ?? element.parentNode ?? element);
+ return element.requestFullscreen();
+}
+
+/**
+ * Used to await a fullscreen change event, once.
+ *
+ * @param {EventTarget} target
+ * @returns
+ */
+function fullScreenChange(target = document) {
+ return new Promise((resolve) =>
+ target.addEventListener("fullscreenchange", resolve, { once: true })
+ );
+}
+
+/**
+ * Sets up a message event listener, and returns a promise that resolves
+ * when the message from the iframe is received.
+ *
+ * @param {HTMLIFrameElement} iframe
+ * @returns {Promise<object>}
+ */
+function promiseMessage(iframe) {
+ return new Promise((resolve) => {
+ window.addEventListener(
+ "message",
+ (e) => {
+ if (e.data?.report.api === "fullscreen") {
+ resolve(e.data);
+ }
+ },
+ { once: true }
+ );
+ iframe.contentWindow.postMessage({ action: "report" }, "*");
+ });
+}