event-propagate-disabled-keyboard.tentative.html (4478B)
1 <!DOCTYPE html> 2 <meta charset="utf-8"> 3 <title>KeyboardEvent propagation on disabled form elements</title> 4 <link rel="author" href="mailto:avandolder@mozilla.com"> 5 <script src="/resources/testharness.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <script src="/resources/testdriver.js"></script> 8 <script src="/resources/testdriver-vendor.js"></script> 9 <script src="/resources/testdriver-actions.js"></script> 10 <script> 11 class CustomControl extends HTMLElement { 12 static get formAssociated() {return true;} 13 14 constructor() { 15 super(); 16 this.internals = this.attachInternals(); 17 18 this.attachShadow({mode: "open", delegatesFocus: true}); 19 this.shadowRoot.append( 20 document.querySelector("template").content.cloneNode(true) 21 ); 22 } 23 24 get target() { 25 return this.shadowRoot.getElementById("target"); 26 } 27 } 28 29 customElements.define("custom-control", CustomControl) 30 </script> 31 32 <template> 33 <div tabindex="0" id="target"> 34 <slot></slot> 35 </div> 36 </template> 37 38 <div tabindex="0" id="reset"></div> 39 40 <form id="form"> 41 <input> <!-- Sanity check with non-disabled control --> 42 <select disabled></select> 43 <textarea disabled></textarea> 44 <input disabled type="button"> 45 <input disabled type="checkbox"> 46 <input disabled type="color" value="#000000"> 47 <input disabled type="date"> 48 <input disabled type="datetime-local"> 49 <input disabled type="email"> 50 <input disabled type="file"> 51 <input disabled type="image"> 52 <input disabled type="month"> 53 <input disabled type="number"> 54 <input disabled type="password"> 55 <input disabled type="radio"> 56 <input disabled type="range" value="0"> 57 <input disabled type="reset"> 58 <input disabled type="search"> 59 <input disabled type="submit"> 60 <input disabled type="tel"> 61 <input disabled type="text"> 62 <input disabled type="time"> 63 <input disabled type="url"> 64 <input disabled type="week"> 65 66 <fieldset disabled><span tabindex="0">Span</span></fieldset> 67 <button disabled><span tabindex="0">Span</span></button> 68 <custom-control disabled>Text</custom-control> 69 </form> 70 71 <script> 72 const keyEvents = ["keydown", "keyup"]; 73 74 function setupTest(t, element, observingElement) { 75 const observedEvents = []; 76 const controller = new AbortController(); 77 const {signal} = controller; 78 const listenerFn = t.step_func(event => { 79 observedEvents.push(event.type); 80 }); 81 for (const event of keyEvents) { 82 observingElement.addEventListener(event, listenerFn, {signal}); 83 } 84 t.add_cleanup(() => controller.abort()); 85 86 const target = element; 87 return {target, observedEvents}; 88 } 89 90 function fire_trusted_key_events(target) { 91 const actions = new test_driver.Actions(); 92 return actions.keyDown("a").keyUp("a").send(); 93 } 94 95 function fire_untrusted_key_events(target) { 96 target.dispatchEvent(new KeyboardEvent("keydown", {bubbles: true})); 97 target.dispatchEvent(new KeyboardEvent("keyup", {bubbles: true})); 98 } 99 100 const observingElement = document.getElementById("form"); 101 const reset = document.getElementById("reset"); 102 103 for (const element of observingElement.children) { 104 promise_test(async t => { 105 const {observedEvents} = setupTest(t, element, observingElement); 106 107 const target = element.firstElementChild ?? element.target ?? element; 108 await t.step_func(fire_untrusted_key_events)(target); 109 await new Promise(resolve => t.step_timeout(resolve, 0)); 110 111 assert_array_equals(observedEvents, keyEvents, "Observed events"); 112 }, `Untrusted key events on ${element.outerHTML}, observed from <${observingElement.localName}>`); 113 114 // Only test elements with children for trusted key events. 115 if (!element.firstElementChild && !element.target) { 116 continue; 117 } 118 119 promise_test(async t => { 120 const {observedEvents} = setupTest(t, element, observingElement); 121 122 const target = element.firstElementChild ?? element.target; 123 124 reset.focus(); 125 assert_not_equals(document.activeElement, target, "Reset current focus"); 126 target.focus(); 127 assert_equals(document.activeElement, element.firstElementChild ?? element, "Focus the target element"); 128 129 await t.step_func(fire_trusted_key_events)(target); 130 await new Promise(resolve => t.step_timeout(resolve, 0)); 131 132 assert_array_equals(observedEvents, keyEvents, "Observed events"); 133 }, `Trusted key events on ${element.outerHTML}, observed from <${observingElement.localName}>`); 134 } 135 </script>