test_bug448602.html (9633B)
1 <!DOCTYPE HTML> 2 <html> 3 <!-- 4 https://bugzilla.mozilla.org/show_bug.cgi?id=448602 5 --> 6 <head> 7 <title>Test for Bug 448602</title> 8 <script src="/tests/SimpleTest/SimpleTest.js"></script> 9 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> 10 </head> 11 <body> 12 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=448602">Mozilla Bug 448602</a> 13 <p id="display"></p> 14 <div id="content" style="display: none"> 15 16 </div> 17 <pre id="test"> 18 <script type="application/javascript"> 19 20 /** Test for Bug 448602 */ 21 22 var els, root, l2, l3; 23 24 var handlerCalled = false; 25 var capturingListenerCalled = false; 26 var bubblingListenerCalled = false; 27 28 function clearListenerStates() { 29 handlerCalled = false; 30 capturingListenerCalled = false; 31 bubblingListenerCalled = false; 32 } 33 34 function runTests() { 35 els = SpecialPowers.Cc["@mozilla.org/eventlistenerservice;1"] 36 .getService(SpecialPowers.Ci.nsIEventListenerService); 37 38 // Event listener info tests 39 root = document.getElementById("testroot"); 40 var infos = els.getListenerInfoFor(root); 41 is(infos.length, 0, "Element shouldn't have listeners (1)"); 42 43 var listenerSource = 'handlerCalled = true;'; 44 root.setAttribute("onclick", listenerSource); 45 infos = els.getListenerInfoFor(root); 46 is(infos.length, 1, "Element should have listeners (1)"); 47 is(infos[0].toSource(), 'function onclick(event) {\n' + listenerSource + '\n}', 48 "Unexpected serialization (1)"); 49 is(infos[0].type, "click", "Wrong type (1)"); 50 is(infos[0].capturing, false, "Wrong phase (1)"); 51 is(infos[0].allowsUntrusted, true, "Should allow untrusted events (1)"); 52 is(SpecialPowers.unwrap(infos[0].listenerObject), root.onclick, 53 "Should have the right listener object (1)"); 54 55 // Test disabling and enabling the listener. 56 ok(!handlerCalled); 57 root.click(); 58 ok(handlerCalled); 59 60 clearListenerStates() 61 infos[0].enabled = false; 62 root.click(); 63 ok(!handlerCalled); 64 65 clearListenerStates() 66 infos[0].enabled = true; 67 root.click(); 68 ok(handlerCalled); 69 clearListenerStates(); 70 71 function capturingListener() { 72 capturingListenerCalled = true; 73 } 74 function bubblingListener() { 75 bubblingListenerCalled = true; 76 } 77 root.addEventListener("click", capturingListener, true); 78 root.addEventListener("click", bubblingListener); 79 root.addEventListener("fooevent", capturingListener, true); 80 root.addEventListener("fooevent", bubblingListener); 81 82 // We now have both "click" and "fooevent" listeners. 83 // Get the new set of listener infos, because we'll want to flip certain 84 // "click" event listeners on and off in the tests below. 85 // The order of event types is not guaranteed by getListenerInfoFor; but the 86 // order of listeners for a single event is guaranteed. So we filter the infos 87 // by event type. 88 const combinedListenerInfos = [...els.getListenerInfoFor(root)]; 89 const clickInfos = combinedListenerInfos.filter((info) => info.type == "click"); 90 91 // Use a child node to dispatch events so that both capturing and bubbling 92 // listeners get called. 93 l2 = document.getElementById("testlevel2"); 94 l2.click(); 95 ok(handlerCalled); 96 ok(capturingListenerCalled); 97 ok(bubblingListenerCalled); 98 clearListenerStates(); 99 100 clickInfos[0].enabled = false; 101 l2.click(); 102 ok(!handlerCalled); 103 ok(capturingListenerCalled); 104 ok(bubblingListenerCalled); 105 clearListenerStates(); 106 clickInfos[0].enabled = true; 107 108 clickInfos[1].enabled = false; 109 l2.click(); 110 ok(handlerCalled); 111 ok(!capturingListenerCalled); 112 ok(bubblingListenerCalled); 113 clearListenerStates(); 114 clickInfos[1].enabled = true; 115 116 clickInfos[2].enabled = false; 117 l2.click(); 118 ok(handlerCalled); 119 ok(capturingListenerCalled); 120 ok(!bubblingListenerCalled); 121 clearListenerStates(); 122 clickInfos[2].enabled = true; 123 124 root.removeEventListener("click", capturingListener, true); 125 root.removeEventListener("click", bubblingListener); 126 root.removeEventListener("fooevent", capturingListener, true); 127 root.removeEventListener("fooevent", bubblingListener); 128 root.removeAttribute("onclick"); 129 130 root.setAttribute("onclick", "...invalid script..."); 131 SimpleTest.expectUncaughtException(true); 132 infos = els.getListenerInfoFor(root); 133 SimpleTest.expectUncaughtException(false); 134 is(infos.length, 1); 135 is(infos[0].listenerObject, null); 136 137 root.removeAttribute("onclick"); 138 infos = els.getListenerInfoFor(root); 139 is(infos.length, 0, "Element shouldn't have listeners (2)"); 140 141 var l = function (e) { alert(e); }; 142 root.addEventListener("foo", l, true, true); 143 root.addEventListener("foo", l, false, false); 144 infos = els.getListenerInfoFor(root); 145 is(infos.length, 2, "Element should have listeners (2)"); 146 is(infos[0].toSource(), "(function (e) { alert(e); })", 147 "Unexpected serialization (2)"); 148 is(infos[0].type, "foo", "Wrong type (2)"); 149 is(infos[0].capturing, true, "Wrong phase (2)"); 150 is(infos[0].allowsUntrusted, true, "Should allow untrusted events (2)"); 151 is(SpecialPowers.unwrap(infos[0].listenerObject), l, 152 "Should have the right listener object (2)"); 153 is(infos[1].toSource(), "(function (e) { alert(e); })", 154 "Unexpected serialization (3)"); 155 is(infos[1].type, "foo", "Wrong type (3)"); 156 is(infos[1].capturing, false, "Wrong phase (3)"); 157 is(infos[1].allowsUntrusted, false, "Shouldn't allow untrusted events (1)"); 158 is(SpecialPowers.unwrap(infos[1].listenerObject), l, 159 "Should have the right listener object (3)"); 160 161 root.removeEventListener("foo", l, true); 162 root.removeEventListener("foo", l); 163 infos = els.getListenerInfoFor(root); 164 is(infos.length, 0, "Element shouldn't have listeners (3)"); 165 166 root.onclick = l; 167 infos = els.getListenerInfoFor(root); 168 is(infos.length, 1, "Element should have listeners (3)"); 169 is(infos[0].toSource(), '(function (e) { alert(e); })', 170 "Unexpected serialization (4)"); 171 is(infos[0].type, "click", "Wrong type (4)"); 172 is(infos[0].capturing, false, "Wrong phase (4)"); 173 is(infos[0].allowsUntrusted, true, "Should allow untrusted events (3)"); 174 is(SpecialPowers.unwrap(infos[0].listenerObject), l, 175 "Should have the right listener object (4)"); 176 177 l3 = document.getElementById("testlevel3"); 178 179 try { 180 els.getListenerInfoFor(null); 181 ok(false, "Should have thrown an exception."); 182 } catch (ex) { 183 ok(true, "We should be still running."); 184 } 185 setTimeout(testAllListener, 0); 186 } 187 188 function dispatchTrusted(t, o) { 189 SpecialPowers.dispatchEvent(window, t, new Event("testevent", o)); 190 } 191 192 function testAllListener() { 193 els = SpecialPowers.wrap(els); 194 var results = []; 195 var expectedResults = 196 [ { target: "testlevel3", phase: 3, trusted: false }, 197 { target: "testlevel3", phase: 3, trusted: false }, 198 { target: "testlevel3", phase: 3, trusted: true }, 199 { target: "testlevel3", phase: 3, trusted: true }, 200 { target: "testlevel3", phase: 3, trusted: true } 201 ]; 202 203 function allListener(e) { 204 results.push({ 205 target: e.target.id, 206 phase: e.eventPhase, 207 trusted: e.isTrusted 208 }); 209 e.stopPropagation(); 210 } 211 function allListenerTrustedOnly(e) { 212 results.push({ 213 target: e.target.id, 214 phase: e.eventPhase, 215 trusted: e.isTrusted 216 }); 217 e.stopPropagation(); 218 } 219 220 els.addListenerForAllEvents(root, allListener, false, true); 221 var infos = els.getListenerInfoFor(root); 222 var nullTypes = 0; 223 for (var i = 0; i < infos.length; ++i) { 224 if (infos[i].type == null) { 225 ++nullTypes; 226 } 227 } 228 is(nullTypes, 1, "Should have one all-event-listener!"); 229 230 els.addListenerForAllEvents(root, allListener, false, true, true); 231 els.addListenerForAllEvents(root, allListenerTrustedOnly, false, false, true); 232 l3.dispatchEvent(new Event("testevent", { bubbles: true, composed: true })); 233 dispatchTrusted(l3, { bubbles: true, composed: true }); 234 els.removeListenerForAllEvents(root, allListener, false); 235 els.removeListenerForAllEvents(root, allListener, false, true); 236 els.removeListenerForAllEvents(root, allListenerTrustedOnly, false, true); 237 // make sure removeListenerForAllEvents works. 238 l3.dispatchEvent(new Event("testevent", { bubbles: true, composed : true })); 239 dispatchTrusted(l3, { bubbles: true, composed: true }); 240 241 // Test the order of event listeners. 242 var clickListenerCalled = false; 243 var allListenerCalled = false; 244 function clickListener() { 245 clickListenerCalled = true; 246 ok(allListenerCalled, "Should have called '*' listener before normal listener!"); 247 } 248 function allListener2() { 249 allListenerCalled = true; 250 ok(!clickListenerCalled, "Shouldn't have called click listener before '*' listener!"); 251 } 252 root.onclick = null; // Remove the listener added in earlier tests. 253 root.addEventListener("click", clickListener); 254 els.addListenerForAllEvents(root, allListener2, false, true); 255 l3.dispatchEvent(new MouseEvent("click", { bubbles: true })); 256 root.removeEventListener("click", clickListener); 257 els.removeListenerForAllEvents(root, allListener2, false); 258 ok(allListenerCalled, "Should have called '*' listener"); 259 ok(clickListenerCalled, "Should have called click listener"); 260 261 is(results.length, expectedResults.length, "count"); 262 for (var i = 0; i < expectedResults.length; ++i) { 263 for (var p in expectedResults[i]) { 264 is(results[i][p], expectedResults[i][p], p); 265 } 266 } 267 SimpleTest.finish(); 268 } 269 270 SimpleTest.waitForExplicitFinish(); 271 addLoadEvent(runTests); 272 </script> 273 </pre> 274 <div id="testroot"> 275 <div id="testlevel2"> 276 <div id="testlevel3"> 277 Test 278 </div> 279 </div> 280 </div> 281 </body> 282 </html>