1<!doctype html> 2<!-- 3@license 4Copyright (c) 2014 The Polymer Project Authors. All rights reserved. 5This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt 6The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt 7The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt 8Code distributed by Google as part of the polymer project is also 9subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt 10--> 11<html> 12<head> 13 <meta charset="utf-8"> 14 <script> 15 WCT = {waitFor: function (cb) {HTMLImports.whenReady(cb)}} 16 </script> 17 <script src="./test-flags.js"></script> 18 <script src="../node_modules/wct-browser-legacy/browser.js"></script> 19 <script src="../node_modules/@webcomponents/webcomponents-platform/webcomponents-platform.js"></script> 20 <script src="../node_modules/es6-promise/dist/es6-promise.auto.min.js"></script> 21 <script src="../node_modules/@webcomponents/template/template.js"></script> 22 <script src="../node_modules/@webcomponents/html-imports/html-imports.min.js"></script> 23 <script src="../node_modules/@webcomponents/shadydom/shadydom.min.js"></script> 24 <script src="../node_modules/@webcomponents/custom-elements/custom-elements.min.js"></script> 25 <script src="../scoping-shim.min.js"></script> 26 <script src="../apply-shim.min.js"></script> 27 <script src="../custom-style-interface.min.js"></script> 28 <script src="module/generated/make-element.js"></script> 29 30 <custom-style> 31 <style> 32 div#priority { 33 border: 1px solid black; 34 } 35 </style> 36 </custom-style> 37</head> 38<body> 39 40<template id="x-gchild"> 41 <style> 42 </style> 43 <div id="target">x-gchild</div> 44</template> 45 46<template id="x-child"> 47 <div id="simple">simple</div> 48 <div id="complex1" class="scoped">complex1</div> 49 <div id="complex2" selected>complex2</div> 50 <div id="media">media</div> 51 <div id="shadow" class="shadowTarget">shadowTarget</div> 52 <div id="deep" class="deepTarget">deepTarget</div> 53 <x-gchild id="gchild1"></x-gchild> 54 <x-gchild id="gchild2" class="wide"></x-gchild> 55</template> 56 57<template id="x-child2"> 58 <style> 59 :host(.wide) #target{ 60 border: none; 61 } 62 </style> 63 <div id="target">x-child2</div> 64</template> 65 66<template id="x-scope-class"> 67 <div id="scope">Trivial</div> 68</template> 69 70<template id="x-scoped"> 71 <style> 72 :host { 73 display: block; 74 border: 1px solid orange; 75 --keyframes100: 100px; 76 } 77 78 :host(.wide) { 79 border-width: 2px; 80 } 81 82 :host(.wide)::after { 83 content: '-content-'; 84 }; 85 86 #keyframes2.special { 87 --keyframes100: 200px; 88 } 89 90 #simple { 91 border: 3px solid orange; 92 } 93 94 .scoped, [selected] { 95 border: 4px solid pink; 96 } 97 98 @media(max-width: 10000px) { 99 .media { 100 border: 5px solid brown; 101 } 102 } 103 104 .container ::slotted(*) { 105 border: 6px solid navy; 106 } 107 108 #priority { 109 border: 9px solid orange; 110 } 111 112 .container1 > ::slotted([slot=content1]) { 113 border: 13px solid navy; 114 } 115 116 .container2 > ::slotted([slot=content2]) { 117 border: 14px solid navy; 118 } 119 120 .computed { 121 border: 15px solid orange; 122 } 123 124 .computeda { 125 border: 20px solid orange; 126 } 127 128 #child { 129 border: 16px solid tomato; 130 display: block; 131 } 132 133 svg { 134 margin-top: 20px; 135 } 136 137 #circle { 138 fill: seagreen; 139 stroke-width: 1px; 140 stroke: tomato; 141 } 142 </style> 143 <slot name="blank"></slot> 144 <div id="simple">simple</div> 145 <div id="complex1" class="scoped">complex1</div> 146 <div id="complex2" selected>complex2</div> 147 <div id="media" class="media">media</div> 148 <div class="container1"> 149 <slot name="content1"></slot> 150 </div> 151 <div class="container2"> 152 <slot name="content2"></slot> 153 </div> 154 <div class="container"> 155 <slot></slot> 156 </div> 157 <x-child id="child"></x-child> 158 <div id="priority">priority</div> 159 <x-child2 class="wide" id="child2"></x-child2> 160 <div id="computed">Computed</div> 161 <svg height="25" width="25"> 162 <circle id="circle" cx="12" cy="12" r="10"></circle> 163 </svg> 164 <x-scope-class id="scopeClass"></x-scope-class> 165 <x-keyframes id="keyframes"></x-keyframes> 166 <x-keyframes id="keyframes2"></x-keyframes> 167</template> 168 169<template id="x-slotted"> 170 <style> 171 ::slotted(.auto-content) { 172 border: 2px solid orange; 173 } 174 .bar, ::slotted(.complex-child) { 175 border: 6px solid navy; 176 } 177 #container ::slotted(*) { 178 border: 8px solid green; 179 } 180 </style> 181 <slot></slot> 182 <div id="container"> 183 <slot name="container"></slot> 184 </div> 185</template> 186 187<template id="dynamic"> 188 <div class="added"> 189 Added 190 <div class="sub-added"> 191 Sub-added 192 </div> 193 </div> 194 </div> 195</template> 196 197<template id="x-dynamic-scope"> 198 <style> 199 .added { 200 border: 17px solid beige; 201 } 202 .sub-added { 203 border: 18px solid #fafafa; 204 } 205 </style> 206 <div id="container"></div> 207</template> 208 209<template id="x-keyframes"> 210 <style> 211 :host { 212 display: block; 213 position: relative; 214 border: 10px solid blue; 215 left: 0px; 216 /* Prefix required by Safari <= 8 */ 217 -webkit-animation-duration: 0.3s; 218 animation-duration: 0.3s; 219 -webkit-animation-fill-mode: forwards; 220 animation-fill-mode: forwards; 221 } 222 223 :host([animated]) { 224 /* Prefix required by Safari <= 8 */ 225 -webkit-animation-name: x-keyframes-animation; 226 animation-name: x-keyframes-animation; 227 } 228 229 /* Prefix required by Safari <= 8 */ 230 @-webkit-keyframes x-keyframes-animation { 231 0% { 232 left: var(--keyframes0, 0px); 233 } 234 235 100% { 236 left: var(--keyframes100, 10px); 237 } 238 } 239 @keyframes x-keyframes-animation { 240 0% { 241 left: var(--keyframes0, 0px); 242 } 243 244 100% { 245 left: var(--keyframes100, 10px); 246 } 247 } 248 </style> 249 x-keyframes 250</template> 251 252<template id="x-attr-selector"> 253 <style> 254 #foo1 ~ #bar1 { 255 border: 2px solid red; 256 } 257 258 #foo1 ~ #bar1 ~ #foo2[attr~=foo2] ~ #bar2[attr~=bar2] { 259 border: 4px solid red; 260 } 261 262 #foo1 ~ #bar1 ~ #foo2[attr~=foo2] ~ #bar2[attr~=bar2] ~ #foo3[attr~=foo3][a~=a] ~ #bar3[attr~=bar3][a~=a] { 263 border: 6px solid red; 264 } 265 </style> 266 <div id="foo1"></div> 267 <div id="bar1">bar1</div> 268 <div id="foo2" attr="foo2"></div> 269 <div id="bar2" attr="bar2">bar2</div> 270 <div id="foo3" attr="foo3" a="a"></div> 271 <div id="bar3" attr="bar3" a="a">bar3</div> 272</template> 273 274<template id="x-adjacent-sibling"> 275 <style> 276 div { 277 border: 20px solid black; 278 } 279 #foo2 + #foo1 { 280 border: 2px solid black; 281 } 282 #foo1 + #foo2 { 283 border: 4px solid black; 284 } 285 #foo2 + #foo3 { 286 border: 6px solid black; 287 } 288 </style> 289 <div id="foo1"></div> 290 <div id="foo2"></div> 291 <div id="foo3"></div> 292</template> 293 294<template id="svg"> 295 <svg class="svg" viewBox="0 0 24 24"> 296 <circle id="circle" r="12" cx="12" cy="12" /> 297 </svg> 298</template> 299 300<template id="x-dynamic-svg"> 301 <style> 302 .svg { 303 height: 24px; 304 width: 24px; 305 } 306 #circle { 307 fill: red; 308 fill-opacity: 0.5; 309 } 310 </style> 311 <div id="container"></div> 312</template> 313 314<template id="x-specificity"> 315 <style> 316 :host { 317 border-top: 1px solid red; 318 } 319 :host(.bar) { 320 border-top: 2px solid red; 321 } 322 </style> 323 <slot></slot> 324</template> 325 326<template id="self-test"> 327 <style> 328 :host { 329 --border: 10px solid rgb(123, 123, 123); 330 } 331 332 a { 333 border: var(--border); 334 } 335 </style> 336 <a>I should be red.</a> 337</template> 338 339<template id="nth-plus-one"> 340 <style> 341 .foo.bar { 342 color: rgb(255, 0, 0); 343 } 344 div:nth-child(n+1) { 345 color: rgb(0, 255, 0); 346 } 347 </style> 348 <div>1</div> 349 <div class="foo bar">2</div> 350</template> 351 352<template id="shady-unscoped"> 353 <style shady-unscoped> 354 .unscoped { 355 color: rgb(255, 0, 0); 356 } 357 </style> 358 <div class="unscoped"></div> 359</template> 360 361<template id="shady-unscoped-2"> 362 <style shady-unscoped> 363 .unscoped { 364 color: rgb(255, 0, 0); 365 } 366 </style> 367 <span class="unscoped"></span> 368</template> 369 370<template id="unscoped-apply-user"> 371 <style> 372 div { 373 @apply --unscoped-foo; 374 } 375 </style> 376 <div></div> 377</template> 378 379<template id="unscoped-apply"> 380 <style shady-unscoped> 381 html, :host > * { 382 --unscoped-foo: {border: 10px solid black}; 383 } 384 </style> 385 <unscoped-apply-user></unscoped-apply-user> 386</template> 387 388<template id="any-selector"> 389 <style> 390 :-webkit-any(div, span) { 391 color: rgb(123, 123, 123); 392 } 393 :-moz-any(div, span) { 394 color: rgb(123, 123, 123); 395 } 396 </style> 397 <div>a</div> 398 <span>b</span> 399</template> 400 401<template id="scoped-keyframes"> 402 <style> 403 :host { 404 --time: 0.1s; 405 } 406 407 div { 408 /* prefix for older chrome and safari */ 409 -webkit-animation-duration: var(--time); 410 animation-duration: var(--time); 411 -webkit-animation-fill-mode: forwards; 412 animation-fill-mode: forwards; 413 border: 0px solid black; 414 } 415 416 :host([animate]) div { 417 /* prefix for older chrome and safari */ 418 -webkit-animation-name: border-grow; 419 animation-name: border-grow; 420 } 421 422 /* prefix for older chrome and safari */ 423 @-webkit-keyframes border {} 424 @-webkit-keyframes border-grow { 425 to { 426 border-top-width: 10px; 427 } 428 } 429 @keyframes border {} 430 @keyframes border-grow { 431 to { 432 border-top-width: 10px; 433 } 434 } 435 </style> 436 437 <div id="target">Hello world</div> 438</template> 439 440<template id="nested-templates"> 441 <style> 442 * { 443 opacity: 0.5; 444 } 445 </style> 446 <div id="a"></div> 447 <template id="t1"> 448 <div id="b"> 449 <div id="c"> 450 <template id="t2"> 451 <div id="d"></div> 452 </template> 453 </div> 454 </div> 455 </template> 456 <svg> 457 <template id="t3"> 458 <g id="g"> 459 <circle id="circle"></circle> 460 </g> 461 </template> 462 </svg> 463</template> 464 465<template id="bad-mixin"> 466 <style> 467 :host(.nomatch) { 468 --div-border: { 469 border: 2px solid black; 470 } 471 } 472 div { 473 @apply --div-border; 474 } 475 </style> 476 <div></div> 477</template> 478 479<template id="x-parent-skip"> 480 <style> 481 :host { 482 --foo: 10px solid black; 483 } 484 </style> 485 <x-skip></x-skip> 486</template> 487 488<template id="x-skip"> 489 <x-child-skip></x-child-skip> 490</template> 491 492<template id="x-child-skip"> 493 <style> 494 div { 495 border: var(--foo); 496 } 497 </style> 498 <div></div> 499</template> 500 501<script> 502(function() { 503 function assertComputed(element, value, property, pseudo) { 504 var computed = getComputedStyle(element, pseudo); 505 property = property || 'border-top-width'; 506 if (Array.isArray(value)) { 507 assert.oneOf(computed[property], value, 'computed style incorrect for ' + property); 508 } else { 509 assert.equal(computed[property], value, 'computed style incorrect for ' + property); 510 } 511 } 512 513 function findNode(desc) { 514 var parts = desc.split('.'); 515 var root = document; 516 var node; 517 for (var i=0, p; i < parts.length; i++) { 518 p = parts[i]; 519 if (p == '$') { 520 root = node.shadowRoot; 521 } else { 522 node = root.querySelector('#' + p); 523 } 524 } 525 return node; 526 } 527 528 function flush() { 529 if (window.ShadyDOM) { 530 window.ShadyDOM.flush(); 531 } 532 window.ShadyCSS.ScopingShim.flush(); 533 } 534 535 suite('scoped-styling', function() { 536 537 suiteSetup(function() { 538 makeElement('x-gchild'); 539 makeElement('x-child', function() { 540 this.classList.add('nug'); 541 }); 542 makeElement('x-child2'); 543 makeElement('x-scope-class'); 544 makeElement('x-scoped'); 545 makeElement('x-slotted'); 546 (function() { 547 var dynamic = document.querySelector('template#dynamic'); 548 549 makeElement('x-dynamic-scope', 550 function() { 551 // simulate 3rd party action by using normal dom to add to element. 552 var dom = document.importNode(dynamic.content, true); 553 this.shadowRoot.querySelector('#container').appendChild(dom); 554 }); 555 })(); 556 makeElement('x-keyframes'); 557 makeElement('x-attr-selector'); 558 (function() { 559 var template = document.querySelector('template#svg'); 560 561 makeElement('x-dynamic-svg', function() { 562 var dom = document.importNode(template.content, true); 563 this.shadowRoot.querySelector('#container').appendChild(dom); 564 }); 565 })(); 566 makeElement('x-specificity'); 567 makeElement('nested-templates'); 568 }); 569 570 var el; 571 setup(function() { 572 el = document.createElement('x-scoped'); 573 el.id = 'el'; 574 document.body.appendChild(el); 575 flush(); 576 }); 577 578 teardown(function() { 579 document.body.removeChild(el); 580 }); 581 582 test(':host', function() { 583 assertComputed(el, '1px'); 584 assertComputed(el, ['', 'none'], 'content', '::after'); 585 }); 586 587 test(':host(...)', function() { 588 var el2 = document.createElement('x-scoped'); 589 el2.classList.add('wide'); 590 document.body.appendChild(el2); 591 flush(); 592 assertComputed(el2, '2px'); 593 assertComputed(el2, ['"-content-"', '-content-'], 'content', '::after'); 594 document.body.removeChild(el2); 595 }); 596 597 test('scoped selectors, simple and complex', function() { 598 assertComputed(findNode('el.$.simple'), '3px'); 599 assertComputed(findNode('el.$.complex1'), '4px'); 600 assertComputed(findNode('el.$.complex2'), '4px'); 601 }); 602 603 test('media query scoped selectors', function() { 604 assertComputed(findNode('el.$.media'), '5px'); 605 }); 606 607 test('upper bound encapsulation', function() { 608 var d = document.createElement('div'); 609 d.classList.add('scoped'); 610 document.body.appendChild(d); 611 assertComputed(d, '0px'); 612 document.body.removeChild(d); 613 }); 614 615 test('lower bound encapsulation', function() { 616 assertComputed(findNode('el.$.child.$.simple'), '0px'); 617 assertComputed(findNode('el.$.child.$.complex1'), '0px'); 618 assertComputed(findNode('el.$.child.$.complex2'), '0px'); 619 assertComputed(findNode('el.$.child.$.media'), '0px'); 620 }); 621 622 test('nested templates', function() { 623 var el = document.createElement('nested-templates'); 624 document.body.appendChild(el); 625 // Append nested template content. Note the <template> in <svg> is not 626 // an HTML template with .content at this point; it is just an unknown 627 // SVGElement so we don't have to stamp it 628 var t1 = el.shadowRoot.querySelector('#t1'); 629 el.shadowRoot.appendChild(t1.content.cloneNode(true)); 630 var t2 = el.shadowRoot.querySelector('#t2'); 631 el.shadowRoot.appendChild(t2.content.cloneNode(true)); 632 // Everything should now have 'opacity: 0.5' 633 var els = Array.from(el.shadowRoot.querySelectorAll('[id]')); 634 assert.deepEqual(els.map(e => e.getAttribute('id')), ['a', 't1', 't3', 'g', 'circle', 'b', 'c', 't2', 'd']); 635 els.forEach(e => { 636 assert.equal(getComputedStyle(e).opacity, '0.5', `Element with id "${e.id}" does not have the correct opacity`); 637 }); 638 document.body.removeChild(el); 639 }); 640 641 }); 642 643 suite('slotted', function() { 644 645 test('::slotted selectors', function() { 646 var el = document.createElement('x-scoped'); 647 document.body.appendChild(el); 648 var content1 = document.createElement('div'); 649 content1.slot = 'content1'; 650 var content2 = document.createElement('div'); 651 content2.slot = 'content2'; 652 var content = document.createElement('div'); 653 content.className = 'content'; 654 el.appendChild(content1); 655 el.appendChild(content2); 656 el.appendChild(content); 657 flush(); 658 659 assertComputed(content, '6px'); 660 assertComputed(content1, '13px'); 661 assertComputed(content2, '14px'); 662 document.body.removeChild(el); 663 }); 664 665 test('auto ::slotted selector', function() { 666 var x = document.createElement('x-slotted'); 667 var d1 = document.createElement('div'); 668 d1.classList.add('auto-content'); 669 d1.textContent = 'auto-content'; 670 document.body.appendChild(x); 671 x.appendChild(d1); 672 flush(); 673 assertComputed(d1, '2px'); 674 document.body.removeChild(x); 675 }); 676 677 test('::slotted + child in complex selector', function() { 678 var x = document.createElement('x-slotted'); 679 var d1 = document.createElement('div'); 680 d1.classList.add('complex-child'); 681 d1.textContent = 'complex-child'; 682 document.body.appendChild(x); 683 x.appendChild(d1); 684 flush(); 685 assertComputed(d1, '6px'); 686 document.body.removeChild(x); 687 }); 688 689 test('::slotted + named slot', function() { 690 var x = document.createElement('x-slotted'); 691 var d1 = document.createElement('div'); 692 d1.setAttribute('slot', 'container') 693 d1.textContent = 'named slot child'; 694 document.body.appendChild(x); 695 x.appendChild(d1); 696 flush(); 697 assertComputed(d1, '8px'); 698 document.body.removeChild(x); 699 }); 700 701 }); 702 703 suite('dynamic changes', function() { 704 705 test('elements dynamically added/removed from root', function() { 706 var el = document.createElement('x-scoped'); 707 document.body.appendChild(el); 708 flush(); 709 var d = document.createElement('div'); 710 d.classList.add('scoped'); 711 d.textContent = 'Dynamically... Scoped!'; 712 el.shadowRoot.appendChild(d); 713 flush(); 714 assertComputed(d, '4px'); 715 document.body.appendChild(d); 716 flush(); 717 assert.notInclude(d.getAttribute('style-scoped') || '', el.is, 'scoping attribute not removed when added to other root'); 718 assert.notInclude(d.className, el.is, 'scoping class not removed when added to other root'); 719 el.shadowRoot.appendChild(d); 720 flush(); 721 assertComputed(d, '4px'); 722 el.shadowRoot.removeChild(d); 723 flush(); 724 assert.notInclude(d.getAttribute('style-scoped') || '', el.is, 'scoping attribute not removed when removed from root'); 725 assert.notInclude(d.className, el.is, 'scoping class not removed when removed from root'); 726 el.shadowRoot.appendChild(d); 727 flush(); 728 assertComputed(d, '4px'); 729 document.body.removeChild(el); 730 }); 731 732 test('elements dynamically added/removed from host', function() { 733 var el = document.createElement('x-scoped'); 734 document.body.appendChild(el); 735 var d = document.createElement('div'); 736 d.classList.add('scoped'); 737 d.slot = 'blank'; 738 d.textContent = 'Dynamically... unScoped!'; 739 el.appendChild(d); 740 flush(); 741 assertComputed(d, '0px'); 742 el.removeChild(d); 743 flush(); 744 assert.notInclude(d.getAttribute('style-scoped') || '', el.is, 'scoping attribute not removed when added to other root'); 745 assert.notInclude(d.className, el.is, 'scoping class not removed when added to other root'); 746 el.appendChild(d); 747 flush(); 748 assertComputed(d, '0px'); 749 el.removeChild(d); 750 flush(); 751 assert.notInclude(d.getAttribute('style-scoped') || '', el.is, 'scoping attribute not removed when removed from root'); 752 assert.notInclude(d.className, el.is, 'scoping class not removed when removed from root'); 753 el.appendChild(d); 754 flush(); 755 assertComputed(d, '0px'); 756 document.body.removeChild(el); 757 }); 758 759 test('element subtree added via dom api', function() { 760 var el = document.createElement('x-dynamic-scope'); 761 document.body.appendChild(el); 762 flush(); 763 var container = el.shadowRoot.querySelector('#container'); 764 var a = container.querySelector('.added'); 765 assertComputed(a, '17px'); 766 var b = container.querySelector('.sub-added'); 767 assertComputed(b, '18px'); 768 document.body.removeChild(el); 769 }); 770 771 test('changes to class attribute', function() { 772 var el = document.createElement('x-scoped'); 773 el.id = 'el' 774 document.body.appendChild(el); 775 flush(); 776 var d = findNode('el.$.computed'); 777 assertComputed(d, '0px'); 778 d.setAttribute('class', 'computed'); 779 assertComputed(d, '15px'); 780 d.setAttribute('class', '', 'empty class attr does not remove class'); 781 assertComputed(d, '0px'); 782 d.setAttribute('class', 'computed ', 'class attr with space does not apply'); 783 assertComputed(d, '15px'); 784 document.body.removeChild(el); 785 }); 786 787 }); 788 789 suite('misc', function() { 790 791 var el; 792 setup(function() { 793 el = document.createElement('x-scoped'); 794 el.id = 'el'; 795 document.body.appendChild(el); 796 flush(); 797 }); 798 799 teardown(function() { 800 document.body.removeChild(el); 801 }); 802 803 test('keyframes change scope', function(done) { 804 var xKeyframes = findNode('el.$.keyframes'); 805 // Edge 16 does not support CSS Custom Properties in keyframes 806 if (window.ShadyCSS.nativeCss && navigator.userAgent.match(/Edge/)) { 807 this.skip(); 808 } 809 var onAnimationEnd = function() { 810 xKeyframes.removeEventListener('animationend', onAnimationEnd); 811 xKeyframes.removeEventListener('webkitAnimationEnd', onAnimationEnd); 812 assertComputed(xKeyframes, '100px', 'left'); 813 814 xKeyframes = findNode('el.$.keyframes2'); 815 816 onAnimationEnd = function() { 817 xKeyframes.removeEventListener('animationend', onAnimationEnd); 818 xKeyframes.removeEventListener('webkitAnimationEnd', onAnimationEnd); 819 assertComputed(xKeyframes, '200px', 'left'); 820 done(); 821 }; 822 823 xKeyframes.addEventListener('animationend', onAnimationEnd); 824 xKeyframes.addEventListener('webkitAnimationEnd', onAnimationEnd); 825 826 xKeyframes.classList.add('special'); 827 xKeyframes.setAttribute('animated', ''); 828 window.ShadyCSS.ScopingShim.styleElement(xKeyframes); 829 }; 830 xKeyframes.addEventListener('animationend', onAnimationEnd); 831 xKeyframes.addEventListener('webkitAnimationEnd', onAnimationEnd); 832 xKeyframes.setAttribute('animated', ''); 833 assertComputed(xKeyframes, '0px', 'left'); 834 }); 835 836 test('keyframe names are transformed correctly', function(done) { 837 makeElement('scoped-keyframes'); 838 var e = document.createElement('scoped-keyframes'); 839 document.body.appendChild(e); 840 flush(); 841 var target = e.shadowRoot.querySelector('#target'); 842 var onAnimationEnd = function() { 843 assertComputed(target, '10px'); 844 target.removeEventListener('animationend', onAnimationEnd); 845 target.removeEventListener('webkitAnimationEnd', onAnimationEnd); 846 document.body.removeChild(e); 847 done(); 848 }; 849 target.addEventListener('animationend', onAnimationEnd); 850 target.addEventListener('webkitAnimationEnd', onAnimationEnd); 851 e.setAttribute('animate', ''); 852 assertComputed(target, '0px'); 853 }); 854 855 test('attribute inclusive selector and general sibling selectors', function() { 856 var x = document.createElement('x-attr-selector'); 857 x.id = 'x'; 858 document.body.appendChild(x); 859 flush(); 860 assertComputed(findNode('x.$.bar1'), '2px'); 861 assertComputed(findNode('x.$.bar2'), '4px'); 862 assertComputed(findNode('x.$.bar3'), '6px'); 863 document.body.removeChild(x); 864 }); 865 866 test('adjacent sibling selectors', function() { 867 makeElement('x-adjacent-sibling'); 868 var x = document.createElement('x-adjacent-sibling'); 869 x.id = 'x'; 870 document.body.appendChild(x); 871 flush(); 872 assertComputed(findNode('x.$.foo1'), '20px'); 873 assertComputed(findNode('x.$.foo2'), '4px'); 874 assertComputed(findNode('x.$.foo3'), '6px'); 875 document.body.removeChild(x); 876 }) 877 878 test('svg classes are dynamically scoped correctly', function() { 879 var x = document.createElement('x-dynamic-svg'); 880 x.id = 'x'; 881 document.body.appendChild(x); 882 flush(); 883 var container = findNode('x.$.container'); 884 var svg = container.querySelector('.svg'); 885 var computed = getComputedStyle(svg); 886 assert.equal(computed.height, '24px'); 887 assert.equal(computed.width, '24px'); 888 var circle = container.querySelector('#circle'); 889 computed = getComputedStyle(circle); 890 assert.equal(computed['fill-opacity'], '0.5'); 891 document.body.removeChild(x); 892 }); 893 894 test(':host selectors always lowest priority', function() { 895 var priority = findNode('el.$.priority'); 896 assertComputed(priority, '9px'); 897 el.setAttribute('class', 'wide'); 898 assertComputed(priority, '9px'); 899 }); 900 901 test('svg elements properly scoped', function() { 902 if (window.ShadyCSS.nativeShadow) { 903 this.skip(); 904 } 905 var circle = findNode('el.$.circle'); 906 var classes = (circle.getAttribute('class') || '').split(/\s+/); 907 assert.include(classes, 'x-scoped'); 908 assert.include(classes, 'style-scope'); 909 assert.notInclude(classes, 'null'); 910 assertComputed(circle, '1px', 'strokeWidth'); 911 }); 912 913 test('set attribute class has style scoping selectors', function() { 914 if (window.ShadyCSS.nativeShadow) { 915 this.skip(); 916 } 917 var s = findNode('el.$.scopeClass'); 918 var scope = findNode('el.$.scopeClass.$.scope'); 919 assert.isTrue(s.classList.contains('style-scope')); 920 assert.isTrue(s.classList.contains('x-scoped')); 921 s.setAttribute('class', 'foo'); 922 assert.isTrue(s.classList.contains('foo')); 923 assert.isTrue(s.classList.contains('style-scope')); 924 assert.isTrue(s.classList.contains('x-scoped')); 925 // 926 assert.isTrue(scope.classList.contains('style-scope')); 927 assert.isTrue(scope.classList.contains('x-scope-class')); 928 scope.setAttribute('class', 'foo'); 929 assert.isTrue(scope.classList.contains('foo')); 930 assert.isTrue(scope.classList.contains('style-scope')); 931 assert.isTrue(scope.classList.contains('x-scope-class')); 932 }); 933 934 test('specificity of :host selector with class', function() { 935 var e1 = document.createElement('x-specificity'); 936 document.body.appendChild(e1); 937 flush(); 938 assertComputed(e1, '1px'); 939 document.body.removeChild(e1); 940 var e2 = document.createElement('x-specificity'); 941 e2.setAttribute('class', 'bar'); 942 document.body.appendChild(e2); 943 flush(); 944 assertComputed(e2, '2px'); 945 document.body.removeChild(e2); 946 }); 947 948 test('self-use is supported', function() { 949 makeElement('self-test'); 950 var e = document.createElement('self-test'); 951 document.body.appendChild(e); 952 flush(); 953 assertComputed(e.shadowRoot.querySelector('a'), '10px'); 954 document.body.removeChild(e); 955 }); 956 957 test('nth-child selectors work correctly with plusses', function() { 958 makeElement('nth-plus-one'); 959 var e = document.createElement('nth-plus-one'); 960 document.body.appendChild(e); 961 flush(); 962 assertComputed(e.shadowRoot.querySelector('.foo'), 'rgb(255, 0, 0)', 'color'); 963 document.body.removeChild(e); 964 }); 965 966 test(':-webkit-any and :-moz-any selectors are supported', function() { 967 if (navigator.userAgent.match(/Trident|Edge/)) { 968 this.skip(); 969 } 970 makeElement('any-selector'); 971 var e = document.createElement('any-selector'); 972 document.body.appendChild(e); 973 flush(); 974 assertComputed(e.shadowRoot.querySelector('div'), 'rgb(123, 123, 123)', 'color'); 975 assertComputed(e.shadowRoot.querySelector('span'), 'rgb(123, 123, 123)', 'color'); 976 document.body.removeChild(e); 977 }); 978 979 test(':host() sets mixin definitions correctly', function() { 980 makeElement('bad-mixin'); 981 var e = document.createElement('bad-mixin'); 982 document.body.appendChild(e); 983 flush(); 984 assertComputed(e.shadowRoot.querySelector('div'), '0px'); 985 document.body.removeChild(e); 986 }); 987 988 test('trees with elements missing styles render correctly', function() { 989 makeElement('x-parent-skip'); 990 makeElement('x-skip'); 991 makeElement('x-child-skip'); 992 const p = document.createElement('x-parent-skip'); 993 document.body.appendChild(p); 994 flush(); 995 const inner = p.shadowRoot.querySelector('x-skip').shadowRoot.querySelector('x-child-skip').shadowRoot.querySelector('div'); 996 assertComputed(inner, '10px'); 997 document.body.removeChild(p); 998 }); 999 1000 test('trees with elements missing templates render correctly', function() { 1001 makeElement('no-shadow'); 1002 const p = document.createElement('x-parent-skip'); 1003 const n = document.createElement('no-shadow'); 1004 const c = document.createElement('x-child-skip'); 1005 document.body.appendChild(p); 1006 p.shadowRoot.appendChild(n); 1007 n.shadowRoot.appendChild(c); 1008 flush(); 1009 const inner = c.shadowRoot.querySelector('div'); 1010 assertComputed(inner, '10px'); 1011 document.body.removeChild(p); 1012 }) 1013 1014 }); 1015 1016 suite('unscoping', function() { 1017 suiteSetup(function() { 1018 makeElement('shady-unscoped'); 1019 }); 1020 test('styles with "shady-unscoped" attr work in Shady and Shadow', function() { 1021 var el = document.createElement('shady-unscoped'); 1022 document.body.appendChild(el); 1023 flush(); 1024 var div = el.shadowRoot.querySelector('div'); 1025 assertComputed(div, 'rgb(255, 0, 0)', 'color'); 1026 document.body.removeChild(el); 1027 }); 1028 test('styles with "shady-unscoped" attr deduplicate', function(){ 1029 if (window.ShadyCSS.nativeShadow) { 1030 this.skip(); 1031 } 1032 makeElement('shady-unscoped-2'); 1033 var el1 = document.createElement('shady-unscoped'); 1034 var el2 = document.createElement('shady-unscoped-2'); 1035 document.body.appendChild(el1); 1036 document.body.appendChild(el2); 1037 flush(); 1038 assert.equal(document.querySelectorAll('style[shady-unscoped]').length, 1); 1039 document.body.removeChild(el1); 1040 document.body.removeChild(el2); 1041 }); 1042 test('@apply does not work in shady-unscoped', function() { 1043 makeElement('unscoped-apply-user'); 1044 makeElement('unscoped-apply'); 1045 var el = document.createElement('unscoped-apply'); 1046 document.body.appendChild(el); 1047 flush(); 1048 var inner = el.shadowRoot.querySelector('unscoped-apply-user'); 1049 var target = inner.shadowRoot.querySelector('div'); 1050 assertComputed(target, '0px'); 1051 document.body.removeChild(el); 1052 }); 1053 }); 1054 1055})(); 1056</script> 1057</body> 1058</html> 1059