UNPKG

@polymer/polymer

Version:

The Polymer library makes it easy to create your own web components. Give your element some markup and properties, and then use it on a site. Polymer provides features like dynamic templates and data binding to reduce the amount of boilerplate you need to

485 lines (405 loc) 16.2 kB
<!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="../../../webcomponentsjs/webcomponents-lite.js" register="true" shadydom="true"></script> <script src="../../../web-component-tester/browser.js"></script> <link rel="import" href="../../polymer.html"> </head> <body> <template></template> <script> // TODO(sorvell): cannot register element in main document under polyfill. HTMLImports.whenReady(function() { var template = document.querySelector('template'); Polymer({ is: 'x-content-test', _template: template }); }); /* * Test the `<slot>` element distribution algorithm by verifying the * resulting composed tree structure. */ function testRender(descr, hostInnerHtml, shadowRootHtml, expectedHtml) { test(descr, function() { // Create an instance of the test element. var host = document.createElement('x-content-test'); // Populate the initial pool of light DOM children. host.innerHTML = hostInnerHtml; document.body.appendChild(host); // Pretend we're stamping the template contents. if (shadowRootHtml) { host.shadowRoot.innerHTML = shadowRootHtml; } // Invoke distribution and verify the resulting tree. ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), expectedHtml); document.body.removeChild(host); }); test(descr + ' fragment', function() { // Create an instance of the test element. var host = document.createElement('x-content-test'); // Populate the initial pool of light DOM children. host.innerHTML = hostInnerHtml; document.body.appendChild(host); // Pretend we're stamping the template contents. var div = document.createElement('div'); div.innerHTML = shadowRootHtml; var frag = document.createDocumentFragment(); while (div.firstChild) { frag.appendChild(div.firstChild); } host.shadowRoot.appendChild(frag); // Invoke distribution and verify the resulting tree. ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), expectedHtml); document.body.removeChild(host); }); } testRender('Empty shadow', 'abc', '', ''); testRender('Simple shadow', 'abc', 'def', 'def'); testRender('Fallback shadow', 'abc', '<slot name="xxx">fallback</name>', 'fallback'); testRender('Fallback shadow, empty host', '', '<slot name="xxx">fallback</name>', 'fallback'); testRender('Content', 'abc', '<slot>fallback</slot>', 'abc'); testRender('Content before', 'abc', 'before<slot>fallback</slot>', 'beforeabc'); testRender('Content after', 'abc', '<slot>fallback</slot>after', 'abcafter'); suite('render content', function() { testRender('no select', '<a href="">Link</a> <b>bold</b>', '<slot></slot>', '<a href="">Link</a> <b>bold</b>'); testRender('select ""', '<a href="">Link</a> <b>bold</b>', '<slot></slot>', '<a href="">Link</a> <b>bold</b>'); testRender('slot a', '<a slot="a">a</a> <a slot="b">b</a>', '<slot name="a"></slot>', '<a slot="a">a</a>'); testRender('slot b a', '<a slot="a">a</a> <a slot="b">b</a>', '<slot name="b"></slot><slot name="a"></slot>', '<a slot="b">b</a><a slot="a">a</a>'); testRender('slot b a 2', '<a slot="a">a</a> <a slot="b">b</a> <a slot="b">c</a>', '<slot name="b"></slot><slot name="a"></slot>', '<a slot="b">b</a><a slot="b">c</a><a slot="a">a</a>'); testRender('slot c catchall', '<span>a</span><span>b</span><span slot="c">c</span><span>d</span>', '<slot name="c"></slot><slot></slot>', '<span slot="c">c</span><span>a</span><span>b</span><span>d</span>'); }); test('Reproject', function() { var host = document.createElement('x-content-test'); document.body.appendChild(host); host.innerHTML = '<a></a>'; // pre-distirbution grab first composed node. var a = getComposedChildAtIndex(host, 0); host.shadowRoot.innerHTML = '<x-content-test id="p"></x-content-test>'; // force upgrade on polyfilled browsers var p = host.shadowRoot.firstChild; p.innerHTML = '<b slot="b"></b><slot slot="a"></slot>'; var b = p.firstChild; var content = p.lastChild; p.shadowRoot.innerHTML = 'a: <slot name="a"></slot>b: <slot name="b"></slot>'; var textNodeA = p.shadowRoot.firstChild; var contentA = p.shadowRoot.childNodes[1]; var textNodeB = p.shadowRoot.childNodes[2]; var contentB = p.shadowRoot.childNodes[3]; function testRender() { ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<x-content-test id="p">a: <a></a>b: <b slot="b"></b></x-content-test>'); assertArrayEqual(host.childNodes, [a]); assert.strictEqual(a.parentNode, host); assertArrayEqual(host.shadowRoot.childNodes, [p]); assert.strictEqual(p.parentNode, host.shadowRoot); assertArrayEqual(p.childNodes, [b, content]); assert.strictEqual(b.parentNode, p); assert.strictEqual(content.parentNode, p); assertArrayEqual(p.shadowRoot.childNodes, [textNodeA, contentA, textNodeB, contentB]); } testRender(); testRender(); document.body.removeChild(host); }); suite('Mutate light DOM', function() { var host; setup(function() { host = document.createElement('x-content-test'); document.body.appendChild(host); }); teardown(function() { document.body.removeChild(host); }); test('removeAllChildNodes - mutate host', function() { host.innerHTML = '<a>Hello</a>'; host.shadowRoot.innerHTML = '<slot>fallback</slot>'; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<a>Hello</a>'); host.firstChild.textContent = ''; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<a></a>'); host.innerHTML = ''; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), 'fallback'); }); test('removeAllChildNodes - mutate shadow', function() { host.innerHTML = '<a>Hello</a>'; host.shadowRoot.innerHTML = '<slot></slot><b>after</b>'; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b>after</b>'); host.shadowRoot.childNodes[1].textContent = ''; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b></b>'); host.shadowRoot.innerHTML = ''; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), ''); }); test('removeAllChildNodes - mutate shadow fallback', function() { host.innerHTML = '<a>Hello</a>'; host.shadowRoot.innerHTML = '<slot name="xxx"><b>fallback</b></slot>'; var b = host.shadowRoot.firstChild.firstChild; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<b>fallback</b>'); b.textContent = ''; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<b></b>'); host.shadowRoot.firstChild.innerHTML = ''; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), ''); host.shadowRoot.innerHTML = ''; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), ''); }); test('removeChild - mutate host', function() { host.innerHTML = '<a>Hello</a>'; host.shadowRoot.innerHTML = '<slot>fallback</slot>'; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<a>Hello</a>'); host.firstChild.removeChild(host.firstChild.firstChild); ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<a></a>'); host.innerHTML = ''; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), 'fallback'); }); test('removeChild - mutate host 2', function() { host.innerHTML = '<a></a><b></b>'; var a = getComposedChildAtIndex(host, 0); var b = getComposedChildAtIndex(host, 1); host.shadowRoot.innerHTML = '<slot>fallback</slot>'; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<a></a><b></b>'); host.removeChild(b); ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<a></a>'); host.removeChild(a); ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), 'fallback'); }); test('removeChild - mutate shadow', function() { host.innerHTML = '<a>Hello</a>'; host.shadowRoot.innerHTML = '<slot></slot><b>after</b>'; var b = host.shadowRoot.lastChild; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b>after</b>'); b.removeChild(b.firstChild); ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b></b>'); host.shadowRoot.removeChild(b); ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<a>Hello</a>'); host.shadowRoot.removeChild(host.shadowRoot.firstChild); ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), ''); }); test('setAttribute slot', function() { host.innerHTML = '<a slot="a">Hello</a><b slot="b">World</b>'; host.shadowRoot.innerHTML = '<slot name="b">fallback b</slot>' + '<slot name="a">fallback a</slot>'; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<b slot="b">World</b><a slot="a">Hello</a>'); host.shadowRoot.firstChild.setAttribute('name', 'xxx'); ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), 'fallback b<a slot="a">Hello</a>'); host.shadowRoot.firstChild.setAttribute('name', ''); host.shadowRoot.lastChild.setAttribute('name', ''); ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), 'fallback bfallback a'); }); test('appendChild - mutate host', function() { host.innerHTML = '<a>Hello</a>'; host.shadowRoot.innerHTML = '<slot></slot>'; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<a>Hello</a>'); var b = document.createElement('b'); host.appendChild(b); ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b></b>'); }); test('appendChild - mutate shadow', function() { host.innerHTML = '<a>Hello</a>'; host.shadowRoot.innerHTML = '<slot></slot>'; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<a>Hello</a>'); var b = document.createElement('b'); host.shadowRoot.appendChild(b); ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b></b>'); }); test('insertBefore - mutate host', function() { host.innerHTML = '<a>Hello</a>'; var a = getComposedChildAtIndex(host, 0); host.shadowRoot.innerHTML = '<slot></slot>'; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<a>Hello</a>'); var b = document.createElement('b'); host.insertBefore(b, a); ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<b></b><a>Hello</a>'); }); test('insertBefore - mutate shadow', function() { host.innerHTML = '<a>Hello</a>'; host.shadowRoot.innerHTML = '<slot></slot>'; var content = host.shadowRoot.firstChild; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<a>Hello</a>'); var b = document.createElement('b'); host.shadowRoot.insertBefore(b, content); ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<b></b><a>Hello</a>'); }); test('replaceChild - mutate host', function() { host.innerHTML = '<a>Hello</a>'; host.shadowRoot.innerHTML = '<slot></slot>'; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<a>Hello</a>'); var b = document.createElement('b'); host.replaceChild(b, host.firstChild); ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<b></b>'); }); test('replaceChild - mutate shadow', function() { host.innerHTML = '<a>Hello</a>'; host.shadowRoot.innerHTML = '<slot></slot>'; var content = host.shadowRoot.firstChild; ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<a>Hello</a>'); var b = document.createElement('b'); host.shadowRoot.replaceChild(b, content); ShadyDOM.flush(); assert.strictEqual(getComposedHTML(host), '<b></b>'); }); test('querySelectorAll (shadowRoot)', function() { host.innerHTML = '<div id="main"></div>'; host.shadowRoot.innerHTML = '<slot></slot><span id="main"></span>' + '<x-content-test></x-content-test>'; // force upgrade on polyfilled browsers ShadyDOM.flush(); var hostLocalMain = getComposedChildAtIndex(host.shadowRoot, 1); var child = getComposedChildAtIndex(host.shadowRoot, 100); child.innerHTML = '<div id="sub"></div>'; var childLightSub = getComposedChildAtIndex(child, 0); child.shadowRoot.innerHTML = '<slot></slot><span id="sub"></span>'; var childLocalSub = child.shadowRoot.lastChild; ShadyDOM.flush(); assert.deepEqual(host.root.querySelectorAll('span#main'), [hostLocalMain]); assert.deepEqual(host.root.querySelectorAll('div#sub'), [childLightSub]); assert.deepEqual(child.root.querySelectorAll('span#sub'), [childLocalSub]); }); test('querySelectorAll (light dom)', function() { host.innerHTML = '<div id="main"></div>'; var hostLightMain = getComposedChildAtIndex(host, 0); host.shadowRoot.innerHTML = '<slot></slot><span id="main"></span>' + '<x-content-test></x-content-test>'; var child = getComposedChildAtIndex(host.shadowRoot, 100); child.innerHTML = '<div id="sub"></div>'; var childLightSub = getComposedChildAtIndex(child, 100) ; child.shadowRoot.innerHTML = '<slot></slot><span id="sub"></span>'; ShadyDOM.flush(); assert.deepEqual(host.querySelectorAll('div#main'), [hostLightMain]); assert.deepEqual(host.querySelectorAll('#sub'), []); assert.deepEqual(child.querySelectorAll('div#sub'), [childLightSub]); }); }); suite('Add shadowRoot to element with childNodes', function() { var el; setup(function() { el = document.createElement('div'); el.testHTML = '<div slot="a">hi</div>'; el.innerHTML = el.testHTML; el.attachShadow({mode: 'open'}); }); test('empty root', function() { ShadyDOM.flush(); assert.equal(getComposedHTML(el), ''); }); test('simple root', function() { var shadow = '<div>shadow</div>'; el.shadowRoot.innerHTML = shadow; ShadyDOM.flush(); assert.equal(getComposedHTML(el), shadow); }); test('slot matching', function() { var shadow = '<div><slot name="a"></slot></div>'; el.shadowRoot.innerHTML = shadow; ShadyDOM.flush(); assert.equal(getComposedHTML(el), '<div>' + el.testHTML + '</div>'); }); test('slot not matching', function() { var shadow = '<div><slot name="b"></slot></div>'; el.shadowRoot.innerHTML = shadow; ShadyDOM.flush(); assert.equal(getComposedHTML(el), '<div></div>'); }); }); function getEffectiveChildNodes(node) { var list = []; var c$ = node.childNodes; for (var i=0, l=c$.length, c; (i<l) && (c=c$[i]); i++) { if (c.localName && (c.localName === 'content' || c.localName === 'slot')) { list = list.concat(c.assignedNodes({flatten: true})); } else { list.push(c); } } return list; } function getComposedHTML(node) { // Ignore shady CSS scoping return ShadyDOM.nativeTree.innerHTML(node).replace(/ class="[^"]*"/g, ''); } function getComposedChildAtIndex(node, index) { var c$ = getEffectiveChildNodes(node); if (c$) { index = index || 0; index = Math.max(0, Math.min(index, c$.length-1)); return c$[index]; } } function assertArrayEqual(a, b, msg) { assert.equal(a.length, b.length, msg); for (var i = 0; i < a.length; i++) { assert.equal(a[i], b[i], msg); } } </script> </body> </html>