summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/dom/events/Event-dispatch-on-disabled-elements.html
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/dom/events/Event-dispatch-on-disabled-elements.html')
-rw-r--r--testing/web-platform/tests/dom/events/Event-dispatch-on-disabled-elements.html251
1 files changed, 251 insertions, 0 deletions
diff --git a/testing/web-platform/tests/dom/events/Event-dispatch-on-disabled-elements.html b/testing/web-platform/tests/dom/events/Event-dispatch-on-disabled-elements.html
new file mode 100644
index 0000000000..e7d6b455bb
--- /dev/null
+++ b/testing/web-platform/tests/dom/events/Event-dispatch-on-disabled-elements.html
@@ -0,0 +1,251 @@
+<!doctype html>
+<meta charset="utf8">
+<meta name="timeout" content="long">
+<title>Events must dispatch on disabled elements</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+<style>
+ @keyframes fade {
+ 0% {
+ opacity: 1;
+ }
+ 100% {
+ opacity: 0;
+ }
+ }
+</style>
+<body>
+<script>
+// HTML elements that can be disabled
+const formElements = ["button", "input", "select", "textarea"];
+
+test(() => {
+ for (const localName of formElements) {
+ const elem = document.createElement(localName);
+ elem.disabled = true;
+ // pass becomes true if the event is called and it's the right type.
+ let pass = false;
+ const listener = ({ type }) => {
+ pass = type === "click";
+ };
+ elem.addEventListener("click", listener, { once: true });
+ elem.dispatchEvent(new Event("click"));
+ assert_true(
+ pass,
+ `Untrusted "click" Event didn't dispatch on ${elem.constructor.name}.`
+ );
+ }
+}, "Can dispatch untrusted 'click' Events at disabled HTML elements.");
+
+test(() => {
+ for (const localName of formElements) {
+ const elem = document.createElement(localName);
+ elem.disabled = true;
+ // pass becomes true if the event is called and it's the right type.
+ let pass = false;
+ const listener = ({ type }) => {
+ pass = type === "pass";
+ };
+ elem.addEventListener("pass", listener, { once: true });
+ elem.dispatchEvent(new Event("pass"));
+ assert_true(
+ pass,
+ `Untrusted "pass" Event didn't dispatch on ${elem.constructor.name}`
+ );
+ }
+}, "Can dispatch untrusted Events at disabled HTML elements.");
+
+test(() => {
+ for (const localName of formElements) {
+ const elem = document.createElement(localName);
+ elem.disabled = true;
+ // pass becomes true if the event is called and it's the right type.
+ let pass = false;
+ const listener = ({ type }) => {
+ pass = type === "custom-pass";
+ };
+ elem.addEventListener("custom-pass", listener, { once: true });
+ elem.dispatchEvent(new CustomEvent("custom-pass"));
+ assert_true(
+ pass,
+ `CustomEvent "custom-pass" didn't dispatch on ${elem.constructor.name}`
+ );
+ }
+}, "Can dispatch CustomEvents at disabled HTML elements.");
+
+test(() => {
+ for (const localName of formElements) {
+ const elem = document.createElement(localName);
+
+ // Element is disabled... so this click() MUST NOT fire an event.
+ elem.disabled = true;
+ let pass = true;
+ elem.onclick = e => {
+ pass = false;
+ };
+ elem.click();
+ assert_true(
+ pass,
+ `.click() must not dispatch "click" event on disabled ${
+ elem.constructor.name
+ }.`
+ );
+
+ // Element is (re)enabled... so this click() fires an event.
+ elem.disabled = false;
+ pass = false;
+ elem.onclick = e => {
+ pass = true;
+ };
+ elem.click();
+ assert_true(
+ pass,
+ `.click() must dispatch "click" event on enabled ${
+ elem.constructor.name
+ }.`
+ );
+ }
+}, "Calling click() on disabled elements must not dispatch events.");
+
+promise_test(async () => {
+ // For each form element type, set up transition event handlers.
+ for (const localName of formElements) {
+ const elem = document.createElement(localName);
+ elem.disabled = true;
+ document.body.appendChild(elem);
+ const eventPromises = [
+ "transitionrun",
+ "transitionstart",
+ "transitionend",
+ ].map(eventType => {
+ return new Promise(r => {
+ elem.addEventListener(eventType, r);
+ });
+ });
+ // Flushing style triggers transition.
+ getComputedStyle(elem).opacity;
+ elem.style.transition = "opacity .1s";
+ elem.style.opacity = 0;
+ getComputedStyle(elem).opacity;
+ // All the events fire...
+ await Promise.all(eventPromises);
+ elem.remove();
+ }
+}, "CSS Transitions transitionrun, transitionstart, transitionend events fire on disabled form elements");
+
+promise_test(async () => {
+ // For each form element type, set up transition event handlers.
+ for (const localName of formElements) {
+ const elem = document.createElement(localName);
+ elem.disabled = true;
+ document.body.appendChild(elem);
+ getComputedStyle(elem).opacity;
+ elem.style.transition = "opacity 100s";
+ // We use ontransitionstart to cancel the event.
+ elem.ontransitionstart = () => {
+ elem.style.display = "none";
+ };
+ const promiseToCancel = new Promise(r => {
+ elem.ontransitioncancel = r;
+ });
+ // Flushing style triggers the transition.
+ elem.style.opacity = 0;
+ getComputedStyle(elem).opacity;
+ await promiseToCancel;
+ // And we are done with this element.
+ elem.remove();
+ }
+}, "CSS Transitions transitioncancel event fires on disabled form elements");
+
+promise_test(async () => {
+ // For each form element type, set up transition event handlers.
+ for (const localName of formElements) {
+ const elem = document.createElement(localName);
+ document.body.appendChild(elem);
+ elem.disabled = true;
+ const animationStartPromise = new Promise(r => {
+ elem.addEventListener("animationstart", () => {
+ // Seek to the second iteration to trigger the animationiteration event
+ elem.style.animationDelay = "-100s"
+ r();
+ });
+ });
+ const animationIterationPromise = new Promise(r => {
+ elem.addEventListener("animationiteration", ()=>{
+ elem.style.animationDelay = "-200s"
+ r();
+ });
+ });
+ const animationEndPromise = new Promise(r => {
+ elem.addEventListener("animationend", r);
+ });
+ elem.style.animation = "fade 100s 2";
+ elem.classList.add("animate");
+ // All the events fire...
+ await Promise.all([
+ animationStartPromise,
+ animationIterationPromise,
+ animationEndPromise,
+ ]);
+ elem.remove();
+ }
+}, "CSS Animation animationstart, animationiteration, animationend fire on disabled form elements");
+
+promise_test(async () => {
+ // For each form element type, set up transition event handlers.
+ for (const localName of formElements) {
+ const elem = document.createElement(localName);
+ document.body.appendChild(elem);
+ elem.disabled = true;
+
+ const promiseToCancel = new Promise(r => {
+ elem.addEventListener("animationcancel", r);
+ });
+
+ elem.addEventListener("animationstart", () => {
+ // Cancel the animation by hiding it.
+ elem.style.display = "none";
+ });
+
+ // Trigger the animation
+ elem.style.animation = "fade 100s";
+ elem.classList.add("animate");
+ await promiseToCancel;
+ // And we are done with this element.
+ elem.remove();
+ }
+}, "CSS Animation's animationcancel event fires on disabled form elements");
+
+promise_test(async () => {
+ for (const localName of formElements) {
+ const elem = document.createElement(localName);
+ elem.disabled = true;
+ document.body.appendChild(elem);
+ // Element is disabled, so clicking must not fire events
+ let pass = true;
+ elem.onclick = e => {
+ pass = false;
+ };
+ // Disabled elements are not clickable.
+ await test_driver.click(elem);
+ assert_true(
+ pass,
+ `${elem.constructor.name} is disabled, so onclick must not fire.`
+ );
+ // Element is (re)enabled... so this click() will fire an event.
+ pass = false;
+ elem.disabled = false;
+ elem.onclick = () => {
+ pass = true;
+ };
+ await test_driver.click(elem);
+ assert_true(
+ pass,
+ `${elem.constructor.name} is enabled, so onclick must fire.`
+ );
+ elem.remove();
+ }
+}, "Real clicks on disabled elements must not dispatch events.");
+</script>