summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/html/semantics/invokers
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/html/semantics/invokers')
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/idlharness.tentative.html2
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/interestelement-interface.tentative.html1
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/interestevent-dispatch-shadow.tentative.html104
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/interestevent-interface.tentative.html167
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/interesttarget-button-event-dispatch.tentative.html155
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/interesttarget-on-popover-behavior.tentative.html113
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invokeelement-interface.tentative.html2
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invokeevent-dispatch-shadow.tentative.html2
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invokeevent-interface.tentative.html2
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-button-event-dispatch.tentative.html103
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-fullscreen-behavior.tentative.html1
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-audio-behavior.tentative.html40
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-audio-invalid-behavior.tentative.html37
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-details-behavior.tentative.html295
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-details-invalid-behavior.tentative.html49
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-dialog-behavior.tentative.html61
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-dialog-invalid-behavior.tentative.html120
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-popover-behavior.tentative.html312
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-popover-invalid-behavior.tentative.html47
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/invoketarget-on-video-behavior.tentative.html40
-rw-r--r--testing/web-platform/tests/html/semantics/invokers/resources/invoker-utils.js11
21 files changed, 1148 insertions, 516 deletions
diff --git a/testing/web-platform/tests/html/semantics/invokers/idlharness.tentative.html b/testing/web-platform/tests/html/semantics/invokers/idlharness.tentative.html
index b215f65813..8a86a5aaa1 100644
--- a/testing/web-platform/tests/html/semantics/invokers/idlharness.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/idlharness.tentative.html
@@ -1,6 +1,6 @@
<!doctype html>
<meta charset="utf-8" />
-<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<meta name="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
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
index dc119de833..8b1e375695 100644
--- a/testing/web-platform/tests/html/semantics/invokers/interestelement-interface.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/interestelement-interface.tentative.html
@@ -1,5 +1,6 @@
<!doctype html>
<meta charset="utf-8" />
+<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
<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>
diff --git a/testing/web-platform/tests/html/semantics/invokers/interestevent-dispatch-shadow.tentative.html b/testing/web-platform/tests/html/semantics/invokers/interestevent-dispatch-shadow.tentative.html
new file mode 100644
index 0000000000..d96907ec84
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/interestevent-dispatch-shadow.tentative.html
@@ -0,0 +1,104 @@
+<!doctype html>
+<meta charset="utf-8" />
+<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<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>
+<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>
+
+<div id="div"></div>
+<button id="button"></button>
+
+<script>
+ test(function () {
+ const host = document.createElement("div");
+ const shadow = host.attachShadow({ mode: "closed" });
+ const slot = shadow.appendChild(document.createElement("slot"));
+ let childEvent = null;
+ let childEventTarget = null;
+ let childEventInvoker = null;
+ let hostEvent = null;
+ let hostEventTarget = null;
+ let hostEventInvoker = null;
+ slot.addEventListener(
+ "interest",
+ (e) => {
+ childEvent = e;
+ childEventTarget = e.target;
+ childEventInvoker = e.invoker;
+ },
+ { once: true },
+ );
+ host.addEventListener(
+ "interest",
+ (e) => {
+ hostEvent = e;
+ hostEventTarget = e.target;
+ hostEventInvoker = e.invoker;
+ },
+ { once: true },
+ );
+ const event = new InterestEvent("interest", {
+ bubbles: true,
+ invoker: slot,
+ composed: true,
+ });
+ slot.dispatchEvent(event);
+ assert_true(childEvent instanceof InterestEvent, "slot saw interest event");
+ assert_equals(
+ childEventTarget,
+ slot,
+ "target is child inside shadow boundary",
+ );
+ assert_equals(
+ childEventInvoker,
+ slot,
+ "invoker is child inside shadow boundary",
+ );
+ assert_equals(
+ hostEvent,
+ childEvent,
+ "event dispatch propagates across shadow boundary",
+ );
+ assert_equals(
+ hostEventTarget,
+ host,
+ "target is retargeted to shadowroot host",
+ );
+ assert_equals(
+ hostEventInvoker,
+ host,
+ "invoker is retargeted to shadowroot host",
+ );
+ }, "InterestEvent propagates across shadow boundaries retargeting invoker");
+
+ test(function (t) {
+ const host = document.createElement("div");
+ document.body.append(host);
+ t.add_cleanup(() => host.remove());
+ const shadow = host.attachShadow({ mode: "open" });
+ const button = shadow.appendChild(document.createElement("button"));
+ const interestee = host.appendChild(document.createElement("div"));
+ button.interestTargetElement = interestee;
+ let event = null;
+ let eventTarget = null;
+ let eventInvoker = null;
+ interestee.addEventListener(
+ "interest",
+ (e) => {
+ event = e;
+ eventTarget = e.target;
+ eventInvoker = e.invoker;
+ },
+ { once: true },
+ );
+ button.focus();
+ assert_true(event instanceof InterestEvent);
+ assert_equals(eventTarget, interestee, "target is interestee");
+ assert_equals(eventInvoker, host, "interestee is host");
+ }, "cross shadow InterestEvent retargets interestee to host element");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/interestevent-interface.tentative.html b/testing/web-platform/tests/html/semantics/invokers/interestevent-interface.tentative.html
new file mode 100644
index 0000000000..ed7d82f1fb
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/interestevent-interface.tentative.html
@@ -0,0 +1,167 @@
+<!doctype html>
+<meta charset="utf-8" />
+<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<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>
+<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>
+
+<div id="div"></div>
+<button id="button"></button>
+
+<script>
+ test(function () {
+ const event = new InterestEvent("test");
+ assert_equals(event.action, "");
+ assert_readonly(event, "action", "readonly attribute value");
+ }, "action is a readonly defaulting to ''");
+
+ test(function () {
+ const event = new InterestEvent("test");
+ assert_equals(event.invoker, null);
+ assert_readonly(event, "invoker", "readonly attribute value");
+ }, "invoker is readonly defaulting to null");
+
+ test(function () {
+ const event = new InterestEvent("test", { action: "sAmPle" });
+ assert_equals(event.action, "sAmPle");
+ }, "action reflects initialized attribute");
+
+ test(function () {
+ const event = new InterestEvent("test", { action: undefined });
+ assert_equals(event.action, "");
+ }, "action set to undefined");
+
+ test(function () {
+ const event = new InterestEvent("test", { action: null });
+ assert_equals(event.action, "null");
+ }, "action set to null");
+
+ test(function () {
+ const event = new InterestEvent("test", { action: false });
+ assert_equals(event.action, "false");
+ }, "action set to false");
+
+ test(function () {
+ const event = new InterestEvent("test", { action: "" });
+ assert_equals(event.action, "");
+ }, "action explicitly set to empty string");
+
+ test(function () {
+ const event = new InterestEvent("test", { action: true });
+ assert_equals(event.action, "true");
+ }, "action set to true");
+
+ test(function () {
+ const event = new InterestEvent("test", { action: 0.5 });
+ assert_equals(event.action, "0.5");
+ }, "action set to a number");
+
+ test(function () {
+ const event = new InterestEvent("test", { action: [] });
+ assert_equals(event.action, "");
+ }, "action set to []");
+
+ test(function () {
+ const event = new InterestEvent("test", { action: [1, 2, 3] });
+ assert_equals(event.action, "1,2,3");
+ }, "action set to [1, 2, 3]");
+
+ test(function () {
+ const event = new InterestEvent("test", { action: { sample: 0.5 } });
+ assert_equals(event.action, "[object Object]");
+ }, "action set to an object");
+
+ test(function () {
+ const event = new InterestEvent("test", {
+ action: {
+ toString() {
+ return "sample";
+ },
+ },
+ });
+ assert_equals(event.action, "sample");
+ }, "action set to an object with a toString function");
+
+ test(function () {
+ const eventInit = { action: "sample", invoker: document.body };
+ const event = new InterestEvent("test", eventInit);
+ assert_equals(event.action, "sample");
+ assert_equals(event.invoker, document.body);
+ }, "InterestEventInit properties set value");
+
+ test(function () {
+ const eventInit = {
+ action: "open",
+ invoker: document.getElementById("div"),
+ };
+ const event = new InterestEvent("beforetoggle", eventInit);
+ assert_equals(event.action, "open");
+ assert_equals(event.invoker, document.getElementById("div"));
+ }, "InterestEventInit properties set value 2");
+
+ test(function () {
+ const eventInit = {
+ action: "closed",
+ invoker: document.getElementById("button"),
+ };
+ const event = new InterestEvent("toggle", eventInit);
+ assert_equals(event.action, "closed");
+ assert_equals(event.invoker, document.getElementById("button"));
+ }, "InterestEventInit properties set value 3");
+
+ test(function () {
+ const event = new InterestEvent("test", { invoker: undefined });
+ assert_equals(event.invoker, null);
+ }, "invoker set to undefined");
+
+ test(function () {
+ const event = new InterestEvent("test", { invoker: null });
+ assert_equals(event.invoker, null);
+ }, "invoker set to null");
+
+ test(function () {
+ assert_throws_js(
+ TypeError,
+ function () {
+ new InterestEvent("test", { invoker: false });
+ },
+ "invoker is not an object",
+ );
+ }, "invoker set to false");
+
+ test(function () {
+ assert_throws_js(
+ TypeError,
+ function () {
+ const event = new InterestEvent("test", { invoker: true });
+ },
+ "invoker is not an object",
+ );
+ }, "invoker set to true");
+
+ test(function () {
+ assert_throws_js(
+ TypeError,
+ function () {
+ const event = new InterestEvent("test", { invoker: {} });
+ },
+ "invoker is not an object",
+ );
+ }, "invoker set to {}");
+
+ test(function () {
+ assert_throws_js(
+ TypeError,
+ function () {
+ const eventInit = { action: "closed", invoker: new XMLHttpRequest() };
+ const event = new InterestEvent("toggle", eventInit);
+ },
+ "invoker is not an Element",
+ );
+ }, "invoker set to non-Element EventTarget");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/interesttarget-button-event-dispatch.tentative.html b/testing/web-platform/tests/html/semantics/invokers/interesttarget-button-event-dispatch.tentative.html
new file mode 100644
index 0000000000..7fdfdfaa70
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/interesttarget-button-event-dispatch.tentative.html
@@ -0,0 +1,155 @@
+<!doctype html>
+<meta charset="utf-8" />
+<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<meta name="author" title="Luke Warlow" href="mailto:lwarlow@igalia.com" />
+<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>
+
+<div id="interestee"></div>
+<button id="interestbutton" interesttarget="interestee">Button</button>
+<a href="/" id="interestanchor" interesttarget="interestee">Anchor</a>
+<button id="otherbutton">Other Button</button>
+
+<script>
+ promise_test(async function (t) {
+ t.add_cleanup(() => otherbutton.focus());
+ let event = null;
+ interestee.addEventListener("interest", (e) => (event = e), { once: true });
+ interestbutton.focus();
+ assert_true(event instanceof InterestEvent, "event is InterestEvent");
+ assert_equals(event.type, "interest", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, "", "action");
+ assert_equals(event.target, interestee, "target");
+ assert_equals(event.invoker, interestbutton, "invoker");
+ }, "InterestEvent dispatches on button focus");
+
+ promise_test(async function (t) {
+ t.add_cleanup(() => otherbutton.focus());
+ let event = null;
+ interestee.addEventListener("interest", (e) => (event = e), { once: true });
+ await hoverOver(interestbutton);
+ assert_true(event instanceof InterestEvent, "event is InterestEvent");
+ assert_equals(event.type, "interest", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, "", "action");
+ assert_equals(event.target, interestee, "target");
+ assert_equals(event.invoker, interestbutton, "invoker");
+ }, "InterestEvent dispatches on button hover");
+
+ promise_test(async function (t) {
+ t.add_cleanup(() => otherbutton.focus());
+ let event = null;
+ interestee.addEventListener("interest", (e) => (event = e), { once: true });
+ interestanchor.focus();
+ assert_true(event instanceof InterestEvent, "event is InterestEvent");
+ assert_equals(event.type, "interest", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, "", "action");
+ assert_equals(event.target, interestee, "target");
+ assert_equals(event.invoker, interestanchor, "invoker");
+ }, "InterestEvent dispatches on anchor focus");
+
+ promise_test(async function (t) {
+ t.add_cleanup(() => otherbutton.focus());
+ let event = null;
+ interestee.addEventListener("interest", (e) => (event = e), { once: true });
+ await hoverOver(interestanchor);
+ assert_true(event instanceof InterestEvent, "event is InterestEvent");
+ assert_equals(event.type, "interest", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, "", "action");
+ assert_equals(event.target, interestee, "target");
+ assert_equals(event.invoker, interestanchor, "invoker");
+ }, "InterestEvent dispatches on anchor hover");
+
+ promise_test(async function (t) {
+ t.add_cleanup(() => otherbutton.focus());
+ let event = null;
+ interestee.addEventListener("interest", (e) => (event = e), { once: true });
+ interestbutton.interestAction = "fooBar";
+ interestbutton.focus();
+ assert_true(event instanceof InterestEvent, "event is InterestEvent");
+ assert_equals(event.type, "interest", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, "fooBar", "action");
+ assert_equals(event.target, interestee, "target");
+ assert_equals(event.invoker, interestbutton, "invoker");
+ }, "event action is set to interestAction");
+
+ promise_test(async function (t) {
+ t.add_cleanup(() => otherbutton.focus());
+ let event = null;
+ interestee.addEventListener("interest", (e) => (event = e), { once: true });
+ interestbutton.setAttribute("interestaction", "BaRbAz");
+ interestbutton.focus();
+ assert_true(event instanceof InterestEvent, "event is InterestEvent");
+ assert_equals(event.type, "interest", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, "BaRbAz", "action");
+ assert_equals(event.target, interestee, "target");
+ assert_equals(event.invoker, interestbutton, "invoker");
+ }, "event action is set to interestaction attribute");
+
+ promise_test(async function (t) {
+ t.add_cleanup(() => {
+ interestbutton.removeAttribute('disabled');
+ otherbutton.focus();
+ });
+ let called = false;
+ interestee.addEventListener(
+ "interest",
+ () => {
+ called = true;
+ },
+ { once: true },
+ );
+ interestbutton.setAttribute("disabled", "");
+ interestbutton.focus();
+ assert_false(called, "event was not called");
+ }, "event does not dispatch if invoker is disabled");
+
+ promise_test(async function (t) {
+ svgInterestee = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
+ t.add_cleanup(() => {
+ interestbutton.interestTargetElement = interestee;
+ svgInterestee.remove();
+ otherbutton.focus();
+ });
+ document.body.append(svgInterestee);
+ let called = false;
+ assert_false(svgInterestee instanceof HTMLElement);
+ assert_true(svgInterestee instanceof Element);
+ let event = null;
+ svgInterestee.addEventListener(
+ "interest",
+ (e) => {
+ event = e;
+ called = true;
+ },
+ { once: true },
+ );
+ interestbutton.interestTargetElement = svgInterestee;
+ interestbutton.focus();
+ assert_true(called, "event was called");
+ assert_equals(event.invoker, interestbutton, "event.invoker is set to right element");
+ assert_equals(event.target, svgInterestee, "event.target is set to right element");
+ }, "event dispatches if interestee is non-HTML Element");
+</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/interesttarget-on-popover-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/interesttarget-on-popover-behavior.tentative.html
new file mode 100644
index 0000000000..b930fc645d
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/interesttarget-on-popover-behavior.tentative.html
@@ -0,0 +1,113 @@
+<!doctype html>
+<meta charset="utf-8" />
+<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<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>
+<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>
+
+<div id="interestee" popover>
+ Popover Content
+</div>
+<button id="interestbutton" interesttarget="interestee">Interest Invoker</button>
+<button id="otherbutton">Other button</button>
+
+<script>
+ function reset() {
+ hoverOver(otherbutton);
+ otherbutton.focus();
+ interestee.hidePopover();
+ interestbutton.removeAttribute("interestaction");
+ }
+
+ // auto
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ assert_false(interestee.matches(":popover-open"));
+ await hoverOver(interestbutton);
+ assert_true(interestee.matches(":popover-open"));
+ }, "hover interest invoking (as auto) closed popover opens");
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ interestee.showPopover();
+ assert_true(interestee.matches(":popover-open"));
+ await hoverOver(interestbutton);
+ assert_false(interestee.matches(":popover-open"));
+ }, "hover interest invoking (as auto) open popover closes");
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ assert_false(interestee.matches(":popover-open"));
+ interestbutton.focus();
+ assert_true(interestee.matches(":popover-open"));
+ }, "focus interest invoking (as auto) closed popover opens");
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ interestee.showPopover();
+ assert_true(interestee.matches(":popover-open"));
+ interestbutton.focus();
+ assert_false(interestee.matches(":popover-open"));
+ }, "focus interest invoking (as auto) open popover closes");
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ assert_false(interestee.matches(":popover-open"));
+ interestee.addEventListener("interest", (e) => e.preventDefault(), {
+ once: true,
+ });
+ await hoverOver(interestbutton);
+ assert_false(interestee.matches(":popover-open"));
+ }, "interest invoking (as auto) closed popover with preventDefault does not open");
+
+ // togglepopover
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ assert_false(interestee.matches(":popover-open"));
+ interestbutton.setAttribute("interestaction", "togglepopover");
+ await hoverOver(interestbutton);
+ assert_true(interestee.matches(":popover-open"));
+ }, "hover interest invoking (as togglepopover) closed popover opens");
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ interestee.showPopover();
+ assert_true(interestee.matches(":popover-open"));
+ interestbutton.setAttribute("interestaction", "togglepopover");
+ await hoverOver(interestbutton);
+ assert_false(interestee.matches(":popover-open"));
+ }, "hover interest invoking (as togglepopover) open popover closes");
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ assert_false(interestee.matches(":popover-open"));
+ interestbutton.setAttribute("interestaction", "togglepopover");
+ interestbutton.focus();
+ assert_true(interestee.matches(":popover-open"));
+ }, "focus interest invoking (as togglepopover) closed popover opens");
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ interestee.showPopover();
+ assert_true(interestee.matches(":popover-open"));
+ interestbutton.setAttribute("interestaction", "togglepopover");
+ interestbutton.focus();
+ assert_false(interestee.matches(":popover-open"));
+ }, "focus interest invoking (as togglepopover) open popover closes");
+
+ promise_test(async function (t) {
+ t.add_cleanup(reset);
+ assert_false(interestee.matches(":popover-open"));
+ interestbutton.setAttribute("interestaction", "tOgGlEpOpOvEr");
+ interestbutton.focus();
+ assert_true(interestee.matches(":popover-open"));
+ }, "interest invoking (as togglepopover - case insensitive) closed popover opens");
+
+</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 5a2854fe31..5adacadabb 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
@@ -1,6 +1,6 @@
<!doctype html>
<meta charset="utf-8" />
-<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<meta name="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invokeevent-dispatch-shadow.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invokeevent-dispatch-shadow.tentative.html
index 84337d5723..1ecff88760 100644
--- a/testing/web-platform/tests/html/semantics/invokers/invokeevent-dispatch-shadow.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/invokeevent-dispatch-shadow.tentative.html
@@ -1,6 +1,6 @@
<!doctype html>
<meta charset="utf-8" />
-<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<meta name="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
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 382f808071..0cfb4d5ee5 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
@@ -1,6 +1,6 @@
<!doctype html>
<meta charset="utf-8" />
-<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<meta name="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
<link rel="help" href="https://open-ui.org/components/invokers.explainer/" />
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
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 d8d9c04022..9120cc3192 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
@@ -1,6 +1,7 @@
<!doctype html>
<meta charset="utf-8" />
-<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<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>
@@ -27,35 +28,63 @@
assert_equals(event.invoker, invokerbutton, "invoker");
}, "event dispatches on click");
- promise_test(async function (t) {
- let event = null;
- invokee.addEventListener("invoke", (e) => (event = e), { once: true });
- invokerbutton.invokeAction = "fooBar";
- await clickOn(invokerbutton);
- assert_true(event instanceof InvokeEvent, "event is InvokeEvent");
- assert_equals(event.type, "invoke", "type");
- assert_equals(event.bubbles, false, "bubbles");
- assert_equals(event.composed, true, "composed");
- assert_equals(event.isTrusted, true, "isTrusted");
- assert_equals(event.action, "fooBar", "action");
- assert_equals(event.target, invokee, "target");
- assert_equals(event.invoker, invokerbutton, "invoker");
- }, "event action is set to invokeAction");
+ // valid custom invokeactions
+ ["-foo", "foo-", "cAsE-cArRiEs", "-", "-a-", "a-b", "---", "show-picker"].forEach(
+ (action) => {
+ promise_test(async function (t) {
+ t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
+ let event = null;
+ invokee.addEventListener("invoke", (e) => (event = e), { once: true });
+ invokerbutton.invokeAction = action;
+ await clickOn(invokerbutton);
+ assert_true(event instanceof InvokeEvent, "event is InvokeEvent");
+ assert_equals(event.type, "invoke", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, action, "action");
+ assert_equals(event.target, invokee, "target");
+ assert_equals(event.invoker, invokerbutton, "invoker");
+ }, `setting custom invokeAction property to ${action} (must include dash) sets event action`);
- promise_test(async function (t) {
- let event = null;
- invokee.addEventListener("invoke", (e) => (event = e), { once: true });
- invokerbutton.setAttribute("invokeaction", "BaRbAz");
- await clickOn(invokerbutton);
- assert_true(event instanceof InvokeEvent, "event is InvokeEvent");
- assert_equals(event.type, "invoke", "type");
- assert_equals(event.bubbles, false, "bubbles");
- assert_equals(event.composed, true, "composed");
- assert_equals(event.isTrusted, true, "isTrusted");
- assert_equals(event.action, "BaRbAz", "action");
- assert_equals(event.target, invokee, "target");
- assert_equals(event.invoker, invokerbutton, "invoker");
- }, "event action is set to invokeaction attribute");
+ promise_test(async function (t) {
+ t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
+ let event = null;
+ invokee.addEventListener("invoke", (e) => (event = e), { once: true });
+ invokerbutton.setAttribute("invokeaction", action);
+ await clickOn(invokerbutton);
+ assert_true(event instanceof InvokeEvent, "event is InvokeEvent");
+ assert_equals(event.type, "invoke", "type");
+ assert_equals(event.bubbles, false, "bubbles");
+ assert_equals(event.composed, true, "composed");
+ assert_equals(event.isTrusted, true, "isTrusted");
+ assert_equals(event.action, action, "action");
+ assert_equals(event.target, invokee, "target");
+ assert_equals(event.invoker, invokerbutton, "invoker");
+ }, `setting custom invokeaction attribute to ${action} (must include dash) sets event action`);
+ },
+ );
+
+ // invalid custom invokeactions
+ ["foo", "foobar", "foo bar", "em—dash", "hidedocument"].forEach((action) => {
+ promise_test(async function (t) {
+ t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
+ let event = null;
+ invokee.addEventListener("invoke", (e) => (event = e), { once: true });
+ invokerbutton.invokeAction = action;
+ await clickOn(invokerbutton);
+ assert_equals(event, null, "event should not have fired");
+ }, `setting custom invokeAction property to ${action} (no dash) did not dispatch an event`);
+
+ promise_test(async function (t) {
+ t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
+ let event = null;
+ invokee.addEventListener("invoke", (e) => (event = e), { once: true });
+ invokerbutton.setAttribute("invokeaction", action);
+ await clickOn(invokerbutton);
+ assert_equals(event, null, "event should not have fired");
+ }, `setting custom invokeaction attribute to ${action} (no dash) did not dispatch an event`);
+ });
promise_test(async function (t) {
let called = false;
@@ -78,7 +107,7 @@
}, "event does not dispatch if click:preventDefault is called");
promise_test(async function (t) {
- t.add_cleanup(() => invokerbutton.removeAttribute('disabled'));
+ t.add_cleanup(() => invokerbutton.removeAttribute("disabled"));
let called = false;
invokee.addEventListener(
"invoke",
@@ -93,7 +122,7 @@
}, "event does not dispatch if invoker is disabled");
promise_test(async function (t) {
- svgInvokee = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
+ svgInvokee = document.createElementNS("http://www.w3.org/2000/svg", "svg");
t.add_cleanup(() => {
invokerbutton.invokeTargetElement = invokee;
svgInvokee.remove();
@@ -115,7 +144,15 @@
invokerbutton.invokeTargetElement = svgInvokee;
await clickOn(invokerbutton);
assert_true(called, "event was called");
- assert_equals(eventInvoker, invokerbutton, "event.invoker is set to right element");
- assert_equals(eventTarget, svgInvokee, "event.target is set to right 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-fullscreen-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-fullscreen-behavior.tentative.html
index b72020283e..2e2c5f683f 100644
--- a/testing/web-platform/tests/html/semantics/invokers/invoketarget-fullscreen-behavior.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-fullscreen-behavior.tentative.html
@@ -1,6 +1,7 @@
<!doctype html>
<meta charset="utf-8" />
<meta name="author" title="Luke Warlow" href="mailto:luke@warlow.dev" />
+<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>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-audio-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-audio-behavior.tentative.html
index f3abeae165..37acb7a539 100644
--- a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-audio-behavior.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-audio-behavior.tentative.html
@@ -1,6 +1,7 @@
<!doctype html>
<meta charset="utf-8" />
<meta name="author" title="Luke Warlow" href="mailto:luke@warlow.dev" />
+<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>
@@ -25,7 +26,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -43,7 +44,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "playpause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.paused);
@@ -59,7 +60,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "playpause");
invokerbutton.click();
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.paused);
@@ -78,7 +79,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "playpause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -91,12 +92,12 @@
invokee.currentTime = 0;
invokee.muted = false;
});
- await test_driver.bless('play audio');
+ await test_driver.bless("play audio");
invokee.play();
assert_false(invokee.paused);
invokerbutton.setAttribute("invokeaction", "playpause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -114,7 +115,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "play");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.paused);
@@ -130,7 +131,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "play");
invokerbutton.click();
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.paused);
@@ -149,7 +150,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "play");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -162,12 +163,12 @@
invokee.currentTime = 0;
invokee.muted = false;
});
- await test_driver.bless('play audio');
+ await test_driver.bless("play audio");
invokee.play();
assert_false(invokee.paused);
invokerbutton.setAttribute("invokeaction", "play");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.paused);
@@ -185,8 +186,8 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "pause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
- requestAnimationFrame(resolve);
+ await new Promise((resolve) => {
+ requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
}, "invoking audio with pause action is a no-op");
@@ -204,7 +205,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "pause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -217,12 +218,12 @@
invokee.currentTime = 0;
invokee.muted = false;
});
- await test_driver.bless('play audio');
+ await test_driver.bless("play audio");
invokee.play();
assert_false(invokee.paused);
invokerbutton.setAttribute("invokeaction", "pause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -240,7 +241,7 @@
assert_false(invokee.muted);
invokerbutton.setAttribute("invokeaction", "toggleMuted");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.muted);
@@ -259,7 +260,7 @@
assert_false(invokee.muted);
invokerbutton.setAttribute("invokeaction", "toggleMuted");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.muted);
@@ -276,10 +277,9 @@
assert_true(invokee.muted);
invokerbutton.setAttribute("invokeaction", "toggleMuted");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.muted);
}, "invoking muted audio with toggleMuted action unmutes it");
-
</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-audio-invalid-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-audio-invalid-behavior.tentative.html
new file mode 100644
index 0000000000..9e15ce38e8
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-audio-invalid-behavior.tentative.html
@@ -0,0 +1,37 @@
+<!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>
+
+<audio controls id="invokee" src="/media/sound_5.mp3"></audio>
+<button id="invokerbutton" invoketarget="invokee"></button>
+
+<script>
+ // invalid actions on audio
+ [
+ "foo-bar",
+ "showpopover",
+ "showmodal",
+ "showpicker",
+ "open",
+ "close",
+ ].forEach((action) => {
+ promise_test(async function (t) {
+ t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
+ invokerbutton.setAttribute("invokeaction", action);
+ assert_true(invokee.paused);
+ assert_false(invokee.muted);
+ await clickOn(invokerbutton);
+ await waitForRender();
+ assert_true(invokee.paused);
+ assert_false(invokee.muted);
+ }, `invoking (as ${action}) on audio does nothing`);
+ });
+</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-details-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-details-behavior.tentative.html
index c6735e2611..ad9b6caa57 100644
--- a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-details-behavior.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-details-behavior.tentative.html
@@ -1,6 +1,7 @@
<!doctype html>
<meta charset="utf-8" />
<meta name="author" title="Luke Warlow" href="mailto:luke@warlow.dev" />
+<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>
@@ -9,210 +10,136 @@
<script src="/resources/testdriver-vendor.js"></script>
<script src="resources/invoker-utils.js"></script>
-<details id="invokee">
- Details Contents
-</details>
+<details id="invokee">Details Contents</details>
<button id="invokerbutton" invoketarget="invokee"></button>
<script>
- // auto
-
- promise_test(async function (t) {
- assert_false(invokee.matches("[open]"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
- assert_true(invokee.matches("[open]"));
- }, "invoking closed details with auto action opens");
-
- promise_test(async function (t) {
- assert_false(invokee.matches("[open]"));
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
- });
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
- assert_false(invokee.matches("[open]"));
- }, "invoking closed details with auto action and preventDefault does not open");
-
- promise_test(async function (t) {
- invokee.setAttribute('open', '');
- assert_true(invokee.matches("[open]"));
- await clickOn(invokerbutton);
- assert_false(invokee.matches("[open]"));
- }, "invoking open details with auto action closes");
-
- promise_test(async function (t) {
- invokee.setAttribute('open', '');
- t.add_cleanup(() => invokee.removeAttribute('open'));
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
- });
- assert_true(invokee.matches("[open]"));
- await clickOn(invokerbutton);
- assert_true(invokee.matches("[open]"));
- }, "invoking open details with auto action and preventDefault does not close");
-
- promise_test(async function (t) {
- t.add_cleanup(() => invokee.removeAttribute('open'));
- invokee.addEventListener("invoke", (e) => {
- invokee.setAttribute('open', '');
- }, {
- once: true,
- });
- assert_false(invokee.matches("[open]"));
- await clickOn(invokerbutton);
- assert_false(invokee.matches("[open]"));
- }, "invoking details with auto action where event listener opens leads to a closed details");
-
- promise_test(async function (t) {
- invokee.setAttribute('open', '');
- t.add_cleanup(() => invokee.removeAttribute('open'));
- invokee.addEventListener("invoke", (e) => {
- invokee.removeAttribute('open');
- }, {
- once: true,
- });
- assert_true(invokee.matches("[open]"));
- await clickOn(invokerbutton);
- assert_true(invokee.matches("[open]"));
- }, "invoking open details with auto action where event listener closes leads to an open details");
-
- // toggle
-
- promise_test(async function (t) {
- assert_false(invokee.matches("[open]"));
- invokerbutton.setAttribute("invokeaction", "toggle");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
- assert_true(invokee.matches("[open]"));
- }, "invoking closed details with toggle action opens");
-
- promise_test(async function (t) {
- assert_false(invokee.matches("[open]"));
- invokerbutton.setAttribute("invokeaction", "tOgGlE");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
- assert_true(invokee.matches("[open]"));
- }, "invoking closed details with toggle (case-insensitive) action opens");
-
- promise_test(async function (t) {
- assert_false(invokee.matches("[open]"));
- invokerbutton.setAttribute("invokeaction", "toggle");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
+ function resetState() {
+ invokerbutton.removeAttribute("invokeaction");
+ invokee.removeAttribute("open");
+ }
+
+ // Open actions
+ [
+ null,
+ "",
+ "toggle",
+ "open",
+ /* test case sensitivity */
+ "tOgGlE",
+ "oPeN",
+ ].forEach((action) => {
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ if (action !== null) invokerbutton.invokeAction = action;
+ assert_false(invokee.matches("[open]"));
+ await clickOn(invokerbutton);
+ assert_true(invokee.matches("[open]"));
+ },
+ `invoking (as ${
+ action === null ? "auto" : action || "explicit empty"
+ }) closed details opens`,
+ );
+
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ if (action !== null) invokerbutton.invokeAction = action;
+ assert_false(invokee.matches("[open]"));
+ invokee.addEventListener("invoke", (e) => e.preventDefault(), {
+ once: true,
+ });
+ await clickOn(invokerbutton);
+ t.add_cleanup(() => invokee.removeAttribute("open"));
+ assert_false(invokee.matches("[open]"));
+ },
+ `invoking (as ${
+ action === null ? "auto" : action || "explicit empty"
+ }) closed details with preventDefault does not open`,
+ );
+ });
+
+ // Close actions
+ [
+ null,
+ "",
+ "toggle",
+ "close",
+ /* test case sensitivity */
+ "tOgGlE",
+ "cLoSe",
+ ].forEach((action) => {
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ if (action !== null) invokerbutton.invokeAction = action;
+ invokee.setAttribute("open", "");
+ assert_true(invokee.matches("[open]"));
+ await clickOn(invokerbutton);
+ assert_false(invokee.matches("[open]"));
+ },
+ `invoking (as ${
+ action === null ? "auto" : action || "explicit empty"
+ }) open details closes`,
+ );
+
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ if (action !== null) invokerbutton.invokeAction = action;
+ invokee.setAttribute("open", "");
+ invokerbutton.setAttribute("invokeaction", "toggle");
+ invokee.addEventListener("invoke", (e) => e.preventDefault(), {
+ once: true,
+ });
+ assert_true(invokee.matches("[open]"));
+ await clickOn(invokerbutton);
+ assert_true(invokee.matches("[open]"));
+ },
+ `invoking (as ${
+ action === null ? "auto" : action || "explicit empty"
+ }) open details with prevent default closes`,
+ );
+ });
+
+ // toggle specific
+
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ invokerbutton.invokeAction = "toggle";
+ invokee.addEventListener(
+ "invoke",
+ (e) => {
+ invokee.setAttribute("open", "");
+ },
+ {
once: true,
- });
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
+ },
+ );
assert_false(invokee.matches("[open]"));
- }, "invoking closed details with toggle action and preventDefault does not open");
-
- promise_test(async function (t) {
- invokee.setAttribute('open', '');
- invokerbutton.setAttribute("invokeaction", "toggle");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- assert_true(invokee.matches("[open]"));
await clickOn(invokerbutton);
assert_false(invokee.matches("[open]"));
- }, "invoking open details with toggle action closes");
+ }, "invoking (as toggle) closed details where event listener opens leads to a closed details");
- promise_test(async function (t) {
- invokee.setAttribute('open', '');
- t.add_cleanup(() => invokee.removeAttribute('open'));
- invokerbutton.setAttribute("invokeaction", "toggle");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
- });
- assert_true(invokee.matches("[open]"));
- await clickOn(invokerbutton);
- assert_true(invokee.matches("[open]"));
- }, "invoking open details with toggle action and preventDefault does not close");
-
- // open
-
- promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "open");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- assert_false(invokee.matches("[open]"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
- assert_true(invokee.matches("[open]"));
- }, "invoking closed details with open action opens");
-
- promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "oPeN");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- assert_false(invokee.matches("[open]"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
- assert_true(invokee.matches("[open]"));
- }, "invoking closed details with open (case insensitive) action opens");
+ // open specific
promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "open");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- invokee.setAttribute('open', '');
+ t.add_cleanup(resetState);
+ invokerbutton.invokeAction = "open";
+ invokee.setAttribute("open", "");
assert_true(invokee.matches("[open]"));
await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
assert_true(invokee.matches("[open]"));
}, "invoking open details with open action is noop");
- promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "open");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- assert_false(invokee.matches("[open]"));
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
- });
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
- assert_false(invokee.matches("[open]"));
- }, "invoking closed popover with open action and preventDefault does not open");
-
// close
promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "close");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
+ t.add_cleanup(resetState);
+ invokerbutton.invokeAction = "close";
assert_false(invokee.matches("[open]"));
await clickOn(invokerbutton);
assert_false(invokee.matches("[open]"));
}, "invoking closed details with close action is noop");
-
- promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "close");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- invokee.setAttribute('open', '');
- assert_true(invokee.matches("[open]"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
- assert_false(invokee.matches("[open]"));
- }, "invoking open details with close action closes");
-
- promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "cLoSe");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- invokee.setAttribute('open', '');
- assert_true(invokee.matches("[open]"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.removeAttribute('open'));
- assert_false(invokee.matches("[open]"));
- }, "invoking open details with close (case insensitive) action closes");
-
- promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "close");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- invokee.setAttribute('open', '');
- t.add_cleanup(() => invokee.removeAttribute('open'));
- assert_true(invokee.matches("[open]"));
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
- });
- await clickOn(invokerbutton);
- assert_true(invokee.matches("[open]"));
- }, "invoking open details with close action with preventDefault does not close");
</script>
diff --git a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-details-invalid-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-details-invalid-behavior.tentative.html
new file mode 100644
index 0000000000..d5e90af9c0
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-details-invalid-behavior.tentative.html
@@ -0,0 +1,49 @@
+<!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>
+
+<details id="invokee">Details Contents</details>
+<button id="invokerbutton" invoketarget="invokee"></button>
+
+<script>
+ function resetState() {
+ invokerbutton.removeAttribute("invokeaction");
+ invokee.removeAttribute("open");
+ }
+
+ // invalid actions on details
+ [
+ "foo-bar",
+ "showpopover",
+ "showmodal",
+ "showpicker",
+ "hidepopover",
+ "hide",
+ "toggleopen",
+ ].forEach((action) => {
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ invokerbutton.invokeAction = action;
+ assert_false(invokee.matches("[open]"));
+ await clickOn(invokerbutton);
+ assert_false(invokee.matches("[open]"));
+ }, `invoking (as ${action}) on details does nothing`);
+
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ invokerbutton.invokeAction = action;
+ invokee.setAttribute("open", "");
+ assert_true(invokee.matches("[open]"));
+ await clickOn(invokerbutton);
+ assert_true(invokee.matches("[open]"));
+ }, `invoking (as ${action}) on open details does nothing`);
+ });
+</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
index 774d308703..9f73e092b0 100644
--- 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
@@ -295,67 +295,6 @@
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) => {
diff --git a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-dialog-invalid-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-dialog-invalid-behavior.tentative.html
new file mode 100644
index 0000000000..af84c22594
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-dialog-invalid-behavior.tentative.html
@@ -0,0 +1,120 @@
+<!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");
+ }
+
+ // 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`,
+ );
+ });
+ });
+</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 2bddfa7621..f414559e55 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
@@ -1,6 +1,7 @@
<!doctype html>
<meta charset="utf-8" />
-<meta name="author" title="Keith Cirkel" href="mailto:keithamus@github.com" />
+<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>
@@ -19,215 +20,138 @@
promise_test(async function (t) {
assert_false(invokee.matches(":popover-open"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.hidePopover());
- assert_true(invokee.matches(":popover-open"));
- }, "invoking (as auto) closed popover opens");
-
- promise_test(async function (t) {
- assert_false(invokee.matches(":popover-open"));
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
+ invokee.addEventListener("invoke", (e) => { invokerbutton.setAttribute('invokeaction', 'hidepopover'); }, {
once: true,
});
await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.hidePopover());
- assert_false(invokee.matches(":popover-open"));
- }, "invoking (as auto) closed popover with preventDefault does not open");
-
- promise_test(async function (t) {
- invokee.showPopover();
- assert_true(invokee.matches(":popover-open"));
- await clickOn(invokerbutton);
- assert_false(invokee.matches(":popover-open"));
- }, "invoking (as auto) open popover closes");
-
- promise_test(async function (t) {
- invokee.showPopover();
- assert_true(invokee.matches(":popover-open"));
- await clickOn(containedinvoker);
- assert_false(invokee.matches(":popover-open"));
- }, "invoking (as auto) from within open popover closes");
-
- promise_test(async function (t) {
- invokee.showPopover();
- t.add_cleanup(() => invokee.hidePopover());
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
+ t.add_cleanup(() => {
+ invokee.hidePopover();
+ invokerbutton.removeAttribute("invokeaction");
});
assert_true(invokee.matches(":popover-open"));
- await clickOn(containedinvoker);
- assert_true(invokee.matches(":popover-open"));
- }, "invoking (as auto) open popover with preventDefault does not close");
-
- // togglepopover
-
- promise_test(async function (t) {
- assert_false(invokee.matches(":popover-open"));
- invokerbutton.setAttribute("invokeaction", "togglepopover");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.hidePopover());
- assert_true(invokee.matches(":popover-open"));
- }, "invoking (as togglepopover) closed popover opens");
-
- promise_test(async function (t) {
- assert_false(invokee.matches(":popover-open"));
- invokerbutton.setAttribute("invokeaction", "tOgGlEpOpOvEr");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.hidePopover());
- assert_true(invokee.matches(":popover-open"));
- }, "invoking (as togglepopover - case insensitive) closed popover opens");
-
- promise_test(async function (t) {
- assert_false(invokee.matches(":popover-open"));
- invokerbutton.setAttribute("invokeaction", "togglepopover");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
- });
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.hidePopover());
- assert_false(invokee.matches(":popover-open"));
- }, "invoking (as togglepopover) closed popover with preventDefault does not open");
-
- promise_test(async function (t) {
- invokee.showPopover();
- 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"));
- }, "invoking (as togglepopover) open popover closes");
-
- promise_test(async function (t) {
- invokee.showPopover();
- containedinvoker.setAttribute("invokeaction", "togglepopover");
- t.add_cleanup(() => containedinvoker.removeAttribute("invokeaction"));
- assert_true(invokee.matches(":popover-open"));
- 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());
- 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(containedinvoker);
- assert_true(invokee.matches(":popover-open"));
- }, "invoking (as togglepopover) open popover with preventDefault does not close");
-
- // showpopover
-
- promise_test(async function (t) {
+ }, "changing invokeaction attribute inside invokeevent doesn't impact the invocation");
+
+ function resetState() {
+ invokerbutton.removeAttribute("invokeaction");
+ containedinvoker.removeAttribute("invokeaction");
+ try {
+ invokee.hidePopover();
+ } catch {}
+ invokee.setAttribute("popover", "");
+ }
+
+ // Open actions
+ [
+ null,
+ "",
+ "togglepopover",
+ "showpopover",
+ /* test case sensitivity */
+ "tOgGlEpOpOvEr",
+ "sHoWpOpOvEr",
+ ].forEach((action) => {
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ if (action !== null) invokerbutton.invokeAction = action;
+ assert_false(invokee.matches(":popover-open"));
+ await clickOn(invokerbutton);
+ assert_true(invokee.matches(":popover-open"));
+ },
+ `invoking (as ${
+ action === null ? "auto" : action || "explicit empty"
+ }) closed popover opens`,
+ );
+
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ if (action !== null) invokerbutton.invokeAction = action;
+ assert_false(invokee.matches(":popover-open"));
+ invokee.addEventListener("invoke", (e) => e.preventDefault(), {
+ once: true,
+ });
+ await clickOn(invokerbutton);
+ assert_false(invokee.matches(":popover-open"));
+ },
+ `invoking (as ${
+ action === null ? "auto" : action || "explicit empty"
+ }) closed popover with preventDefault does not open`,
+ );
+ });
+
+ // Close actions
+ [
+ null,
+ "",
+ "togglepopover",
+ "hidepopover",
+ /* test case sensitivity */
+ "tOgGlEpOpOvEr",
+ "hIdEpOpOvEr",
+ ].forEach((action) => {
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ if (action !== null) invokerbutton.invokeAction = action;
+ invokee.showPopover();
+ assert_true(invokee.matches(":popover-open"));
+ await clickOn(invokerbutton);
+ assert_false(invokee.matches(":popover-open"));
+ },
+ `invoking (as ${
+ action === null ? "auto" : action || "explicit empty"
+ }) open popover closes`,
+ );
+
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ if (action !== null) containedinvoker.invokeAction = action;
+ invokee.showPopover();
+ assert_true(invokee.matches(":popover-open"));
+ await clickOn(containedinvoker);
+ assert_false(invokee.matches(":popover-open"));
+ },
+ `invoking (as ${
+ action === null ? "auto" : action || "explicit empty"
+ }) from within open popover closes`,
+ );
+
+ promise_test(
+ async function (t) {
+ t.add_cleanup(resetState);
+ if (action !== null) invcontainedinvokervokeaction = action;
+ invokee.showPopover();
+ invokee.addEventListener("invoke", (e) => e.preventDefault(), {
+ once: true,
+ });
+ assert_true(invokee.matches(":popover-open"));
+ await clickOn(containedinvoker);
+ assert_true(invokee.matches(":popover-open"));
+ },
+ `invoking (as ${
+ action === null ? "auto" : action || "explicit empty"
+ }) open popover with preventDefault does not close`,
+ );
+ });
+
+ // showpopover specific
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
invokerbutton.setAttribute("invokeaction", "showpopover");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- assert_false(invokee.matches(":popover-open"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.hidePopover());
- assert_true(invokee.matches(":popover-open"));
- }, "invoking (as showpopover) closed popover opens");
-
- promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "sHoWpOpOvEr");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- assert_false(invokee.matches(":popover-open"));
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.hidePopover());
- assert_true(invokee.matches(":popover-open"));
- }, "invoking (as showpopover - case insensitive) closed popover opens");
-
- promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "showpopover");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
invokee.showPopover();
assert_true(invokee.matches(":popover-open"));
await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.hidePopover());
assert_true(invokee.matches(":popover-open"));
}, "invoking (as showpopover) open popover is noop");
+ // hidepopover specific
promise_test(async function (t) {
- invokerbutton.setAttribute("invokeaction", "showpopover");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
- assert_false(invokee.matches(":popover-open"));
- invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
- });
- await clickOn(invokerbutton);
- t.add_cleanup(() => invokee.hidePopover());
- assert_false(invokee.matches(":popover-open"));
- }, "invoking (as showpopover) closed popover with preventDefault does not open");
-
- // hidepopover
-
- promise_test(async function (t) {
+ t.add_cleanup(resetState);
invokerbutton.setAttribute("invokeaction", "hidepopover");
- t.add_cleanup(() => invokerbutton.removeAttribute("invokeaction"));
assert_false(invokee.matches(":popover-open"));
await clickOn(invokerbutton);
assert_false(invokee.matches(":popover-open"));
}, "invoking (as hidepopover) closed popover is noop");
-
- promise_test(async function (t) {
- containedinvoker.setAttribute("invokeaction", "hidepopover");
- t.add_cleanup(() => containedinvoker.removeAttribute("invokeaction"));
- invokee.showPopover();
- assert_true(invokee.matches(":popover-open"));
- 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) {
- containedinvoker.setAttribute("invokeaction", "hIdEpOpOvEr");
- t.add_cleanup(() => containedinvoker.removeAttribute("invokeaction"));
- invokee.showPopover();
- assert_true(invokee.matches(":popover-open"));
- 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) {
- 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(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/invoketarget-on-popover-invalid-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-popover-invalid-behavior.tentative.html
new file mode 100644
index 0000000000..755f3a6777
--- /dev/null
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-popover-invalid-behavior.tentative.html
@@ -0,0 +1,47 @@
+<!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>
+
+<div id="invokee" popover>
+ <button id="containedinvoker" invoketarget="invokee"></button>
+</div>
+<button id="invokerbutton" invoketarget="invokee"></button>
+
+<script>
+ function resetState() {
+ invokerbutton.removeAttribute("invokeaction");
+ containedinvoker.removeAttribute("invokeaction");
+ try {
+ invokee.hidePopover();
+ } catch {}
+ invokee.setAttribute("popover", "");
+ }
+
+ // invalid actions on showpopover
+ ["foo-bar", "showmodal", "showpicker", "open", "close"].forEach((action) => {
+ promise_test(async function (t) {
+ t.add_cleanup(resetState);
+ invokerbutton.invokeAction = action;
+ 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) {
+ t.add_cleanup(resetState);
+ invokerbutton.invokeAction = action;
+ 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/invoketarget-on-video-behavior.tentative.html b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-video-behavior.tentative.html
index 5bbcd83e72..d15d6f9584 100644
--- a/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-video-behavior.tentative.html
+++ b/testing/web-platform/tests/html/semantics/invokers/invoketarget-on-video-behavior.tentative.html
@@ -1,6 +1,7 @@
<!doctype html>
<meta charset="utf-8" />
<meta name="author" title="Luke Warlow" href="mailto:luke@warlow.dev" />
+<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>
@@ -25,7 +26,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -43,7 +44,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "playpause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.paused);
@@ -62,7 +63,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "playpause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -75,12 +76,12 @@
invokee.currentTime = 0;
invokee.muted = false;
});
- await test_driver.bless('play video');
+ await test_driver.bless("play video");
invokee.play();
assert_false(invokee.paused);
invokerbutton.setAttribute("invokeaction", "playpause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -98,7 +99,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "play");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.paused);
@@ -112,12 +113,12 @@
invokee.muted = false;
});
invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
+ once: true,
});
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "play");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -130,12 +131,12 @@
invokee.currentTime = 0;
invokee.muted = false;
});
- await test_driver.bless('play video');
+ await test_driver.bless("play video");
invokee.play();
assert_false(invokee.paused);
invokerbutton.setAttribute("invokeaction", "play");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.paused);
@@ -153,7 +154,7 @@
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "pause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -167,12 +168,12 @@
invokee.muted = false;
});
invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
+ once: true,
});
assert_true(invokee.paused);
invokerbutton.setAttribute("invokeaction", "pause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -185,12 +186,12 @@
invokee.currentTime = 0;
invokee.muted = false;
});
- await test_driver.bless('play video');
+ await test_driver.bless("play video");
invokee.play();
assert_false(invokee.paused);
invokerbutton.setAttribute("invokeaction", "pause");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.paused);
@@ -208,7 +209,7 @@
assert_false(invokee.muted);
invokerbutton.setAttribute("invokeaction", "toggleMuted");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_true(invokee.muted);
@@ -222,12 +223,12 @@
invokee.muted = false;
});
invokee.addEventListener("invoke", (e) => e.preventDefault(), {
- once: true,
+ once: true,
});
assert_false(invokee.muted);
invokerbutton.setAttribute("invokeaction", "toggleMuted");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.muted);
@@ -244,10 +245,9 @@
assert_true(invokee.muted);
invokerbutton.setAttribute("invokeaction", "toggleMuted");
await clickOn(invokerbutton);
- await new Promise(resolve => {
+ await new Promise((resolve) => {
requestAnimationFrame(resolve);
});
assert_false(invokee.muted);
}, "invoking muted video with toggleMuted action unmutes it");
-
</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 8420f24b6f..4261f9c0d3 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
@@ -14,3 +14,14 @@ async function clickOn(element) {
.send();
await waitForRender();
}
+async function hoverOver(element) {
+ await waitForRender();
+ 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), {})
+ .send();
+ await waitForRender();
+}