test_shadow_slots.html (20266B)
1 <!DOCTYPE html> 2 <html> 3 4 <head> 5 <title>Test shadow roots with slots</title> 6 7 <link rel="stylesheet" type="text/css" 8 href="chrome://mochikit/content/tests/SimpleTest/test.css" /> 9 10 <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> 11 12 <script type="application/javascript" 13 src="../common.js"></script> 14 <script type="application/javascript" 15 src="../role.js"></script> 16 <script type="application/javascript" 17 src="../promisified-events.js"></script> 18 19 <script type="application/javascript"> 20 async function _dynamicShadowTest(name, mutationFunc, expectedTree, reorder_targets) { 21 info(name); 22 23 let container = getNode(name); 24 let host = container.querySelector('.host'); 25 26 document.body.offsetTop; 27 let event = reorder_targets ? 28 waitForEvents(reorder_targets.map(target => [EVENT_REORDER, target, name])) : 29 waitForEvent(EVENT_REORDER, host, name); 30 31 mutationFunc(container, host); 32 33 await event; 34 35 testAccessibleTree(container, expectedTree); 36 37 return true; 38 } 39 40 async function attachFlatShadow() { 41 await _dynamicShadowTest("attachFlatShadow", 42 (container, host) => { 43 host.attachShadow({ mode: "open" }) 44 .appendChild(container.querySelector('.shadowtree').content.cloneNode(true)); 45 }, { SECTION: [{ SECTION: [{ name: "red"} ] }] }); 46 } 47 48 async function attachOneDeepShadow() { 49 await _dynamicShadowTest("attachOneDeepShadow", 50 (container, host) => { 51 host.attachShadow({ mode: "open" }) 52 .appendChild(container.querySelector('.shadowtree').content.cloneNode(true)); 53 }, { SECTION: [{ SECTION: [{ SECTION: [{ name: "red"} ] }] }] }); 54 } 55 56 async function changeSlotFlat() { 57 await _dynamicShadowTest("changeSlotFlat", 58 (container) => { 59 container.querySelector('.red').removeAttribute('slot'); 60 container.querySelector('.green').setAttribute('slot', 'myslot'); 61 }, { SECTION: [{ SECTION: [{ name: "green"} ] }] }); 62 } 63 64 async function changeSlotOneDeep() { 65 await _dynamicShadowTest("changeSlotOneDeep", 66 (container) => { 67 container.querySelector('.red').removeAttribute('slot'); 68 container.querySelector('.green').setAttribute('slot', 'myslot'); 69 }, { SECTION: [{ SECTION: [{ SECTION: [{ name: "green"} ] }] }] }, ["shadowdiv"]); 70 } 71 72 // Nested roots and slots 73 async function changeSlotNested() { 74 await _dynamicShadowTest("changeSlotNested", 75 (container) => { 76 testAccessibleTree(getNode("changeSlotNested"), 77 { SECTION: [{ SECTION: [{ SECTION: [{ name: "red"} ] }] }] }); 78 container.querySelector('.red').removeAttribute('slot'); 79 container.querySelector('.green').setAttribute('slot', 'myslot'); 80 }, { SECTION: [{ SECTION: [{ SECTION: [{ name: "green"} ] }] }] }, ["shadowdiv"]); 81 } 82 83 async function changeSlotSingleChild() { 84 await _dynamicShadowTest("changeSlotSingleChild", 85 (container) => { 86 container.querySelector('.red').setAttribute('slot', 'invalid'); 87 }, { SECTION: [{ SECTION: [] }] }); 88 } 89 90 async function changeSlotNoShadow() { 91 await _dynamicShadowTest("changeSlotNoShadow", 92 (container) => { 93 // Make sure changing the slot attribute doesn't remove an element 94 // even when it remains in the flat tree. 95 container.querySelector('.red').setAttribute('slot', 'invalid'); 96 // We need a reorder to know when we're done here, so remove another 97 // child. 98 container.querySelector('.green').remove(); 99 }, { SECTION: [{ SECTION: [{ name: "red"} ] }] }); 100 } 101 102 // Dynamic mutations to both shadow root and shadow host subtrees 103 // testing/web-platform/tests/css/css-scoping/shadow-assign-dynamic-001.html 104 async function assignSlotDynamic() { 105 await _dynamicShadowTest("assignSlotDynamic", 106 (container, host) => { 107 host.shadowRoot.appendChild(container.querySelector('.shadowtree').content.cloneNode(true)); 108 host.appendChild(container.querySelector('.lighttree').content.cloneNode(true)); 109 }, { SECTION: [{ SECTION: [{ name: "slot1"}, { name: "slot2" } ] }] }); 110 } 111 112 // testing/web-platform/tests/css/css-scoping/shadow-fallback-dynamic-001.html 113 async function shadowFallbackDynamic_1() { 114 await _dynamicShadowTest("shadowFallbackDynamic_1", 115 (container, host) => { 116 host.firstElementChild.remove(); 117 }, { SECTION: [{ SECTION: [{ name: "green"} ] }] }); 118 } 119 120 // testing/web-platform/tests/css/css-scoping/shadow-fallback-dynamic-002.html 121 async function shadowFallbackDynamic_2() { 122 await _dynamicShadowTest("shadowFallbackDynamic_2", 123 (container, host) => { 124 host.firstElementChild.removeAttribute("slot"); 125 }, { SECTION: [{ SECTION: [{ name: "green"} ] }] }); 126 } 127 128 // testing/web-platform/tests/css/css-scoping/shadow-fallback-dynamic-003.html 129 async function shadowFallbackDynamic_3() { 130 await _dynamicShadowTest("shadowFallbackDynamic_3", 131 (container, host) => { 132 host.appendChild(container.querySelector(".lighttree").content.cloneNode(true)); 133 }, { SECTION: [{ SECTION: [{ name: "green"} ] }] }); 134 } 135 136 // testing/web-platform/tests/css/css-scoping/shadow-fallback-dynamic-004.html 137 async function shadowFallbackDynamic_4() { 138 await _dynamicShadowTest("shadowFallbackDynamic_4", 139 (container, host) => { 140 host.shadowRoot.insertBefore( 141 container.querySelector(".moreshadowtree"). 142 content.cloneNode(true), host.shadowRoot.firstChild); 143 }, { SECTION: [{ SECTION: [{ name: "slotparent2", children: [{ name: "green"} ] }, { name: "slotparent1" } ] }] }); 144 } 145 146 // testing/web-platform/tests/css/css-scoping/shadow-fallback-dynamic-004.html 147 // This tests a case when the the slotted element would remain in the same accessible container 148 async function shadowFallbackDynamic_4_1() { 149 await _dynamicShadowTest("shadowFallbackDynamic_4_1", 150 (container, host) => { 151 host.shadowRoot.insertBefore( 152 container.querySelector(".moreshadowtree"). 153 content.cloneNode(true), host.shadowRoot.firstChild); 154 }, { SECTION: [{ SECTION: [ { name: "green"}, { SEPARATOR: [] } ] }] }); 155 } 156 157 // testing/web-platform/tests/css/css-scoping/shadow-fallback-dynamic-005.html 158 async function shadowFallbackDynamic_5() { 159 await _dynamicShadowTest("shadowFallbackDynamic_5", 160 (container, host) => { 161 host.firstElementChild.setAttribute("slot", "myotherslot"); 162 }, { SECTION: [{ SECTION: [{ name: "green"} ] }] }); 163 } 164 165 // testing/web-platform/tests/css/css-scoping/shadow-reassign-dynamic-002.html 166 async function shadowReassignDynamic_2() { 167 await _dynamicShadowTest("shadowReassignDynamic_2", 168 (container, host) => { 169 host.shadowRoot.querySelector("slot").setAttribute("name", "myslot"); 170 }, { SECTION: [{ SECTION: [{ name: "green"} ] }] }); 171 } 172 173 // testing/web-platform/tests/css/css-scoping/shadow-reassign-dynamic-003.html 174 async function shadowReassignDynamic_3() { 175 await _dynamicShadowTest("shadowReassignDynamic_3", 176 (container, host) => { 177 testAccessibleTree(container, { SECTION: [{ SECTION: [{ name: "green"}, { name: "red", children: [ { PUSHBUTTON: [] }]} ] }] }); 178 host.shadowRoot.querySelector("slot[name]").removeAttribute("name"); 179 180 }, { SECTION: [{ SECTION: [{ name: "green", children: [ { PUSHBUTTON: [] }]}, { name: "red"} ] }] }, 181 [evt => evt.accessible.name == "green", evt => evt.accessible.name == "red"]); 182 } 183 184 // testing/web-platform/tests/css/css-scoping/shadow-reassign-dynamic-004.html 185 async function shadowReassignDynamic_4() { 186 await _dynamicShadowTest("shadowReassignDynamic_4", 187 (container, host) => { 188 host.shadowRoot.getElementById("slot").remove(); 189 }, { SECTION: [{ SECTION: [{ name: "green"} ] }] }); 190 } 191 192 function shadowProcessInvalidation() { 193 testAccessibleTree("shadowProcessInvalidation", 194 { SECTION: [{ 195 SECTION: [{ 196 SECTION: [{ TEXT_LEAF: { name: "Hello "} }, 197 { TEXT: [{ TEXT_LEAF: { name: "World"} }] }, 198 { PUSHBUTTON: { name: "World"} }] 199 }] 200 }] 201 }); 202 } 203 204 async function justAttachShadow() { 205 await _dynamicShadowTest("justAttachShadow", 206 (container, host) => { 207 host.attachShadow({ mode: "open" }); 208 }, { SECTION: [{ SECTION: [] }] }); 209 } 210 211 async function doTest() { 212 await attachFlatShadow(); 213 214 await attachOneDeepShadow(); 215 216 await changeSlotFlat(); 217 218 await changeSlotOneDeep(); 219 220 await changeSlotNested(); 221 222 await changeSlotSingleChild(); 223 224 await changeSlotNoShadow(); 225 226 await assignSlotDynamic(); 227 228 await shadowFallbackDynamic_1(); 229 230 await shadowFallbackDynamic_2(); 231 232 await shadowFallbackDynamic_3(); 233 234 await shadowFallbackDynamic_4(); 235 236 await shadowFallbackDynamic_4_1(); 237 238 await shadowFallbackDynamic_5(); 239 240 await shadowReassignDynamic_2(); 241 242 await shadowReassignDynamic_3(); 243 244 await shadowReassignDynamic_4(); 245 246 shadowProcessInvalidation(); 247 248 await justAttachShadow(); 249 250 SimpleTest.finish(); 251 } 252 253 SimpleTest.waitForExplicitFinish(); 254 addA11yLoadEvent(doTest); 255 </script> 256 </head> 257 <body> 258 259 <p id="display"></p> 260 <div id="content" style="display: none"></div> 261 <pre id="test"> 262 </pre> 263 <div id="attachFlatShadow"> 264 <template class="shadowtree"> 265 <style>::slotted(div) { width: 100px; height: 100px }</style> 266 <slot name="myslot">FAIL</slot> 267 </template> 268 <section class="host"> 269 <div style="background: green" aria-label="green"></div> 270 <div style="background: red" aria-label="red" slot="myslot"></div> 271 </section> 272 </div> 273 274 <div id="attachOneDeepShadow"> 275 <template class="shadowtree"> 276 <style>::slotted(div) { width: 100px; height: 100px }</style> 277 <div id="shadowdiv"> 278 <slot name="myslot">FAIL</slot> 279 </div> 280 </template> 281 <section class="host"> 282 <div style="background: green" aria-label="green"></div> 283 <div style="background: red" aria-label="red" slot="myslot"></div> 284 </section> 285 </div> 286 287 <div id="changeSlotFlat"> 288 <template class="shadowtree"> 289 <style>::slotted(div) { width: 100px; height: 100px }</style> 290 <slot name="myslot">FAIL</slot> 291 </template> 292 <section class="host"> 293 <div class="green" style="background: green" aria-label="green"></div> 294 <div class="red" style="background: red" aria-label="red" slot="myslot"></div> 295 </section> 296 <script> 297 document.querySelector("#changeSlotFlat > .host") 298 .attachShadow({ mode: "open" }) 299 .appendChild(document.querySelector("#changeSlotFlat > .shadowtree").content.cloneNode(true)); 300 </script> 301 </div> 302 303 <div id="changeSlotOneDeep"> 304 <template class="shadowtree"> 305 <style>::slotted(div) { width: 100px; height: 100px }</style> 306 <div id="shadowdiv"> 307 <slot name="myslot">FAIL</slot> 308 </div> 309 </template> 310 <section class="host"> 311 <div class="green" style="background: green" aria-label="green"></div> 312 <div class="red" style="background: red" aria-label="red" slot="myslot"></div> 313 </section> 314 <script> 315 document.querySelector("#changeSlotOneDeep > .host") 316 .attachShadow({ mode: "open" }) 317 .appendChild(document.querySelector("#changeSlotOneDeep > .shadowtree").content.cloneNode(true)); 318 </script> 319 </div> 320 321 <div id="changeSlotNested"> 322 <template class="shadowtree outer"> 323 <div id="shadowdiv"> 324 <slot name="myslot">FAIL</slot> 325 </div> 326 </template> 327 <template class="shadowtree inner"> 328 <style>::slotted(div) { width: 100px; height: 100px }</style> 329 <slot>FAIL</slot> 330 </template> 331 <section class="host"> 332 <div class="green" style="background: green" aria-label="green"></div> 333 <div class="red" style="background: red" aria-label="red" slot="myslot"></div> 334 </section> 335 <script> 336 (function foo() { 337 let outerShadow = 338 document.querySelector("#changeSlotNested > .host"). 339 attachShadow({ mode: "open" }); 340 outerShadow.appendChild( 341 document.querySelector("#changeSlotNested > .shadowtree.outer"). 342 content.cloneNode(true)); 343 let innerShadow = 344 outerShadow.querySelector("#shadowdiv"). 345 attachShadow({ mode: "open" }); 346 innerShadow.appendChild( 347 document.querySelector("#changeSlotNested > .shadowtree.inner"). 348 content.cloneNode(true)); 349 })(); 350 </script> 351 </div> 352 353 <div id="changeSlotSingleChild"> 354 <template class="shadowtree"> 355 <style>::slotted(div) { width: 100px; height: 100px }</style> 356 <slot></slot> 357 </template> 358 <section class="host"> 359 <div class="red" style="background: red" aria-label="red"></div> 360 </section> 361 <script> 362 document.querySelector("#changeSlotSingleChild > .host") 363 .attachShadow({ mode: "open" }) 364 .appendChild(document.querySelector("#changeSlotSingleChild > .shadowtree").content.cloneNode(true)); 365 </script> 366 </div> 367 368 <div id="changeSlotNoShadow"> 369 <section class="host"> 370 <div class="red" style="background: red; width: 100px; height: 100px;" aria-label="red"></div> 371 <div class="green" style="background: green; width: 100px; height: 100px;" aria-label="green"></div> 372 </section> 373 </div> 374 375 <div id="assignSlotDynamic"> 376 <template class="shadowtree"> 377 <style>::slotted(div) { width: 50px; height: 100px }</style> 378 <slot name="slot1">FAIL</slot> 379 <slot name="slot2">FAIL</slot> 380 </template> 381 <template class="lighttree"> 382 <div aria-label="slot1" slot="slot1"></div> 383 <div aria-label="slot2" slot="slot2"></div> 384 </template> 385 <section class="host"></section> 386 <script> 387 document.querySelector("#assignSlotDynamic > .host").attachShadow({ mode: "open" }); 388 </script> 389 </div> 390 391 <div id="shadowFallbackDynamic_1"> 392 <template class="shadowtree"> 393 <slot name="myslot"> 394 <div aria-label="green" style="width: 100px; height: 100px; background: green"></div> 395 </slot> 396 </template> 397 <section class="host"><span slot="myslot">FAIL</span></section> 398 <script> 399 document.querySelector("#shadowFallbackDynamic_1 > .host") 400 .attachShadow({ mode: "open" }) 401 .appendChild(document.querySelector("#shadowFallbackDynamic_1 > .shadowtree").content.cloneNode(true)); 402 </script> 403 </div> 404 405 <div id="shadowFallbackDynamic_2"> 406 <template class="shadowtree"> 407 <slot name="myslot"> 408 <div aria-label="green" style="width: 100px; height: 100px; background: green"></div> 409 </slot> 410 </template> 411 <section class="host"><span slot="myslot">FAIL</span></section> 412 <script> 413 document.querySelector("#shadowFallbackDynamic_2 > .host") 414 .attachShadow({ mode: "open" }) 415 .appendChild(document.querySelector("#shadowFallbackDynamic_2 > .shadowtree").content.cloneNode(true)); 416 </script> 417 </div> 418 419 <div id="shadowFallbackDynamic_3"> 420 <template class="shadowtree"> 421 <slot name="myslot">FAIL</slot> 422 </template> 423 <template class="lighttree"> 424 <div aria-label="green" slot="myslot" style="width: 100px; height: 100px; background: green"></div> 425 </template> 426 <section class="host"></section> 427 <script> 428 document.querySelector("#shadowFallbackDynamic_3 > .host") 429 .attachShadow({ mode: "open" }) 430 .appendChild(document.querySelector("#shadowFallbackDynamic_3 > .shadowtree").content.cloneNode(true)); 431 </script> 432 </div> 433 434 <div id="shadowFallbackDynamic_4"> 435 <template class="shadowtree"> 436 <div aria-label="slotparent1"><slot name="myslot"></slot></div> 437 </template> 438 <template class="moreshadowtree"> 439 <div aria-label="slotparent2"><slot name="myslot">FAIL</slot></div> 440 </template> 441 <section class="host"> 442 <div slot="myslot" aria-label="green" style="width: 100px; height: 100px; background: green"></div> 443 </section> 444 <script> 445 document.querySelector("#shadowFallbackDynamic_4 > .host") 446 .attachShadow({ mode: "open" }) 447 .appendChild(document.querySelector("#shadowFallbackDynamic_4 > .shadowtree").content.cloneNode(true)); 448 </script> 449 </div> 450 451 <div id="shadowFallbackDynamic_4_1"> 452 <template class="shadowtree"> 453 <hr> 454 <slot name="myslot"></slot> 455 </template> 456 <template class="moreshadowtree"> 457 <slot name="myslot">FAIL</slot> 458 </template> 459 <section class="host"> 460 <div slot="myslot" aria-label="green" style="width: 100px; height: 100px; background: green"></div> 461 </section> 462 <script> 463 document.querySelector("#shadowFallbackDynamic_4_1 > .host") 464 .attachShadow({ mode: "open" }) 465 .appendChild(document.querySelector("#shadowFallbackDynamic_4_1 > .shadowtree").content.cloneNode(true)); 466 </script> 467 </div> 468 469 <div id="shadowFallbackDynamic_5"> 470 <template class="shadowtree"> 471 <slot name="myslot"></slot> 472 <slot name="myotherslot">FAIL</slot> 473 </template> 474 <section class="host"> 475 <div slot="myslot" aria-label="green" style="width: 100px; height: 100px; background: green"></div> 476 </section> 477 <script> 478 document.querySelector("#shadowFallbackDynamic_5 > .host") 479 .attachShadow({ mode: "open" }) 480 .appendChild(document.querySelector("#shadowFallbackDynamic_5 > .shadowtree").content.cloneNode(true)); 481 </script> 482 </div> 483 484 <div id="shadowReassignDynamic_2"> 485 <template class="shadowtree"> 486 <style>::slotted(div) { width: 100px; height: 100px }</style> 487 <slot>FAIL</slot> 488 </template> 489 <section class="host"> 490 <div slot="myslot" aria-label="green" style="width: 100px; height: 100px; background: green"></div> 491 </section> 492 <script> 493 document.querySelector("#shadowReassignDynamic_2 > .host") 494 .attachShadow({ mode: "open" }) 495 .appendChild(document.querySelector("#shadowReassignDynamic_2 > .shadowtree").content.cloneNode(true)); 496 </script> 497 </div> 498 499 <div id="shadowReassignDynamic_3"> 500 <template class="shadowtree"> 501 <div aria-label="green"><slot name="nomatch"></slot></div> 502 <div aria-label="red"><slot></slot></div> 503 </template> 504 <section class="host"> 505 <div role="button"></div> 506 </section> 507 <script> 508 document.querySelector("#shadowReassignDynamic_3 > .host") 509 .attachShadow({ mode: "open" }) 510 .appendChild(document.querySelector("#shadowReassignDynamic_3 > .shadowtree").content.cloneNode(true)); 511 </script> 512 </div> 513 514 <div id="shadowReassignDynamic_4"> 515 <template class="shadowtree"> 516 <style>::slotted(div),div { width: 100px; height: 100px }</style> 517 <slot id="slot"></slot> 518 <slot> 519 <div aria-label="red" style="background: red"></div> 520 </slot> 521 </template> 522 <section class="host"> 523 <div aria-label="green" style="background: green"></div> 524 </section> 525 <script> 526 document.querySelector("#shadowReassignDynamic_4 > .host") 527 .attachShadow({ mode: "open" }) 528 .appendChild(document.querySelector("#shadowReassignDynamic_4 > .shadowtree").content.cloneNode(true)); 529 </script> 530 </div> 531 532 <div id="shadowProcessInvalidation"> 533 <template class="shadowtree"> 534 <div id="shadowdiv"> 535 <slot></slot> 536 </div> 537 </template> 538 <section class="host">Hello <span id="c">World</span><button aria-labelledby="c"></button></section> 539 <script> 540 document.querySelector("#shadowProcessInvalidation > .host") 541 .attachShadow({ mode: "open" }) 542 .appendChild(document.querySelector("#shadowProcessInvalidation > .shadowtree").content.cloneNode(true)); 543 </script> 544 </div> 545 546 <div id="justAttachShadow"> 547 <section class="host"> 548 <button></button> 549 </section> 550 </div> 551 552 <div id="eventdump"></div> 553 </body> 554 </html>