math-global-event-handlers.tentative.html (5810B)
1 <!DOCTYPE html> 2 <title>MathMLElement GlobalEventHandlers</title> 3 <link rel="author" title="Brian Kardell" href="mailto:bkardell@igalia.com" /> 4 <link rel="help" href="https://w3c.github.io/mathml-core/#dom-and-javascript"/> 5 <link rel="help" href="https://html.spec.whatwg.org/multipage/#event-handler-idl-attributes"/> 6 <link rel="help" href="https://html.spec.whatwg.org/multipage/#event-handler-content-attributes"/> 7 <meta name="timeout" content="long"> 8 <script src="/resources/testharness.js"></script> 9 <script src="/resources/testharnessreport.js"></script> 10 <script src="/resources/WebIDLParser.js"></script> 11 12 <script> 13 "use strict"; 14 15 // The prefixed animation events are special; their event types are 16 // camel-case. 17 const prefixedAnimationAttributeToEventType = new Map([ 18 ["webkitanimationend", "webkitAnimationEnd"], 19 ["webkitanimationiteration", "webkitAnimationIteration"], 20 ["webkitanimationstart", "webkitAnimationStart"], 21 ["webkittransitionend", "webkitTransitionEnd"], 22 ]); 23 24 // basic pattern lifted from /html/webappapis/scripting/events/event-handler-all-global-events.html 25 promise_setup(async function() { 26 const res = await fetch("/interfaces/html.idl"); 27 const htmlIDL = await res.text(); 28 // Parsing the whole IDL file is slow, so use a small regexp to extract only 29 // the part that is relevant for this test. 30 const parsedHTMLIDL = WebIDL2.parse(htmlIDL. 31 match(/^interface mixin GlobalEventHandlers {[^{}]*};$/m)[0]); 32 const globalEventHandlers = parsedHTMLIDL.find( 33 idl => idl.name === "GlobalEventHandlers" 34 ); 35 36 // onerror is too special 37 const names = globalEventHandlers.members 38 .map(member => member.name) 39 .filter(name => name !== "onerror"); 40 41 for (const name of names) { 42 const withoutOn = name.substring(2); 43 44 promise_test(async () => { 45 const location = MathMLElement.prototype; 46 assert_true( 47 location.hasOwnProperty(name), 48 `${location.constructor.name} has an own property named "${name}"` 49 ); 50 51 assert_false( 52 name in Element.prototype, 53 `Element.prototype must not contain a "${name}" property` 54 ); 55 }, `${name}: must be on the appropriate locations for GlobalEventHandlers`); 56 57 promise_test(async () => { 58 const location = document.createElementNS( 59 "http://www.w3.org/1998/Math/MathML", 60 "math" 61 ); 62 63 assert_equals( 64 location[name], 65 null, 66 `The default value of the property is null for a ${ 67 location.constructor.name 68 } instance` 69 ); 70 }, `${name}: the default value must be null`); 71 72 promise_test(async () => { 73 const div = document.createElement("div"); 74 div.insertAdjacentHTML("beforeend", `<math ${name}="window.${name}Happened1 = true;"></math>`); 75 const compiledHandler = div.firstElementChild[name]; 76 assert_equals( 77 typeof compiledHandler, 78 "function", 79 `The ${name} property must be a function` 80 ); 81 compiledHandler(); 82 assert_true( 83 window[`${name}Happened1`], 84 "Calling the handler must run the code" 85 ); 86 }, `${name}: the content attribute must be compiled into a function as the corresponding property`); 87 88 promise_test(async () => { 89 const el = document.createElementNS( 90 "http://www.w3.org/1998/Math/MathML", 91 "math" 92 ); 93 assert_equals(el[name], null, `The ${name} property must be null (no attribute)`); 94 95 el.setAttribute(name, `window.${name}Happened2 = true;`); 96 const compiledHandler = el[name]; 97 assert_equals( 98 typeof compiledHandler, 99 "function", 100 `The ${name} property must be a function (set attribute)` 101 ); 102 compiledHandler(); 103 assert_true( 104 window[`${name}Happened2`], 105 "Calling the handler must run the code (set attribute)" 106 ); 107 108 window[`${name}Happened2`] = false; 109 const clonedEl = el.cloneNode(true); 110 const clonedCompiledHandler = clonedEl[name]; 111 assert_equals( 112 typeof clonedCompiledHandler, 113 "function", 114 `The ${name} property must be a function (clone node)` 115 ); 116 clonedCompiledHandler(); 117 assert_true( 118 window[`${name}Happened2`], 119 "Calling the handler must run the code (clone node)" 120 ); 121 122 el.setAttribute(name, `window.${name}Happened3 = true;`); 123 const newCompiledHandler = el[name]; 124 assert_equals( 125 typeof newCompiledHandler, 126 "function", 127 `The ${name} property must be a function (modify attribute)` 128 ); 129 newCompiledHandler(); 130 assert_true( 131 window[`${name}Happened3`], 132 "Calling the handler must run the code (modify attribute)" 133 ); 134 135 el.removeAttribute(name); 136 assert_equals(el[name], null, `The ${name} property must be null (remove attribute)`); 137 }, `${name}: dynamic changes on the attribute`); 138 139 promise_test(async () => { 140 const element = document.createElementNS( 141 "http://www.w3.org/1998/Math/MathML", 142 "math" 143 ); 144 let target = undefined; 145 element[name] = (e) => { target = e.currentTarget; } 146 let eventType = withoutOn; 147 if (prefixedAnimationAttributeToEventType.has(eventType)) { 148 eventType = prefixedAnimationAttributeToEventType.get(eventType); 149 } 150 element.dispatchEvent(new Event(eventType)); 151 assert_equals(target, element, "The event must be fired at the <math> element"); 152 }, `${name}: dispatching an Event at a <math> element must trigger element.${name}`); 153 } 154 }); 155 </script>