diff options
Diffstat (limited to 'testing/web-platform/tests/html/semantics/invokers')
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(); +} |