blob: e94fc2b309a30c86548a7430f8b746b2f26c0f53 [file] [log] [blame]
<!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">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
<script>
WCT = {waitFor: function (cb) {HTMLImports.whenReady(cb)}}
</script>
<script src="./test-flags.js"></script>
<script src="../node_modules/wct-browser-legacy/browser.js"></script>
<script src="../node_modules/@webcomponents/webcomponents-platform/webcomponents-platform.js"></script>
<script src="../node_modules/es6-promise/dist/es6-promise.auto.min.js"></script>
<script src="../node_modules/@webcomponents/template/template.js"></script>
<script src="../node_modules/@webcomponents/html-imports/html-imports.min.js"></script>
<script src="../node_modules/@webcomponents/shadydom/shadydom.min.js"></script>
<script src="../node_modules/@webcomponents/custom-elements/custom-elements.min.js"></script>
<script src="../scoping-shim.min.js"></script>
<script src="../apply-shim.min.js"></script>
<script src="../custom-style-interface.min.js"></script>
<script src="module/generated/make-element.js"></script>
<script src="module/generated/custom-style-element.js"></script>
</head>
<body>
<custom-style>
<style>
x-container, x-sample, x-sample-dynamic, x-container-dynamic {
display: block;
padding: 10px;
margin: 10px;
border: 1px solid black;
}
.target {
background-color: rgb(0, 255, 0);
}
</style>
</custom-style>
<template id="x-sample">
<style>
.target {
background-color: rgb(255, 0, 0);
}
</style>
<h2></h2>
<p>here .target elements are red</p>
<div class="target">I'm red</div>
<template id="renderer">
<div class="target"></div>
</template>
</template>
<template id="x-container">
<style>
.target {
background-color: rgb(123, 123, 123);
}
</style>
<h1>x-container</h1>
<p>here .target elements are gray</p>
<div class="target">I'm gray</div>
<slot></slot>
</template>
<h2>body</h2>
<p>here .target elements are green</p>
<div class="target">I'm green</div>
<x-sample id="inBody"></x-sample>
<x-sample id="inContainer"></x-sample>
<x-container></x-container>
<template id="x-dynamic">
<style>
span {
background-color: rgb(123, 123, 123);
}
</style>
<div id="container">
</div>
</template>
<x-dynamic></x-dynamic>
<template id="out-of-band">
<style>
div {
color: var(--foo);
}
</style>
<div>oob shadowed</div>
</template>
<template id="oob-parent">
<style>
out-of-band {
--foo: rgb(0, 0, 255);
}
</style>
<out-of-band></out-of-band>
</template>
<template id="oob-other-parent">
<style>
out-of-band {
--foo: rgb(255, 0, 0);
}
</style>
</template>
<oob-parent></oob-parent>
<oob-other-parent></oob-other-parent>
<template id="x-sample-dynamic">
<style>
.target {
background-color: rgb(255, 0, 0);
}
</style>
<h2></h2>
<p>here .target elements are red</p>
<div class="target">I'm red</div>
<template id="renderer">
<div class="target"></div>
</template>
</template>
<template id="x-container-dynamic">
<style>
.target {
background-color: rgb(123, 123, 123);
}
</style>
<h1>x-container</h1>
<p>here .target elements are gray</p>
<div class="target">I'm gray</div>
<slot></slot>
</template>
<x-container-dynamic></x-container-dynamic>
<template id="css-build" css-build="shady">
<style>:host{@apply --fake;}</style>
<div class="style-scope css-build"></div>
</template>
<template id="css-build-comment"><!--css-build:shady-->
<style>:host{@apply --fake;}</style>
<div class="style-scope css-build-comment"></div>
</template>
<script>
suite('Dynamic Scoping', () => {
function stamp(parent, host) {
let template = host.shadowRoot.querySelector('template#renderer')
let el = template.content.cloneNode(true).querySelector('div.target');
el.textContent = `stamped by ${host.id}`;
parent.appendChild(el);
return el;
}
test('DOM is scoped correctly when stamped from an element into document', (done) => {
let inBody = document.querySelector('x-sample#inBody');
let inContainer = document.querySelector('x-sample#inContainer');
makeElement('x-sample', function() {
this.shadowRoot.querySelector('h2').textContent = `${this.id}`;
});
makeElement('x-container');
setTimeout(() => {
let body = stamp(document.body, inBody);
let container = stamp(document.querySelector('x-container').shadowRoot, inContainer);
requestAnimationFrame(() => {
assert.equal(getComputedStyle(body).backgroundColor, 'rgb(0, 255, 0)');
assert.equal(getComputedStyle(container).backgroundColor, 'rgb(123, 123, 123)')
done();
});
}, 300);
});
test('DOM is scoped correctly when created dynamically inside a scoped container', (done) => {
makeElement('x-dynamic', function() {
let div = this.shadowRoot.querySelector('#container');
let newDiv = div.cloneNode(true);
let span = document.createElement('span');
span.textContent = 'created dynamically';
newDiv.appendChild(span);
this.shadowRoot.appendChild(newDiv);
requestAnimationFrame(() => {
assert.equal(getComputedStyle(span).backgroundColor, 'rgb(123, 123, 123)');
done();
})
});
});
test('moving a custom element between scopes recalculates correctly', function(done) {
makeElement('out-of-band');
makeElement('oob-parent');
makeElement('oob-other-parent');
let parent = document.querySelector('oob-parent');
let newParent = document.querySelector('oob-other-parent');
let oob = parent.shadowRoot.querySelector('out-of-band');
let shadowDiv = oob.shadowRoot.querySelector('div');
newParent.shadowRoot.appendChild(oob);
requestAnimationFrame(() => {
assert.equal(getComputedStyle(shadowDiv).getPropertyValue('color').trim(), 'rgb(255, 0, 0)');
done();
});
})
function makeDynamicElement(name, connectedCallback) {
let template = document.querySelector(`template#${name}`);
if (template && window.ShadyCSS) {
window.ShadyCSS.prepareTemplate(template, name);
}
window.customElements.define(name, class extends window.HTMLElement {
constructor() {
super();
if (template && !this.shadowRoot) {
this.attachShadow({mode: 'open'});
this.shadowRoot.appendChild(document.importNode(template.content, true));
}
}
connectedCallback() {
window.ShadyCSS && window.ShadyCSS.styleElement(this);
if (connectedCallback) {
connectedCallback.call(this);
}
}
});
}
test('Nested DOM is scoped correctly when created dynamically inside a dynamic container', function(done) {
if (!window.customElements.polyfillWrapFlushCallback && window.ShadyDOM && window.ShadyDOM.inUse) {
/*
* This test is flaky if running with native custom elements and polyfill shadowdom,
* as the shadowdom polyfill may render inside of the constructor and create children,
* which is not allowed in the CE spec.
*/
this.skip();
}
makeDynamicElement('x-container-dynamic');
makeDynamicElement('x-sample-dynamic');
const dynamicDiv = document.createElement('div');
dynamicDiv.classList.add('target');
dynamicDiv.innerText = 'I was created dynamically';
const dynamicSample = document.createElement('x-sample-dynamic');
const dynamicContainer = document.createElement('x-container-dynamic');
dynamicSample.shadowRoot.appendChild(dynamicDiv);
dynamicContainer.shadowRoot.appendChild(dynamicSample);
document.querySelector('x-container-dynamic').shadowRoot.appendChild(dynamicContainer);
requestAnimationFrame(() => {
dynamicSample.shadowRoot.querySelectorAll('div.target').forEach((target) =>
assert.equal(getComputedStyle(target).backgroundColor,'rgb(255, 0, 0)'));
done();
});
});
test('templates marked with "css-build" will be left alone', function() {
makeElement('css-build');
const template = document.querySelector('template#css-build');
const div = template.content.querySelector('div');
const divClasses = Array.from(div.classList);
assert.includeMembers(divClasses, ['style-scope', 'css-build']);
const style = template.content.querySelector('style');
if (style) {
assert.match(style.textContent.trim(), /:host\s*{\s*@apply --fake;\s*}/);
}
});
test('templates with css-build comments will be left alone', function() {
const template = document.querySelector('template#css-build-comment');
const buildComment = template.content.firstChild;
assert.instanceOf(buildComment, Comment, 'first child of template content should be a Comment');
makeElement('css-build-comment');
const div = template.content.querySelector('div');
const divClasses = Array.from(div.classList);
assert.includeMembers(divClasses, ['style-scope', 'css-build-comment']);
const style = template.content.querySelector('style');
if (style) {
assert.match(style.textContent.trim(), /:host\s*{\s*@apply --fake;\s*}/);
}
assert.equal(buildComment.parentNode, null, 'build commment should have been removed');
});
});
</script>
</body>
</html>