Files
polymer/test/unit/styling-scoped.html
Steve Orvell 4f3be61eb5 Merge pull request #5222 from Polymer/3.x-remove-template-strings
Removing support for returning strings from template getter.
2018-05-08 13:02:27 -07:00

1161 lines
31 KiB
HTML

<!doctype html>
<!--
@license
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<html>
<head>
<meta charset="utf-8">
<script src="../../node_modules/@webcomponents/webcomponentsjs/webcomponents-bundle.js"></script>
<script src="wct-browser-config.js"></script>
<script src="../../node_modules/wct-browser-legacy/browser.js"></script>
<script type="module">
let define = window.customElements.define;
let order = [];
window.customElements.define = function(name, fn, options) {
order.push(name);
return define.call(window.customElements, name, fn, options);
};
customElements.defineOrder = order;
</script>
<style>
#priority[style-scope=x-styled], #priority.style-scope.x-styled {
border: 1px solid black;
}
</style>
</head>
<body>
<dom-module id="x-keyframes">
<template>
<style>
:host {
display: block;
position: relative;
border: 10px solid blue;
left: 0px;
/* Prefix required by Safari <= 8 */
-webkit-animation-duration: 0.3s;
animation-duration: 0.3s;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
:host([animated]) {
/* Prefix required by Safari <= 8 */
-webkit-animation-name: x-keyframes-animation;
animation-name: x-keyframes-animation;
}
/* Prefix required by Safari <= 8 */
@-webkit-keyframes x-keyframes-animation {
0% {
left: var(--keyframes0, 0px);
}
100% {
left: var(--keyframes100, 10px);
}
}
@keyframes x-keyframes-animation {
0% {
left: var(--keyframes0, 0px);
}
100% {
left: var(--keyframes100, 10px);
}
}
</style>
x-keyframes
</template>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
is: 'x-keyframes',
properties: {
animated: {
type: Boolean,
value: false,
reflectToAttribute: true
}
}
});
</script>
</dom-module>
<dom-module id="x-gchild">
<template>
<style>
</style>
<div id="target">x-gchild</div>
</template>
</dom-module>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
is: 'x-gchild'
});
</script>
<dom-module id="x-child">
<template>
<div id="simple">simple</div>
<div id="complex1" class="scoped">complex1</div>
<div id="complex2" selected>complex2</div>
<div id="media">media</div>
<div id="shadow" class="shadowTarget">shadowTarget</div>
<div id="deep" class="deepTarget">deepTarget</div>
<x-gchild id="gchild1"></x-gchild>
<x-gchild id="gchild2" class="wide"></x-gchild>
</template>
</dom-module>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
is: 'x-child',
hostAttributes: {
class: 'nug'
}
});
</script>
<dom-module id="x-child2">
<template>
<style>
:host(.wide) #target{
border: none;
}
</style>
<div id="target">x-child2</div>
</template>
</dom-module>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
is: 'x-child2'
});
</script>
<dom-module id="x-scope-class">
<template>
<div id="scope">Trivial</div>
</template>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
is: 'x-scope-class'
});
</script>
</dom-module>
<dom-module id="x-styled">
<template>
<style>
:host {
display: block;
border: 1px solid orange;
--keyframes100: 100px;
}
:host(.wide) {
border-width: 2px;
}
:host(.wide)::after {
content: '-content-';
};
#keyframes2.special {
--keyframes100: 200px;
}
#simple {
border: 3px solid orange;
}
.scoped, [selected] {
border: 4px solid pink;
}
@media(max-width: 10000px) {
.media {
border: 5px solid brown;
}
}
.container ::slotted(*) {
border: 6px solid navy;
}
#priority {
border: 9px solid orange;
}
.container1 > ::slotted([slot=content1]) {
border: 13px solid navy;
}
.container2 > ::slotted([slot=content2]) {
border: 14px solid navy;
}
.computed {
border: 15px solid orange;
}
.computeda {
border: 20px solid orange;
}
.a.computedb {
border: 16px solid gray;
}
#child {
border: 16px solid tomato;
display: block;
}
svg {
margin-top: 20px;
}
#circle {
fill: seagreen;
stroke-width: 1px;
stroke: tomato;
}
</style>
<slot name="blank"></slot>
<div id="simple">simple</div>
<div id="complex1" class="scoped">complex1</div>
<div id="complex2" selected>complex2</div>
<div id="media" class="media">media</div>
<div class="container1">
<slot name="content1"></slot>
</div>
<div class="container2">
<slot name="content2"></slot>
</div>
<div class="container">
<slot></slot>
</div>
<x-child id="child"></x-child>
<div id="priority">priority</div>
<x-child2 class="wide" id="child2"></x-child2>
<div id="computed" class$="{{computeClass(aClass)}}">Computed</div>
<div>
<div id="computed2" class$="a {{computeClass('computedb')}}">Computed</div>
</div>
<div id="repeatContainer">
<template id="repeat" is="dom-repeat" items="{{items}}">
<a class$="{{aaClass}}">A Computed</a>
</template>
</div>
<svg height="25" width="25">
<circle id="circle" cx="12" cy="12" r="10"></circle>
</svg>
<x-scope-class id="scopeClass"></x-scope-class>
<x-keyframes id="keyframes"></x-keyframes>
<x-keyframes id="keyframes2"></x-keyframes>
</template>
</dom-module>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
is: 'x-styled',
properties: {
items: {value: [{}]}
},
computeClass: function(className) {
return className;
}
});
</script>
<template id="dynamic">
<div class="added">
Added
<div class="sub-added">
Sub-added
</div>
</div>
</template>
<dom-module id="x-dynamic-scope">
<template>
<style>
.added {
border: 17px solid beige;
}
.sub-added {
border: 18px solid #fafafa;
}
</style>
<div id="container"></div>
</template>
</dom-module>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
var doc = window.document;
var dynamic = doc.querySelector('template#dynamic');
Polymer({
is: 'x-dynamic-scope',
ready: function() {
// simulate 3rd party action by using normal dom to add to element.
var dom = document.importNode(dynamic.content, true);
this.$.container.appendChild(dom);
}
});
</script>
<template id="dynamic-style-template">
<style>
:host {
border: 40px solid tomato;
}
</style>
<div>big border</div>
</template>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
var doc = window.document;
var template = doc.querySelector('template#dynamic-style-template');
Polymer({
is: 'x-dynamic-template',
registered: function() {
this._template = template;
}
});
</script>
<template id="svg">
<svg class="svg" viewBox="0 0 24 24">
<circle id="circle" r="12" cx="12" cy="12" />
</svg>
</template>
<dom-module id="x-dynamic-svg">
<template>
<style>
.svg {
height: 24px;
width: 24px;
}
#circle {
fill: red;
fill-opacity: 0.5;
}
</style>
<div id="container"></div>
</template>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
var doc = window.document;
var template = doc.querySelector('template#svg');
Polymer({
is: 'x-dynamic-svg',
ready: function() {
this.scopeSubtree(this.$.container, true);
var dom = document.importNode(template.content, true);
this.$.container.appendChild(dom);
}
});
</script>
</dom-module>
<dom-module id="x-specificity">
<template>
<style>
:host {
border-top: 1px solid red;
}
:host(.bar) {
border-top: 2px solid red;
}
</style>
<slot></slot>
</template>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-specificity'});
</script>
</dom-module>
<custom-style>
<style>
html {
--x-specificity-parent : {
border: 10px solid blue;
};
--x-specificity-nested : {
border: 3px solid red;
};
}
</style>
</custom-style>
<dom-module id="x-specificity-parent">
<template>
<style>
::slotted(:not(template)) {
@apply(--x-specificity-parent);
}
</style>
<slot></slot>
</template>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-specificity-parent'});
</script>
</dom-module>
<dom-module id="x-specificity-nested">
<template>
<style>
:host {
@apply(--x-specificity-nested);
}
</style>
</template>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-specificity-nested'});
</script>
</dom-module>
<custom-style>
<style>
html {
--x-overriding : {
border-top: 1px solid red;
}
}
</style>
</custom-style>
<dom-module id="x-overriding">
<template>
<style>
.red {
@apply(--x-overriding);
}
.green {
@apply(--x-overriding);
border-top: 2px solid green;
}
.red-2 {
border-top: 2px solid green;
@apply(--x-overriding);
}
.blue {
@apply(--x-overriding);
border-top: 3px solid blue;
}
</style>
<div class="red">red</div>
<div class="green">green</div>
<div class="red-2">green-2</div>
<div class="blue">blue</div>
</template>
</dom-module>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({
is: 'x-overriding'
});
</script>
<dom-module id="x-attr-selector">
<template>
<style>
#foo1 ~ #bar1 {
border: 2px solid red;
}
#foo1 ~ #bar1 ~ #foo2[attr~=foo2] ~ #bar2[attr~=bar2] {
border: 4px solid red;
}
#foo1 ~ #bar1 ~ #foo2[attr~=foo2] ~ #bar2[attr~=bar2] ~ #foo3[attr~=foo3][a~=a] ~ #bar3[attr~=bar3][a~=a] {
border: 6px solid red;
}
</style>
<div id="foo1"></div>
<div id="bar1">bar1</div>
<div id="foo2" attr="foo2"></div>
<div id="bar2" attr="bar2">bar2</div>
<div id="foo3" attr="foo3" a="a"></div>
<div id="bar3" attr="bar3" a="a">bar3</div>
</template>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-attr-selector'});
</script>
</dom-module>
<dom-module id="shared-style">
<template>
<style>
:host(x-shared1) {
display: block;
border: 2px solid orange;
}
:host(x-shared2) {
display: block;
border: 4px solid orange;
}
:host(.x-shared1) {
top: 10px;
};
</style>
</template>
</dom-module>
<dom-module id="x-shared1">
<template>
<style include="shared-style"></style>
x-shared1
</template>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-shared1'});
</script>
</dom-module>
<dom-module id="x-shared2">
<template>
<style include="shared-style"></style>
x-shared2
</template>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-shared2'});
</script>
</dom-module>
<dom-module id="x-slotted">
<template>
<style>
::slotted(.auto-content) {
border: 2px solid orange;
}
.bar, ::slotted(.complex-child) {
border: 6px solid navy;
}
#container ::slotted(*) {
border: 8px solid green;
}
</style>
<slot></slot>
<div id="container">
<slot name="container"></slot>
</div>
</template>
<script type="module">
import { Polymer } from '../../polymer-legacy.js';
Polymer({is: 'x-slotted'});
</script>
</dom-module>
<template id="xClass">
<style>
:host {
display: block;
border: 1px solid orange;
}
</style>
</template>
<script type="module">
import { PolymerElement, html } from '../../polymer-element.js';
customElements.define('x-class-no-is', class extends PolymerElement {
static get template() {
return window.xClass;
}
});
customElements.define('x-template-string', class extends PolymerElement {
static get template() {
return html`<style>
:host {
display: block;
border: 1px solid orange;
}
</style>;`;
}
});
</script>
<div class="scoped">no margin</div>
<x-styled>
<div slot="content1">Foo</div>
<div slot="content2">Bar</div>
<div class="content">Content</div>
</x-styled>
<x-styled class="wide"></x-styled>
<x-dynamic-scope></x-dynamic-scope>
<dom-bind id="bind">
<template>
<div id="dom-bind-static" class="static">static</div>
<span id="dom-bind-dynamic" class$="[[dynamic]]">[[dynamic]]</span>
</template>
</dom-bind>
<x-dynamic-svg></x-dynamic-svg>
<x-specificity></x-specificity>
<x-specificity class="bar"></x-specificity>
<x-specificity-parent>
<x-specificity-nested></x-specificity-nested>
</x-specificity-parent>
<x-overriding></x-overriding>
<dom-module id="nested-shared-style">
<template>
<style>
:host {
padding-top: 10px;
}
</style>
</template>
</dom-module>
<dom-module id="x-nested-style">
<template>
<div id="container">
<style include="nested-shared-style">
:host {
display: block;
border: 10px solid black;
}
</style>
</div>
</template>
<script type="module">
import { PolymerElement } from '../../polymer-element.js';
class XNestedStyle extends PolymerElement {
static get is() {return 'x-nested-style';}
}
customElements.define(XNestedStyle.is, XNestedStyle);
</script>
</dom-module>
<dom-module id="x-interleaved-styles">
<template>
<style include="x-nested-style"></style>
<style>
:host {
padding-top: 5px;
}
</style>
<style>
:host {
color: blue;
}
</style>
</template>
<script type="module">
import { PolymerElement } from '../../polymer-element.js';
class XInterleaved extends PolymerElement {
static get is() {return 'x-interleaved-styles';}
}
customElements.define(XInterleaved.is, XInterleaved);
</script>
</dom-module>
<dom-module id="double-shared-style">
<template>
<style>
.double-shared-style {
color: green;
}
</style>
</template>
</dom-module>
<dom-module id="importing-double-shared-style">
<template>
<style include="double-shared-style">
</style>
</template>
</dom-module>
<dom-module id="double-shared-styling-element">
<template>
<style include="importing-double-shared-style double-shared-style"></style>
</template>
<script type="module">
import { PolymerElement } from '../../polymer-element.js';
class DoubleSharedStylingElement extends PolymerElement {
static get is() { return 'double-shared-styling-element'; }
}
customElements.define(DoubleSharedStylingElement.is, DoubleSharedStylingElement);
</script>
</dom-module>
<script type="module">
import { dom } from '../../lib/legacy/polymer.dom.js';
import { flush } from '../../lib/utils/flush.js';
function assertComputed(element, value, property, pseudo) {
var computed = getComputedStyle(element, pseudo);
property = property || 'border-top-width';
if (Array.isArray(value)) {
assert.oneOf(computed[property], value, 'computed style incorrect for ' + property);
} else {
assert.equal(computed[property], value, 'computed style incorrect for ' + property);
}
}
var styled = document.querySelector('x-styled');
var styledWide = document.querySelector('x-styled.wide');
var unscoped = document.querySelector('.scoped');
suite('scoped-styling', function() {
test(':host, :host(...)', function() {
assertComputed(styled, '1px');
assertComputed(styledWide, '2px');
assertComputed(styled, ['', 'none'], 'content', '::after');
assertComputed(styledWide, ['"-content-"', '-content-'], 'content', '::after');
});
test('scoped selectors, simple and complex', function() {
assertComputed(styled.$.simple, '3px');
assertComputed(styled.$.complex1, '4px');
assertComputed(styled.$.complex2, '4px');
});
test('media query scoped selectors', function() {
assertComputed(styled.$.media, '5px');
});
test('upper bound encapsulation', function() {
assertComputed(unscoped, '0px');
});
test('lower bound encapsulation', function() {
assertComputed(styled.$.child.$.simple, '0px');
assertComputed(styled.$.child.$.complex1, '0px');
assertComputed(styled.$.child.$.complex2, '0px');
assertComputed(styled.$.child.$.media, '0px');
});
test('::slotted selectors', function() {
var content = document.querySelector('.content');
var content1 = document.querySelector('[slot=content1]');
var content2 = document.querySelector('[slot=content2]');
assertComputed(content, '6px');
assertComputed(content1, '13px');
assertComputed(content2, '14px');
});
test('auto ::slotted selector', function() {
var x = document.createElement('x-slotted');
var d1 = document.createElement('div');
d1.classList.add('auto-content');
d1.textContent = 'auto-content';
document.body.appendChild(x);
dom(x).appendChild(d1);
flush();
assertComputed(d1, '2px');
});
test('::slotted + child in complex selector', function() {
var x = document.createElement('x-slotted');
var d1 = document.createElement('div');
d1.classList.add('complex-child');
d1.textContent = 'complex-child';
document.body.appendChild(x);
dom(x).appendChild(d1);
flush();
assertComputed(d1, '6px');
});
test('::slotted + named slot', function() {
var x = document.createElement('x-slotted');
var d1 = document.createElement('div');
d1.setAttribute('slot', 'container');
d1.textContent = 'named slot child';
document.body.appendChild(x);
dom(x).appendChild(d1);
flush();
assertComputed(d1, '8px');
});
test('elements dynamically added/removed from root', function() {
var d = document.createElement('div');
d.classList.add('scoped');
d.textContent = 'Dynamically... Scoped!';
dom(styled.root).appendChild(d);
flush();
assertComputed(d, '4px');
dom(document.body).appendChild(d);
flush();
assert.notInclude(d.getAttribute('style-scoped') || '', styled.is, 'scoping attribute not removed when added to other root');
assert.notInclude(d.className, styled.is, 'scoping class not removed when added to other root');
assertComputed(d, '0px');
dom(styled.root).appendChild(d);
flush();
assertComputed(d, '4px');
});
test('elements dynamically added/removed from host', function() {
var d = document.createElement('div');
d.classList.add('scoped');
d.slot = 'blank';
d.textContent = 'Dynamically... unScoped!';
dom(styled).appendChild(d);
flush();
assertComputed(d, '0px');
dom(document.body).appendChild(d);
flush();
assert.notInclude(d.getAttribute('style-scoped') || '', styled.is, 'scoping attribute not removed when added to other root');
assert.notInclude(d.className, styled.is, 'scoping class not removed when added to other root');
dom(styled).appendChild(d);
flush();
assertComputed(d, '0px');
dom(styled).removeChild(d);
flush();
assert.notInclude(d.getAttribute('style-scoped') || '', styled.is, 'scoping attribute not removed when removed from root');
assert.notInclude(d.className, styled.is, 'scoping class not removed when removed from root');
dom(styled).appendChild(d);
flush();
assertComputed(d, '0px');
});
test('keyframes change scope', function(done) {
if (navigator.userAgent.match('Edge') && (!window.ShadyCSS || window.ShadyCSS.nativeCss)) {
// skip test due to missing variable support in keyframes
// https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12084341/
this.skip();
}
var xKeyframes = styled.$.keyframes;
var onAnimationEnd = function() {
xKeyframes.removeEventListener('animationend', onAnimationEnd);
xKeyframes.removeEventListener('webkitAnimationEnd', onAnimationEnd);
assertComputed(xKeyframes, '100px', 'left');
xKeyframes = styled.$.keyframes2;
onAnimationEnd = function() {
xKeyframes.removeEventListener('animationend', onAnimationEnd);
xKeyframes.removeEventListener('webkitAnimationEnd', onAnimationEnd);
assertComputed(xKeyframes, '200px', 'left');
done();
};
xKeyframes.addEventListener('animationend', onAnimationEnd);
xKeyframes.addEventListener('webkitAnimationEnd', onAnimationEnd);
dom(xKeyframes).classList.add('special');
xKeyframes.updateStyles();
xKeyframes.animated = true;
};
xKeyframes.addEventListener('animationend', onAnimationEnd);
xKeyframes.addEventListener('webkitAnimationEnd', onAnimationEnd);
xKeyframes.animated = true;
assertComputed(xKeyframes, '0px', 'left');
});
test('elements with computed classes', function() {
assertComputed(styled.$.computed, '0px');
styled.aClass = 'computed';
assertComputed(styled.$.computed, '15px');
assertComputed(styled.$.computed2, '16px');
});
test('<a> with computed classes dynamically added', function() {
assertComputed(styled.$.repeatContainer.firstElementChild, '0px');
styled.aaClass = 'computeda';
assertComputed(styled.$.repeatContainer.firstElementChild, '20px');
});
test('elements with hostAttributes: class', function() {
assertComputed(styled.$.child, '16px');
});
test('element subtree added via dom api', function() {
var container = document.querySelector('x-dynamic-scope').$.container;
var a = container.querySelector('.added');
assertComputed(a, '17px');
var b = container.querySelector('.sub-added');
assertComputed(b, '18px');
});
test('styles in dynamically selected template', function() {
var el = document.createElement('x-dynamic-template');
document.body.appendChild(el);
if (el.shadowRoot) {
// style properly removed
assert.notOk(el.querySelector('style'));
}
assertComputed(el, '40px');
document.body.removeChild(el);
});
test('attribute inclusive selector and general sibling selectors', function() {
var e = document.createElement('x-attr-selector');
document.body.appendChild(e);
flush();
assertComputed(e.$.bar1, '2px');
assertComputed(e.$.bar2, '4px');
assertComputed(e.$.bar3, '6px');
});
test('svg classes are dynamically scoped correctly', function() {
var container = document.querySelector('x-dynamic-svg').$.container;
var svg = container.querySelector('.svg');
var computed = getComputedStyle(svg);
assert.equal(computed.height, '24px');
assert.equal(computed.width, '24px');
var circle = container.querySelector('#circle');
computed = getComputedStyle(circle);
assert.equal(computed['fill-opacity'], '0.5');
});
test(':host with element tag selector', function() {
var s1 = document.createElement('x-shared1');
document.body.appendChild(s1);
assertComputed(s1, '2px');
var s2 = document.createElement('x-shared2');
document.body.appendChild(s2);
assertComputed(s2, '4px');
});
test(':host with superset of element tag selector does not leak', function() {
var t = document.createElement('div');
t.textContent = 'host leak test';
t.classList.add('x-shared1');
document.body.appendChild(t);
assertComputed(t, 'auto', 'top');
});
test(':host(...) with non-matching type selector does not leak', function() {
var t = document.createElement('x-shared1x-shared2');
t.textContent = ':host(non-matching-type-selector)';
document.body.appendChild(t);
assertComputed(t, '0px');
t = document.createElement('x-shared2x-shared1');
t.textContent = ':host(non-matching-type-selector)';
document.body.appendChild(t);
assertComputed(t, '0px');
});
test('static is not required for scoping styling', function() {
var e = document.createElement('x-class-no-is');
document.body.appendChild(e);
assertComputed(e, '1px');
});
test('template string has scoped styling', function() {
var e = document.createElement('x-template-string');
document.body.appendChild(e);
assertComputed(e, '1px');
});
test('styles work correctly when not direct children of the template', function() {
var e = document.createElement('x-nested-style');
document.body.appendChild(e);
assertComputed(e, '10px');
assertComputed(e, '10px', 'padding-top');
});
test('interleaved styles and styles with includes work as expected', function() {
var e = document.createElement('x-interleaved-styles');
document.body.appendChild(e);
assertComputed(e, '5px', 'padding-top');
});
});
suite('double including style sheets', function() {
let el;
setup(function() {
el = document.createElement('double-shared-styling-element');
document.body.appendChild(el);
});
teardown(function() {
document.body.removeChild(el);
});
test('only includes style modules once', function() {
const style = el.shadowRoot.querySelector('style');
// We cant use the regular "does a sub-node have the correct style",
// because we actually need to assert on the actual style content.
// In native shadow dom, the style element resides in the shadowRoot,
// but in shadyDOM it has moved to the head and the selector has been altered.
if (style) {
assert.equal(style.textContent, `.double-shared-style {
color: green;
}`, 'There should be only one class selector in this style element');
} else {
assert.equal(document.head.querySelector('[scope="double-shared-styling-element"]').textContent,
`.double-shared-style.double-shared-styling-element {
color: green;
}`);
}
});
});
if (window.ShadyDOM) {
suite('scoped-styling-shady-only', function() {
test('element style precedence below document styles', function() {
assertComputed(styledWide.$.priority, '1px');
});
test('styles shimmed in registration order', function() {
var regList = customElements.defineOrder;
function regIndex(styleScope) {
for (var i=0, r; (r=regList[i]); i++) {
if (styleScope.match(new RegExp(r + '\\-?\\d*$'))) {
return i;
}
}
}
var s$ = document.head.querySelectorAll('style[scope]');
for (var i=0, scope, prevScope, n=0, o=0; i<s$.length; i++) {
scope = s$[i].getAttribute('scope');
n = regIndex(scope);
assert.isTrue(n >= o, 'style not in registration order, expected `' +
scope + '` to be before `' + prevScope + '`');
o = n;
prevScope = scope;
}
});
test('svg elements properly scoped', function() {
assert.include(styled.$.circle.getAttribute('class'), 'x-styled');
assert.include(styled.$.circle.getAttribute('class'), 'style-scope');
assert.notInclude(styled.$.circle.getAttribute('class'), 'null');
assertComputed(styled.$.circle, '1px', 'strokeWidth');
});
test('dom-bind content is unscoped', function() {
var e = document.querySelector('#bind');
e.dynamic = 'dynamic';
var staticClassEl = document.querySelector('#dom-bind-static');
assert.equal(staticClassEl.className, 'static');
var dynamicClassEl = document.querySelector('#dom-bind-dynamic');
assert.equal(dynamicClassEl.className, 'dynamic');
});
test('serializeValueToAttribute for class', function() {
var s = styled.$.scopeClass;
var scope = s.$.scope;
assert.isTrue(s.classList.contains('style-scope'));
assert.isTrue(s.classList.contains('x-styled'));
s.serializeValueToAttribute('foo', 'class');
assert.isTrue(s.classList.contains('foo'));
assert.isTrue(s.classList.contains('style-scope'));
assert.isTrue(s.classList.contains('x-styled'));
//
assert.isTrue(scope.classList.contains('style-scope'));
assert.isTrue(scope.classList.contains('x-scope-class'));
s.serializeValueToAttribute('foo', 'class', scope);
assert.isTrue(scope.classList.contains('foo'));
assert.isTrue(scope.classList.contains('style-scope'));
assert.isTrue(scope.classList.contains('x-scope-class'));
});
test('specificity of :host selector with class', function() {
assertComputed(document.querySelector('x-specificity'), '1px');
assertComputed(document.querySelector('x-specificity.bar'), '2px');
});
test('specificity of ::slotted :not(template) selector', function() {
assertComputed(document.querySelector('x-specificity-nested'), '10px');
});
test('overwriting mixin properties', function() {
var el = document.querySelector('x-overriding');
assertComputed(el.shadowRoot.querySelector('.red'), '1px');
assertComputed(el.shadowRoot.querySelector('.green'), '2px');
assertComputed(el.shadowRoot.querySelector('.red-2'), '1px');
assertComputed(el.shadowRoot.querySelector('.blue'), '3px');
});
test('dynamically scope element class on add/remove', function () {
var el = document.createElement('x-scope-class');
document.body.appendChild(el);
flush();
var div = document.createElement('div');
el.shadowRoot.appendChild(div);
flush();
assert.isTrue(div.classList.contains('style-scope'));
assert.isTrue(div.classList.contains('x-scope-class'));
el.shadowRoot.appendChild(div);
flush();
document.body.removeChild(el);
});
test('dynamically scope element class on setAttribute class', function () {
var el = document.createElement('x-scope-class');
document.body.appendChild(el);
flush();
var div = document.createElement('div');
el.shadowRoot.appendChild(div);
flush();
div.setAttribute('class', 'foo');
assert.isTrue(div.classList.contains('foo'));
assert.isTrue(div.classList.contains('style-scope'));
assert.isTrue(div.classList.contains('x-scope-class'));
el.shadowRoot.appendChild(div);
flush();
document.body.removeChild(el);
});
test('dynamically scope element class on set className', function () {
var el = document.createElement('x-scope-class');
document.body.appendChild(el);
flush();
var div = document.createElement('div');
el.shadowRoot.appendChild(div);
flush();
div.className = 'foo';
assert.isTrue(div.classList.contains('foo'));
assert.isTrue(div.classList.contains('style-scope'));
assert.isTrue(div.classList.contains('x-scope-class'));
el.shadowRoot.appendChild(div);
flush();
document.body.removeChild(el);
});
});
}
</script>
</body>
</html>