test_devtoolschildremoved.html (16685B)
1 <!doctype html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <title>devtoolschildremoved event tests</title> 6 <script src="/tests/SimpleTest/SimpleTest.js"></script> 7 <script src="/tests/SimpleTest/EventUtils.js"></script> 8 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> 9 <script> 10 "use strict"; 11 12 SimpleTest.waitForExplicitFinish(); 13 SimpleTest.waitForFocus(async () => { 14 await SpecialPowers.pushPrefEnv({ set: [["dom.movebefore.enabled", true]] }); 15 16 // Unlock devtoolschildremoved events. 17 SpecialPowers.wrap(document).devToolsWatchingDOMMutations = true; 18 SimpleTest.registerCleanupFunction(() => { 19 SpecialPowers.wrap(document).devToolsWatchingDOMMutations = false; 20 }); 21 22 function getDevToolsChildRemovedEvent(aTarget, aTestBody, aOnEvent) { 23 let event; 24 function getEvent(e) { 25 if (e.target == aTarget) { 26 event = e; 27 aOnEvent(); 28 } 29 } 30 const chromeEventHandler = SpecialPowers.wrap(window).docShell.chromeEventHandler; 31 chromeEventHandler.addEventListener( 32 "devtoolschildremoved", 33 getEvent, 34 { 35 once: true, 36 capture: true, 37 } 38 ); 39 try { 40 aTestBody(); 41 } finally { 42 chromeEventHandler.removeEventListener( 43 "devtoolschildremoved", 44 getEvent, 45 {capture: true} 46 ); 47 } 48 return event; 49 } 50 51 const srcContainer = document.getElementById("container"); 52 const destContainer = document.getElementById("destContainer"); 53 const refChild = document.getElementById("refChild"); 54 55 // When a node is removed or moved from another place, "devtoolschildremoved" 56 // event whose target is the removed node should be fired. 57 { 58 const span = document.createElement("span"); 59 srcContainer.appendChild(span); 60 const event = getDevToolsChildRemovedEvent( 61 span, 62 () => { 63 span.remove(); 64 }, 65 () => { 66 is( 67 span.parentNode, 68 srcContainer, 69 "devtoolschildremoved when Node.remove() should be called before removed from the DOM" 70 ); 71 } 72 ); 73 isnot(event, undefined, "Node.remove() should cause a devtoolschildremoved event"); 74 } 75 76 { 77 const span = document.createElement("span"); 78 srcContainer.appendChild(span); 79 const event = getDevToolsChildRemovedEvent( 80 span, 81 () => { 82 srcContainer.removeChild(span); 83 }, 84 () => { 85 is( 86 span.parentNode, 87 srcContainer, 88 "devtoolschildremoved when Node.removeChild() should be called before removed from the DOM" 89 ); 90 } 91 ); 92 isnot(event, undefined, "Node.removeChild() should cause a devtoolschildremoved event"); 93 } 94 95 { 96 const span = document.createElement("span"); 97 srcContainer.appendChild(span); 98 const event = getDevToolsChildRemovedEvent( 99 span, 100 () => { 101 destContainer.appendChild(span); 102 }, 103 () => { 104 is( 105 span.parentNode, 106 srcContainer, 107 "devtoolschildremoved when Node.appendChild() should be called before removed from the DOM" 108 ); 109 } 110 ); 111 isnot(event, undefined, "Node.appendChild() with connected node should cause a devtoolschildremoved event"); 112 span.remove(); 113 } 114 115 { 116 const span = document.createElement("span"); 117 srcContainer.appendChild(span); 118 const event = getDevToolsChildRemovedEvent( 119 span, 120 () => { 121 destContainer.insertBefore(span, refChild); 122 }, 123 () => { 124 is( 125 span.parentNode, 126 srcContainer, 127 "devtoolschildremoved when Node.insertBefore() should be called before removed from the DOM" 128 ); 129 } 130 ); 131 isnot(event, undefined, "Node.insertBefore() with connected node should cause a devtoolschildremoved event"); 132 span.remove(); 133 } 134 135 { 136 const span = document.createElement("span"); 137 srcContainer.appendChild(span); 138 const event = getDevToolsChildRemovedEvent( 139 span, 140 () => { 141 destContainer.moveBefore(span, refChild); 142 }, 143 () => { 144 is( 145 span.parentNode, 146 srcContainer, 147 "devtoolschildremoved when Node.moveBefore() should be called before removed from the DOM" 148 ); 149 } 150 ); 151 isnot(event, undefined, "Node.moveBefore() with connected node should cause a devtoolschildremoved event"); 152 span.remove(); 153 } 154 155 // While DevTools breaks on a removal of a node, users can modify the DOM. 156 // In such case, at least we should avoid to crash. 157 { 158 const span = document.createElement("span"); 159 srcContainer.appendChild(span); 160 try { 161 const event = getDevToolsChildRemovedEvent( 162 span, 163 () => { 164 destContainer.appendChild(span); 165 }, 166 () => { 167 refChild.remove(); 168 } 169 ); 170 isnot( 171 event, 172 undefined, 173 "The dest container is modified while Node.appendChild() is called should cause a devtoolschildremoved event" 174 ); 175 } catch (e) { 176 is( 177 span.parentNode, 178 srcContainer, 179 "The moving <span> should stay in the src container when the dest container is modified during Node.appendChild()" 180 ); 181 } finally { 182 span.remove(); 183 destContainer.appendChild(refChild); 184 } 185 } 186 187 { 188 const span = document.createElement("span"); 189 srcContainer.appendChild(span); 190 try { 191 const event = getDevToolsChildRemovedEvent( 192 span, 193 () => { 194 destContainer.insertBefore(span, refChild); 195 }, 196 () => { 197 refChild.remove(); 198 } 199 ); 200 isnot( 201 event, 202 undefined, 203 "The dest container is modified while Node.insertBefore() is called should cause a devtoolschildremoved event" 204 ); 205 } catch (e) { 206 is( 207 span.parentNode, 208 srcContainer, 209 "The moving <span> should stay in the src container when the dest container is modified during Node.insertBefore()" 210 ); 211 } finally { 212 span.remove(); 213 destContainer.appendChild(refChild); 214 } 215 } 216 217 { 218 const span = document.createElement("span"); 219 srcContainer.appendChild(span); 220 try { 221 const event = getDevToolsChildRemovedEvent( 222 span, 223 () => { 224 destContainer.moveBefore(span, refChild); 225 }, 226 () => { 227 refChild.remove(); 228 } 229 ); 230 isnot( 231 event, 232 undefined, 233 "The dest container is modified while Node.moveBefore() is called should cause a devtoolschildremoved event" 234 ); 235 } catch (e) { 236 is( 237 span.parentNode, 238 srcContainer, 239 "The moving <span> should stay in the src container when the dest container is modified during Node.moveBefore()" 240 ); 241 } finally { 242 span.remove(); 243 destContainer.appendChild(refChild); 244 } 245 } 246 247 { 248 const span = document.createElement("span"); 249 srcContainer.appendChild(span); 250 try { 251 const event = getDevToolsChildRemovedEvent( 252 span, 253 () => { 254 destContainer.appendChild(span); 255 }, 256 () => { 257 destContainer.remove(); 258 } 259 ); 260 isnot( 261 event, 262 undefined, 263 "The dest container is removed while Node.appendChild() is called should cause a devtoolschildremoved event" 264 ); 265 } catch (e) { 266 is( 267 span.parentNode, 268 srcContainer, 269 "The moving <span> should stay in the src container when the dest container is removed during Node.appendChild()" 270 ); 271 } finally { 272 span.remove(); 273 document.body.appendChild(destContainer); 274 } 275 } 276 277 { 278 const span = document.createElement("span"); 279 srcContainer.appendChild(span); 280 try { 281 const event = getDevToolsChildRemovedEvent( 282 span, 283 () => { 284 destContainer.insertBefore(span, refChild); 285 }, 286 () => { 287 destContainer.remove(); 288 } 289 ); 290 isnot( 291 event, 292 undefined, 293 "The dest container is removed while Node.insertBefore() is called should cause a devtoolschildremoved event" 294 ); 295 } catch (e) { 296 is( 297 span.parentNode, 298 srcContainer, 299 "The moving <span> should stay in the src container when the dest container is removed during Node.insertBefore()" 300 ); 301 } finally { 302 span.remove(); 303 document.body.appendChild(destContainer); 304 } 305 } 306 307 { 308 const span = document.createElement("span"); 309 srcContainer.appendChild(span); 310 try { 311 const event = getDevToolsChildRemovedEvent( 312 span, 313 () => { 314 destContainer.moveBefore(span, refChild); 315 }, 316 () => { 317 destContainer.remove(); 318 } 319 ); 320 isnot( 321 event, 322 undefined, 323 "The dest container is removed while Node.moveBefore() is called should cause a devtoolschildremoved event" 324 ); 325 } catch (e) { 326 is( 327 span.parentNode, 328 srcContainer, 329 "The moving <span> should stay in the src container when the dest container is removed during Node.moveBefore()" 330 ); 331 } finally { 332 span.remove(); 333 document.body.appendChild(destContainer); 334 } 335 } 336 337 { 338 const span = document.createElement("span"); 339 srcContainer.appendChild(span); 340 try { 341 const event = getDevToolsChildRemovedEvent( 342 span, 343 () => { 344 span.remove(); 345 }, 346 () => { 347 span.remove(); 348 } 349 ); 350 isnot( 351 event, 352 undefined, 353 "The removing <span> is removed while Node.remove() is called should cause a devtoolschildremoved event" 354 ); 355 } catch (e) { 356 } finally { 357 is( 358 span.parentNode, 359 null, 360 "The removing <span> should not stay in the src container when it's removed during Node.remove()" 361 ); 362 span.remove(); 363 } 364 } 365 366 { 367 const span = document.createElement("span"); 368 srcContainer.appendChild(span); 369 try { 370 const event = getDevToolsChildRemovedEvent( 371 span, 372 () => { 373 srcContainer.removeChild(span); 374 }, 375 () => { 376 span.remove(); 377 } 378 ); 379 isnot( 380 event, 381 undefined, 382 "The removing <span> is removed while Node.removeChild() is called should cause a devtoolschildremoved event" 383 ); 384 } catch (e) { 385 } finally { 386 is( 387 span.parentNode, 388 null, 389 "The removing <span> should not stay in the src container when it's removed during Node.removeChild()" 390 ); 391 span.remove(); 392 } 393 } 394 395 { 396 const span = document.createElement("span"); 397 srcContainer.appendChild(span); 398 try { 399 const event = getDevToolsChildRemovedEvent( 400 span, 401 () => { 402 destContainer.appendChild(span); 403 }, 404 () => { 405 span.remove(); 406 } 407 ); 408 isnot( 409 event, 410 undefined, 411 "The moving <span> is removed while Node.appendChild() is called should cause a devtoolschildremoved event" 412 ); 413 } catch (e) { 414 is( 415 span.parentNode, 416 null, 417 "The moving <span> should not in the DOM when it's removed during Node.appendChild()" 418 ); 419 } finally { 420 span.remove(); 421 } 422 } 423 424 { 425 const span = document.createElement("span"); 426 srcContainer.appendChild(span); 427 try { 428 const event = getDevToolsChildRemovedEvent( 429 span, 430 () => { 431 destContainer.insertBefore(span, refChild); 432 }, 433 () => { 434 span.remove(); 435 } 436 ); 437 isnot( 438 event, 439 undefined, 440 "The moving <span> is removed while Node.insertBefore() is called should cause a devtoolschildremoved event" 441 ); 442 } catch (e) { 443 is( 444 span.parentNode, 445 null, 446 "The moving <span> should not in the DOM when it's removed during Node.insertBefore()" 447 ); 448 } finally { 449 span.remove(); 450 } 451 } 452 453 { 454 const span = document.createElement("span"); 455 srcContainer.appendChild(span); 456 try { 457 const event = getDevToolsChildRemovedEvent( 458 span, 459 () => { 460 destContainer.moveBefore(span, refChild); 461 }, 462 () => { 463 span.remove(); 464 } 465 ); 466 isnot( 467 event, 468 undefined, 469 "The moving <span> is removed while Node.moveBefore() is called should cause a devtoolschildremoved event" 470 ); 471 } catch (e) { 472 is( 473 span.parentNode, 474 null, 475 "The moving <span> should not in the DOM when it's removed during Node.moveBefore()" 476 ); 477 } finally { 478 span.remove(); 479 } 480 } 481 482 { 483 const span = document.createElement("span"); 484 srcContainer.appendChild(span); 485 try { 486 const event = getDevToolsChildRemovedEvent( 487 span, 488 () => { 489 span.remove(); 490 }, 491 () => { 492 srcContainer.remove(); 493 } 494 ); 495 isnot( 496 event, 497 undefined, 498 "The src container is removed while Node.remove() is called should cause a devtoolschildremoved event" 499 ); 500 } catch (e) { 501 is( 502 span.parentNode, 503 srcContainer, 504 "The removing <span> should stay in the src container when the container is removed during Node.remove()" 505 ); 506 } finally { 507 span.remove(); 508 document.body.insertBefore(srcContainer, destContainer); 509 } 510 } 511 512 { 513 const span = document.createElement("span"); 514 srcContainer.appendChild(span); 515 try { 516 const event = getDevToolsChildRemovedEvent( 517 span, 518 () => { 519 srcContainer.removeChild(span); 520 }, 521 () => { 522 srcContainer.remove(); 523 } 524 ); 525 isnot( 526 event, 527 undefined, 528 "The src container is removed while Node.removeChild() is called should cause a devtoolschildremoved event" 529 ); 530 } catch (e) { 531 is( 532 span.parentNode, 533 srcContainer, 534 "The removing <span> should stay in the src container when the container is removed during Node.removeChild()" 535 ); 536 } finally { 537 span.remove(); 538 document.body.insertBefore(srcContainer, destContainer); 539 } 540 } 541 542 { 543 const span = document.createElement("span"); 544 srcContainer.appendChild(span); 545 try { 546 const event = getDevToolsChildRemovedEvent( 547 span, 548 () => { 549 destContainer.appendChild(span); 550 }, 551 () => { 552 srcContainer.remove(); 553 } 554 ); 555 isnot( 556 event, 557 undefined, 558 "The src container is removed while Node.appendChild() is called should cause a devtoolschildremoved event" 559 ); 560 } catch (e) { 561 is( 562 span.parentNode, 563 srcContainer, 564 "The moving <span> should stay in the src container when the container is removed during Node.appendChild()" 565 ); 566 } finally { 567 span.remove(); 568 document.body.insertBefore(srcContainer, destContainer); 569 } 570 } 571 572 { 573 const span = document.createElement("span"); 574 srcContainer.appendChild(span); 575 try { 576 const event = getDevToolsChildRemovedEvent( 577 span, 578 () => { 579 destContainer.insertBefore(span, refChild); 580 }, 581 () => { 582 srcContainer.remove(); 583 } 584 ); 585 isnot( 586 event, 587 undefined, 588 "The src container is removed while Node.insertBefore() is called should cause a devtoolschildremoved event" 589 ); 590 } catch (e) { 591 is( 592 span.parentNode, 593 srcContainer, 594 "The moving <span> should stay in the src container when the container is removed during Node.insertBefore()" 595 ); 596 } finally { 597 span.remove(); 598 document.body.insertBefore(srcContainer, destContainer); 599 } 600 } 601 602 { 603 const span = document.createElement("span"); 604 srcContainer.appendChild(span); 605 try { 606 const event = getDevToolsChildRemovedEvent( 607 span, 608 () => { 609 destContainer.moveBefore(span, refChild); 610 }, 611 () => { 612 srcContainer.remove(); 613 } 614 ); 615 isnot( 616 event, 617 undefined, 618 "The src container is removed while Node.moveBefore() is called should cause a devtoolschildremoved event" 619 ); 620 } catch (e) { 621 is( 622 span.parentNode, 623 srcContainer, 624 "The moving <span> should stay in the src container when the container is removed during Node.moveBefore()" 625 ); 626 } finally { 627 span.remove(); 628 document.body.insertBefore(srcContainer, destContainer); 629 } 630 } 631 632 SimpleTest.finish(); 633 }); 634 </script> 635 </head> 636 <body> 637 <div id="container"></div> 638 <div id="destContainer"><span id="refChild"></span></div> 639 </body> 640 </html>