summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/semantics/invokers
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:14:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:14:29 +0000
commitfbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8 (patch)
tree4c1ccaf5486d4f2009f9a338a98a83e886e29c97 /testing/web-platform/tests/html/semantics/invokers
parentReleasing progress-linux version 124.0.1-1~progress7.99u1. (diff)
downloadfirefox-fbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8.tar.xz
firefox-fbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8.zip
Merging upstream version 125.0.1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/html/semantics/invokers')
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/interestelement-interface.tentative.html164
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invokeelement-interface.tentative.html16
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invokeevent-interface.tentative.html6
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-button-event-dispatch.tentative.html8
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-dialog-behavior.tentative.html455
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-popover-behavior.tentative.html64
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/resources/invoker-utils.js8
7 files changed, 685 insertions, 36 deletions
diff --git a/testing/web-platform/tests/html/semantics/invokers/interestelement-interface.tentative.html b/testing/web-platform/tests/html/semantics/invokers/interestelement-interface.tentative.html
new file mode 100644
index 0000000000..dc119de833
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/interestelement-interface.tentative.html
@@ -0,0 +1,164 @@
+<!doctype html>
+<meta charset="utf-8" />
+<meta name="author" title="Luke Warlow" href="mailto:lwarlow@igalia.com" />
+<link rel="help" href="https://open-ui.org/components/interest-invokers.explainer/" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<button id="buttonInvoker" interesttarget="interestee"></button>
+<a id="aInvoker" interesttarget="interestee"></a>
+<input type="button" id="inputInvoker" interesttarget="interestee" />
+<div id="interestee"></div>
+
+<script>
+ test(function () {
+ assert_equals(buttonInvoker.interestTargetElement, interestee);
+ assert_equals(aInvoker.interestTargetElement, interestee);
+ assert_equals(inputInvoker.interestTargetElement, interestee);
+ }, "interestTargetElement reflects interestee HTML element");
+
+ test(function () {
+ const div = document.body.appendChild(document.createElement("div"));
+ buttonInvoker.interestTargetElement = div;
+ aInvoker.interestTargetElement = div;
+ inputInvoker.interestTargetElement = div;
+ assert_equals(buttonInvoker.interestTargetElement, div);
+ assert_equals(buttonInvoker.getAttribute("interesttarget"), "");
+ assert_equals(aInvoker.interestTargetElement, div);
+ assert_equals(aInvoker.getAttribute("interesttarget"), "");
+ assert_equals(inputInvoker.interestTargetElement, div);
+ assert_equals(inputInvoker.getAttribute("interesttarget"), "");
+ }, "interestTargetElement reflects set value");
+
+ test(function () {
+ const host = document.body.appendChild(document.createElement("div"));
+ const shadow = host.attachShadow({ mode: "open" });
+ const button = shadow.appendChild(document.createElement("button"));
+ button.interestTargetElement = interestee;
+ assert_equals(button.interestTargetElement, interestee);
+ assert_equals(buttonInvoker.getAttribute("interesttarget"), "");
+ }, "interestTargetElement reflects set value across shadow root into light dom");
+
+ test(function () {
+ const host = document.body.appendChild(document.createElement("div"));
+ const shadow = host.attachShadow({ mode: "open" });
+ const div = shadow.appendChild(document.createElement("div"));
+ buttonInvoker.interestTargetElement = div;
+ assert_equals(buttonInvoker.interestTargetElement, null);
+ assert_equals(buttonInvoker.getAttribute("interesttarget"), "");
+ }, "interestTargetElement does not reflect set value inside shadowroot");
+
+ test(function () {
+ buttonInvoker.setAttribute('interesttarget', 'invalid');
+ assert_equals(buttonInvoker.interestTargetElement, null);
+ assert_equals(buttonInvoker.getAttribute("interesttarget"), "invalid");
+ aInvoker.setAttribute('interesttarget', 'invalid');
+ assert_equals(aInvoker.interestTargetElement, null);
+ assert_equals(aInvoker.getAttribute("interesttarget"), "invalid");
+ inputInvoker.setAttribute('interesttarget', 'invalid');
+ assert_equals(inputInvoker.interestTargetElement, null);
+ assert_equals(inputInvoker.getAttribute("interesttarget"), "invalid");
+ }, "interestTargetElement does not reflect invalid value");
+
+ test(function () {
+ assert_throws_js(
+ TypeError,
+ function () {
+ buttonInvoker.interestTargetElement = {};
+ },
+ "interestTargetElement attribute value must be an instance of Element",
+ );
+ assert_throws_js(
+ TypeError,
+ function () {
+ aInvoker.interestTargetElement = {};
+ },
+ "interestTargetElement attribute value must be an instance of Element",
+ );
+ assert_throws_js(
+ TypeError,
+ function () {
+ inputInvoker.interestTargetElement = {};
+ },
+ "interestTargetElement attribute value must be an instance of Element",
+ );
+ }, "interestTargetElement throws error on assignment of non Element");
+
+ test(function () {
+ assert_false(buttonInvoker.hasAttribute("interestaction"));
+ assert_equals(buttonInvoker.interestAction, "");
+ assert_false(aInvoker.hasAttribute("interestaction"));
+ assert_equals(aInvoker.interestAction, "");
+ assert_false(inputInvoker.hasAttribute("interestaction"));
+ assert_equals(inputInvoker.interestAction, "");
+ }, "interestAction reflects '' when attribute not present");
+
+ test(function () {
+ buttonInvoker.setAttribute("interestaction", "");
+ assert_equals(buttonInvoker.getAttribute("interestaction"), "");
+ assert_equals(buttonInvoker.interestAction, "");
+ aInvoker.setAttribute("interestaction", "");
+ assert_equals(aInvoker.getAttribute("interestaction"), "");
+ assert_equals(aInvoker.interestAction, "");
+ inputInvoker.setAttribute("interestaction", "");
+ assert_equals(inputInvoker.getAttribute("interestaction"), "");
+ assert_equals(inputInvoker.interestAction, "");
+ }, "interestAction reflects '' when attribute empty, setAttribute version");
+
+ test(function () {
+ buttonInvoker.interestAction = "";
+ assert_equals(buttonInvoker.getAttribute("interestaction"), "");
+ assert_equals(buttonInvoker.interestAction, "");
+ aInvoker.interestAction = "";
+ assert_equals(aInvoker.getAttribute("interestaction"), "");
+ assert_equals(aInvoker.interestAction, "");
+ inputInvoker.interestAction = "";
+ assert_equals(inputInvoker.getAttribute("interestaction"), "");
+ assert_equals(inputInvoker.interestAction, "");
+ }, "interestAction reflects '' when attribute empty, IDL setter version");
+
+ test(function () {
+ buttonInvoker.interestAction = "fooBarBaz";
+ assert_equals(buttonInvoker.getAttribute("interestaction"), "fooBarBaz");
+ assert_equals(buttonInvoker.interestAction, "fooBarBaz");
+ aInvoker.interestAction = "fooBarBaz";
+ assert_equals(aInvoker.getAttribute("interestaction"), "fooBarBaz");
+ assert_equals(aInvoker.interestAction, "fooBarBaz");
+ inputInvoker.interestAction = "fooBarBaz";
+ assert_equals(inputInvoker.getAttribute("interestaction"), "fooBarBaz");
+ assert_equals(inputInvoker.interestAction, "fooBarBaz");
+ }, "interestAction reflects same casing");
+
+ test(function () {
+ buttonInvoker.interestAction = [];
+ assert_equals(buttonInvoker.getAttribute("interestaction"), "");
+ assert_equals(buttonInvoker.interestAction, "");
+ aInvoker.interestAction = [];
+ assert_equals(aInvoker.getAttribute("interestaction"), "");
+ assert_equals(aInvoker.interestAction, "");
+ inputInvoker.interestAction = [];
+ assert_equals(inputInvoker.getAttribute("interestaction"), "");
+ assert_equals(inputInvoker.interestAction, "");
+ }, "interestAction reflects '' when attribute set to []");
+
+ test(function () {
+ buttonInvoker.interestAction = [1, 2, 3];
+ assert_equals(buttonInvoker.getAttribute("interestaction"), "1,2,3");
+ assert_equals(buttonInvoker.interestAction, "1,2,3");
+ aInvoker.interestAction = [1, 2, 3];
+ assert_equals(aInvoker.getAttribute("interestaction"), "1,2,3");
+ assert_equals(aInvoker.interestAction, "1,2,3");
+ inputInvoker.interestAction = [1, 2, 3];
+ assert_equals(inputInvoker.getAttribute("interestaction"), "1,2,3");
+ assert_equals(inputInvoker.interestAction, "1,2,3");
+ }, "interestAction reflects tostring value");
+
+ test(function () {
+ buttonInvoker.interestAction = {};
+ assert_equals(buttonInvoker.interestAction, "[object Object]");
+ aInvoker.interestAction = {};
+ assert_equals(aInvoker.interestAction, "[object Object]");
+ inputInvoker.interestAction = {};
+ assert_equals(inputInvoker.interestAction, "[object Object]");
+ }, "interestAction reflects tostring value 2");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invokeelement-interface.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invokeelement-interface.tentative.html
index b003daf20d..5a2854fe31 100644
--- a/testing/web-platform/tests/html/semantics/invokers/invokeelement-interface.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/invokeelement-interface.tentative.html
@@ -53,14 +53,14 @@
test(function () {
assert_false(invoker.hasAttribute("invokeaction"));
- assert_equals(invoker.invokeAction, "auto");
- }, "invokeAction reflects 'auto' when attribute not present");
+ assert_equals(invoker.invokeAction, "");
+ }, "invokeAction reflects '' when attribute not present");
test(function () {
invoker.setAttribute("invokeaction", "");
assert_equals(invoker.getAttribute("invokeaction"), "");
- assert_equals(invoker.invokeAction, "auto");
- }, "invokeAction reflects 'auto' when attribute empty");
+ assert_equals(invoker.invokeAction, "");
+ }, "invokeAction reflects '' when attribute empty, setAttribute version");
test(function () {
invoker.invokeAction = "fooBarBaz";
@@ -71,8 +71,8 @@
test(function () {
invoker.invokeAction = "";
assert_equals(invoker.getAttribute("invokeaction"), "");
- assert_equals(invoker.invokeAction, "auto");
- }, "invokeAction reflects 'auto' when attribute empty 2");
+ assert_equals(invoker.invokeAction, "");
+ }, "invokeAction reflects '' when attribute empty, IDL version");
test(function () {
invoker.invokeAction = [1, 2, 3];
@@ -83,8 +83,8 @@
test(function () {
invoker.invokeAction = [];
assert_equals(invoker.getAttribute("invokeaction"), "");
- assert_equals(invoker.invokeAction, "auto");
- }, "invokeAction reflects 'auto' when attribute set to []");
+ assert_equals(invoker.invokeAction, "");
+ }, "invokeAction reflects '' when attribute set to []");
test(function () {
invoker.invokeAction = {};
diff --git a/testing/web-platform/tests/html/semantics/invokers/invokeevent-interface.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invokeevent-interface.tentative.html
index 82910b3d44..382f808071 100644
--- a/testing/web-platform/tests/html/semantics/invokers/invokeevent-interface.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/invokeevent-interface.tentative.html
@@ -15,9 +15,9 @@
<script>
test(function () {
const event = new InvokeEvent("test");
- assert_equals(event.action, "auto");
+ assert_equals(event.action, "");
assert_readonly(event, "action", "readonly attribute value");
- }, "action is a readonly defaulting to 'auto'");
+ }, "action is a readonly defaulting to ''");
test(function () {
const event = new InvokeEvent("test");
@@ -32,7 +32,7 @@
test(function () {
const event = new InvokeEvent("test", { action: undefined });
- assert_equals(event.action, "auto");
+ assert_equals(event.action, "");
}, "action set to undefined");
test(function () {
diff --git a/testing/web-platform/tests/html/semantics/invokers/invoketarget-button-event-dispatch.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-button-event-dispatch.tentative.html
index b19c1d3adc..d8d9c04022 100644
--- a/testing/web-platform/tests/html/semantics/invokers/invoketarget-button-event-dispatch.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-button-event-dispatch.tentative.html
@@ -22,7 +22,7 @@
assert_equals(event.bubbles, false, "bubbles");
assert_equals(event.composed, true, "composed");
assert_equals(event.isTrusted, true, "isTrusted");
- assert_equals(event.action, "auto", "action");
+ assert_equals(event.action, "", "action");
assert_equals(event.target, invokee, "target");
assert_equals(event.invoker, invokerbutton, "invoker");
}, "event dispatches on click");
@@ -107,6 +107,7 @@
"invoke",
(event) => {
eventInvoker = event.invoker;
+ eventTarget = event.target;
called = true;
},
{ once: true },
@@ -114,6 +115,7 @@
invokerbutton.invokeTargetElement = svgInvokee;
await clickOn(invokerbutton);
assert_true(called, "event was called");
- assert_true(eventInvoker == svgInvokee, "event invoker is set to right element");
- }, "event dispatches if invoker is non-HTML Element");
+ assert_equals(eventInvoker, invokerbutton, "event.invoker is set to right element");
+ assert_equals(eventTarget, svgInvokee, "event.target is set to right element");
+ }, "event dispatches if invokee is non-HTML Element");
</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-dialog-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-dialog-behavior.tentative.html
new file mode 100644
index 0000000000..774d308703
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-dialog-behavior.tentative.html
@@ -0,0 +1,455 @@
+<!doctype html>
+<meta charset="utf-8" />
+<meta name="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
+<meta name="timeout" content="long">
+<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-actions.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<script src="resources/invoker-utils.js"></script>
+
+<dialog id="invokee">
+ <button id="containedinvoker" invoketarget="invokee"></button>
+</dialog>
+<button id="invokerbutton" invoketarget="invokee"></button>
+
+<script>
+ function resetState() {
+ invokee.close();
+ try { invokee.hidePopover(); } catch {}
+ invokee.removeAttribute("popover");
+ invokerbutton.removeAttribute("invokeaction");
+ containedinvoker.removeAttribute("invokeaction");
+ }
+
+ // opening a dialog
+
+ [null, "", "showmodal", /* test case sensitivity */ "sHoWmOdAl"].forEach(
+ (action) => {
+ ["property", "attribute"].forEach((setType) => {
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ if (typeof action === "string") {
+ if (setType === "property") {
+ invokerbutton.invokeaction = action;
+ } else {
+ invokerbutton.setAttribute("invokeaction", action);
+ }
+ }
+ await clickOn(invokerbutton);
+ assert_true(invokee.open, "invokee.open");
+ assert_true(invokee.matches(":modal"), "invokee :modal");
+ },
+ `invoking (with invokeaction ${setType} as ${
+ action == null ? "auto" : action || "explicit empty"
+ }) closed dialog opens as modal`,
+ );
+
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ invokee.addEventListener("invoke", (e) => e.preventDefault(), {
+ once: true,
+ });
+ if (typeof action === "string") {
+ if (setType === "property") {
+ invokerbutton.invokeaction = action;
+ } else {
+ invokerbutton.setAttribute("invokeaction", action);
+ }
+ }
+ await clickOn(invokerbutton);
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ },
+ `invoking (with invokeaction ${setType} as ${
+ action == null ? "auto" : action || "explicit empty"
+ }) closed dialog with preventDefault is noop`,
+ );
+
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ invokee.addEventListener(
+ "invoke",
+ (e) => {
+ invokerbutton.setAttribute("invokeaction", "close");
+ },
+ { once: true },
+ );
+ if (typeof action === "string") {
+ if (setType === "property") {
+ invokerbutton.invokeaction = action;
+ } else {
+ invokerbutton.setAttribute("invokeaction", action);
+ }
+ }
+ await clickOn(invokerbutton);
+ assert_true(invokee.open, "invokee.open");
+ assert_true(invokee.matches(":modal"), "invokee :modal");
+ },
+ `invoking (with invokeaction ${setType} as ${
+ action == null ? "auto" : action || "explicit empty"
+ }) while changing action still opens as modal`,
+ );
+ });
+ },
+ );
+
+ // closing an already open dialog
+
+ [null, "", "close", /* test case sensitivity */ "cLoSe"].forEach((action) => {
+ ["property", "attribute"].forEach((setType) => {
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ invokee.show();
+ assert_true(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ if (typeof action === "string") {
+ if (setType === "property") {
+ containedinvoker.invokeaction = action;
+ } else {
+ containedinvoker.setAttribute("invokeaction", action);
+ }
+ }
+ await clickOn(containedinvoker);
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ },
+ `invoking to close (with invokeaction ${setType} as ${
+ action == null ? "auto" : action || "explicit empty"
+ }) open dialog closes`,
+ );
+
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ invokee.show();
+ assert_true(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ if (typeof action === "string") {
+ if (setType === "property") {
+ containedinvoker.invokeaction = action;
+ } else {
+ containedinvoker.setAttribute("invokeaction", action);
+ }
+ }
+ invokee.addEventListener("invoke", (e) => e.preventDefault(), {
+ once: true,
+ });
+ await clickOn(containedinvoker);
+ assert_true(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ },
+ `invoking to close (with invokeaction ${setType} as ${
+ action == null ? "auto" : action || "explicit empty"
+ }) open dialog with preventDefault is no-op`,
+ );
+
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ invokee.showModal();
+ assert_true(invokee.open, "invokee.open");
+ assert_true(invokee.matches(":modal"), "invokee :modal");
+ if (typeof action === "string") {
+ if (setType === "property") {
+ containedinvoker.invokeaction = action;
+ } else {
+ containedinvoker.setAttribute("invokeaction", action);
+ }
+ }
+ invokee.addEventListener("invoke", (e) => e.preventDefault(), {
+ once: true,
+ });
+ await clickOn(containedinvoker);
+ assert_true(invokee.open, "invokee.open");
+ assert_true(invokee.matches(":modal"), "invokee :modal");
+ },
+ `invoking to close (with invokeaction ${setType} as ${
+ action == null ? "auto" : action || "explicit empty"
+ }) open modal dialog with preventDefault is no-op`,
+ );
+
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ invokee.show();
+ assert_true(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ if (typeof action === "string") {
+ if (setType === "property") {
+ containedinvoker.invokeaction = action;
+ } else {
+ containedinvoker.setAttribute("invokeaction", action);
+ }
+ }
+ invokee.addEventListener(
+ "invoke",
+ (e) => {
+ containedinvoker.setAttribute("invokeaction", "show");
+ },
+ { once: true },
+ );
+ await clickOn(containedinvoker);
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ },
+ `invoking to close (with invokeaction ${setType} as ${
+ action == null ? "auto" : action || "explicit empty"
+ }) open dialog while changing action still closes`,
+ );
+
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ invokee.showModal();
+ assert_true(invokee.open, "invokee.open");
+ assert_true(invokee.matches(":modal"), "invokee :modal");
+ if (typeof action === "string") {
+ if (setType === "property") {
+ containedinvoker.invokeaction = action;
+ } else {
+ containedinvoker.setAttribute("invokeaction", action);
+ }
+ }
+ invokee.addEventListener(
+ "invoke",
+ (e) => {
+ containedinvoker.setAttribute("invokeaction", "show");
+ },
+ { once: true },
+ );
+ await clickOn(containedinvoker);
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ },
+ `invoking to close (with invokeaction ${setType} as ${
+ action == null ? "auto" : action || "explicit empty"
+ }) open modal dialog while changing action still closes`,
+ );
+ });
+ });
+
+ // showmodal explicit behaviours
+
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ containedinvoker.setAttribute("invokeaction", "showModal");
+ invokee.show();
+ assert_true(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ await clickOn(containedinvoker);
+ assert_true(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ }, "invoking (as showmodal) open dialog is noop");
+
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ containedinvoker.setAttribute("invokeaction", "showmodal");
+ invokee.showModal();
+ assert_true(invokee.open, "invokee.open");
+ assert_true(invokee.matches(":modal"), "invokee :modal");
+ invokee.addEventListener(
+ "invoke",
+ (e) => {
+ containedinvoker.setAttribute("invokeaction", "close");
+ },
+ { once: true },
+ );
+ await clickOn(invokerbutton);
+ assert_true(invokee.open, "invokee.open");
+ assert_true(invokee.matches(":modal"), "invokee :modal");
+ }, "invoking (as showmodal) open modal, while changing action still a no-op");
+
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ invokerbutton.setAttribute("invokeaction", "showmodal");
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ invokee.setAttribute("popover", "auto");
+ await clickOn(invokerbutton);
+ assert_true(invokee.open, "invokee.open");
+ assert_true(invokee.matches(":modal"), "invokee :modal");
+ }, "invoking (as showmodal) closed popover dialog opens as modal");
+
+ // close explicit behaviours
+
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ invokerbutton.setAttribute("invokeaction", "close");
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ await clickOn(containedinvoker);
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ }, "invoking (as close) already closed dialog is noop");
+
+ // invalid
+ [
+ "foo",
+ "foo-bar",
+ "auto",
+ "showpopover",
+ "hidepopover",
+ "togglepopover",
+ "showpicker",
+ ].forEach((action) => {
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ invokerbutton.setAttribute("invokeaction", action);
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ await clickOn(invokerbutton);
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ }, `invoking (as ${action}) on dialog does nothing`);
+
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ containedinvoker.setAttribute("invokeaction", action);
+ invokee.show();
+ assert_true(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ await clickOn(containedinvoker);
+ assert_true(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ }, `invoking (as ${action}) on open dialog does nothing`);
+
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ containedinvoker.setAttribute("invokeaction", action);
+ invokee.showModal();
+ assert_true(invokee.open, "invokee.open");
+ assert_true(invokee.matches(":modal"), "invokee :modal");
+ await clickOn(containedinvoker);
+ assert_true(invokee.open, "invokee.open");
+ assert_true(invokee.matches(":modal"), "invokee :modal");
+ }, `invoking (as ${action}) on open modal dialog does nothing`);
+
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ containedinvoker.setAttribute("invokeaction", action);
+ invokee.showModal();
+ assert_true(invokee.open, "invokee.open");
+ assert_true(invokee.matches(":modal"), "invokee :modal");
+ invokee.addEventListener(
+ "invoke",
+ (e) => {
+ containedinvoker.setAttribute("invokeaction", "");
+ },
+ { once: true },
+ );
+ await clickOn(containedinvoker);
+ assert_true(invokee.open, "invokee.open");
+ assert_true(invokee.matches(":modal"), "invokee :modal");
+ }, `invoking (as ${action}) on open modal while changing the attributer does nothing`);
+ });
+
+ // Open Popovers using Dialog actions
+ ["showmodal", "close", ""].forEach((action) => {
+ ["manual", "auto"].forEach((popoverState) => {
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ invokee.setAttribute("popover", popoverState);
+ invokee.showPopover();
+ containedinvoker.setAttribute("invokeaction", action);
+ assert_true(
+ invokee.matches(":popover-open"),
+ "invokee :popover-open",
+ );
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ invokee.addEventListener("invoke", (e) => e.preventDefault(), {
+ once: true,
+ });
+ await clickOn(containedinvoker);
+ assert_true(
+ invokee.matches(":popover-open"),
+ "invokee :popover-open",
+ );
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ },
+ `invoking (as ${
+ action || "explicit empty"
+ }) dialog as open popover=${popoverState} is noop`,
+ );
+ });
+ });
+
+ // Elements being disconnected during invoke steps
+ ["showmodal", "close", ""].forEach((action) => {
+ promise_test(
+ async function (t) {
+ t.add_cleanup(() => {
+ document.body.prepend(invokee);
+ resetState();
+ });
+ const invokee = document.querySelector("#invokee");
+ invokerbutton.setAttribute("invokeaction", action);
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ invokee.addEventListener(
+ "invoke",
+ (e) => {
+ invokee.remove();
+ },
+ {
+ once: true,
+ },
+ );
+ await clickOn(invokerbutton);
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ },
+ `invoking (as ${
+ action || "explicit empty"
+ }) dialog that is removed is noop`,
+ );
+
+ promise_test(
+ async function (t) {
+ const invokerbutton = document.createElement("button");
+ invokerbutton.invokeTargetElement = invokee;
+ invokerbutton.setAttribute("invokeaction", action);
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ await clickOn(invokerbutton);
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ },
+ `invoking (as ${
+ action || "explicit empty"
+ }) dialog from a detached invoker`,
+ );
+
+ promise_test(
+ async function (t) {
+ const invokerbutton = document.createElement("button");
+ const invokee = document.createElement("dialog");
+ invokerbutton.invokeTargetElement = invokee;
+ invokerbutton.setAttribute("invokeaction", action);
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ await clickOn(invokerbutton);
+ assert_false(invokee.open, "invokee.open");
+ assert_false(invokee.matches(":modal"), "invokee :modal");
+ },
+ `invoking (as ${
+ action || "explicit empty"
+ }) detached dialog from a detached invoker`,
+ );
+ });
+</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-popover-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-popover-behavior.tentative.html
index 03eba22285..2bddfa7621 100644
--- a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-popover-behavior.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-popover-behavior.tentative.html
@@ -10,7 +10,7 @@
<script src="resources/invoker-utils.js"></script>
<div id="invokee" popover>
- <button id="invokerbutton2" invoketarget="invokee"></button>
+ <button id="containedinvoker" invoketarget="invokee"></button>
</div>
<button id="invokerbutton" invoketarget="invokee"></button>
@@ -44,7 +44,7 @@
promise_test(async function (t) {
invokee.showPopover();
assert_true(invokee.matches(":popover-open"));
- await clickOn(invokerbutton2);
+ await clickOn(containedinvoker);
assert_false(invokee.matches(":popover-open"));
}, "invoking (as auto) from within open popover closes");
@@ -55,7 +55,7 @@
once: true,
});
assert_true(invokee.matches(":popover-open"));
- await clickOn(invokerbutton2);
+ await clickOn(containedinvoker);
assert_true(invokee.matches(":popover-open"));
}, "invoking (as auto) open popover with preventDefault does not close");
@@ -93,8 +93,8 @@
promise_test(async function (t) {
invokee.showPopover();
- invokerbutton2.setAttribute("invokeaction", "togglepopover");
- t.add_cleanup(() => invokerbutton2.removeAttribute("invokeaction"));
+ containedinvoker.setAttribute("invokeaction", "togglepopover");
+ t.add_cleanup(() => containedinvoker.removeAttribute("invokeaction"));
assert_true(invokee.matches(":popover-open"));
await clickOn(invokerbutton);
assert_false(invokee.matches(":popover-open"));
@@ -102,23 +102,23 @@
promise_test(async function (t) {
invokee.showPopover();
- invokerbutton2.setAttribute("invokeaction", "togglepopover");
- t.add_cleanup(() => invokerbutton2.removeAttribute("invokeaction"));
+ containedinvoker.setAttribute("invokeaction", "togglepopover");
+ t.add_cleanup(() => containedinvoker.removeAttribute("invokeaction"));
assert_true(invokee.matches(":popover-open"));
- await clickOn(invokerbutton2);
+ await clickOn(containedinvoker);
assert_false(invokee.matches(":popover-open"));
}, "invoking (as togglepopover) from within open popover closes");
promise_test(async function (t) {
invokee.showPopover();
t.add_cleanup(() => invokee.hidePopover());
- invokerbutton2.setAttribute("invokeaction", "togglepopover");
- t.add_cleanup(() => invokerbutton2.removeAttribute("invokeaction"));
+ containedinvoker.setAttribute("invokeaction", "togglepopover");
+ t.add_cleanup(() => containedinvoker.removeAttribute("invokeaction"));
invokee.addEventListener("invoke", (e) => e.preventDefault(), {
once: true,
});
assert_true(invokee.matches(":popover-open"));
- await clickOn(invokerbutton2);
+ await clickOn(containedinvoker);
assert_true(invokee.matches(":popover-open"));
}, "invoking (as togglepopover) open popover with preventDefault does not close");
@@ -175,35 +175,59 @@
}, "invoking (as hidepopover) closed popover is noop");
promise_test(async function (t) {
- invokerbutton2.setAttribute("invokeaction", "hidepopover");
- t.add_cleanup(() => invokerbutton2.removeAttribute("invokeaction"));
+ containedinvoker.setAttribute("invokeaction", "hidepopover");
+ t.add_cleanup(() => containedinvoker.removeAttribute("invokeaction"));
invokee.showPopover();
assert_true(invokee.matches(":popover-open"));
- await clickOn(invokerbutton2);
+ await clickOn(containedinvoker);
t.add_cleanup(() => invokee.hidePopover());
assert_false(invokee.matches(":popover-open"));
}, "invoking (as hidepopover) open popover closes");
promise_test(async function (t) {
- invokerbutton2.setAttribute("invokeaction", "hIdEpOpOvEr");
- t.add_cleanup(() => invokerbutton2.removeAttribute("invokeaction"));
+ containedinvoker.setAttribute("invokeaction", "hIdEpOpOvEr");
+ t.add_cleanup(() => containedinvoker.removeAttribute("invokeaction"));
invokee.showPopover();
assert_true(invokee.matches(":popover-open"));
- await clickOn(invokerbutton2);
+ await clickOn(containedinvoker);
t.add_cleanup(() => invokee.hidePopover());
assert_false(invokee.matches(":popover-open"));
}, "invoking (as hidepopover - case insensitive) open popover closes");
promise_test(async function (t) {
- invokerbutton2.setAttribute("invokeaction", "hidepopover");
- t.add_cleanup(() => invokerbutton2.removeAttribute("invokeaction"));
+ containedinvoker.setAttribute("invokeaction", "hidepopover");
+ t.add_cleanup(() => containedinvoker.removeAttribute("invokeaction"));
invokee.showPopover();
t.add_cleanup(() => invokee.hidePopover());
assert_true(invokee.matches(":popover-open"));
invokee.addEventListener("invoke", (e) => e.preventDefault(), {
once: true,
});
- await clickOn(invokerbutton2);
+ await clickOn(containedinvoker);
assert_true(invokee.matches(":popover-open"));
}, "invoking (as hidepopover) open popover with preventDefault does not close");
+
+ // invalid
+
+ ["foo", "togglemodal", "showpicker", "toggle", "open", "close"].forEach(action => {
+ promise_test(async function (t) {
+ invokerbutton.setAttribute("invokeaction", action);
+ t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
+ assert_false(invokee.matches(":popover-open"));
+ await clickOn(invokerbutton);
+ assert_false(invokee.matches(":popover-open"));
+ }, `invoking (as ${action}) on popover does nothing`);
+
+ promise_test(async function (t) {
+ invokerbutton.setAttribute("invokeaction", action);
+ t.add_cleanup(() => {
+ invokerbutton.removeAttribute("invokeaction")
+ invokee.hidePopover();
+ });
+ invokee.showPopover()
+ assert_true(invokee.matches(":popover-open"));
+ await clickOn(invokerbutton);
+ assert_true(invokee.matches(":popover-open"));
+ }, `invoking (as ${action}) on open popover does nothing`);
+ })
</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/resources/invoker-utils.js b/testing/web-platform/tests/html/semantics/invokers/resources/invoker-utils.js
index 317945502d..8420f24b6f 100644
--- a/testing/web-platform/tests/html/semantics/invokers/resources/invoker-utils.js
+++ b/testing/web-platform/tests/html/semantics/invokers/resources/invoker-utils.js
@@ -2,9 +2,13 @@ function waitForRender() {
return new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve)));
}
async function clickOn(element) {
- const actions = new test_driver.Actions();
await waitForRender();
- await actions.pointerMove(0, 0, {origin: element})
+ let rect = element.getBoundingClientRect();
+ let actions = new test_driver.Actions();
+ // FIXME: Switch to pointerMove(0, 0, {origin: element}) once
+ // https://github.com/web-platform-tests/wpt/issues/41257 is fixed.
+ await actions
+ .pointerMove(Math.round(rect.x + rect.width / 2), Math.round(rect.y + rect.height / 2), {})
.pointerDown({button: actions.ButtonType.LEFT})
.pointerUp({button: actions.ButtonType.LEFT})
.send();