Files
polymer/test/unit/shady.html
2015-04-17 19:23:39 -07:00

491 lines
17 KiB
HTML

<!doctype html>
<!--
@license
Copyright (c) 2014 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"></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.
var registered = false;
function registerTestElement() {
if (registered) return;
var template = document.querySelector('template');
Polymer({
is: 'x-content-test',
_useContent: true,
_template: template
});
registered = true;
}
/**
* Test the `<content>` element distribution algorithm by verifying the
* resulting composed tree structure.
*/
function testRender(descr, hostInnerHtml, shadowRootHtml, expectedHtml) {
test(descr, function() {
registerTestElement();
// 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;
setInnerHTML(host, hostInnerHtml);
syncLightDOM(host);
// Pretend we're stamping the template contents.
setRootInnerHTML(host.shadyRoot, shadowRootHtml);
// Invoke distribution and verify the resulting tree.
host.distributeContent();
assert.strictEqual(getComposedHTML(host), expectedHtml);
});
}
testRender('Empty shadow', 'abc', '', '');
testRender('Simple shadow', 'abc', 'def', 'def');
testRender('Fallback shadow', 'abc',
'<content select="xxx">fallback</content>', 'fallback');
testRender('Content', 'abc',
'<content>fallback</content>', 'abc');
testRender('Content before', 'abc',
'before<content>fallback</content>', 'beforeabc');
testRender('Content after', 'abc',
'<content>fallback</content>after', 'abcafter');
suite('render content', function() {
testRender('no select', '<a href="">Link</a> <b>bold</b>',
'<content></content>',
'<a href="">Link</a> <b>bold</b>');
testRender('select ""', '<a href="">Link</a> <b>bold</b>',
'<content select=""></content>',
'<a href="">Link</a> <b>bold</b>');
testRender('select *', '<a href="">Link</a> <b>bold</b>',
'<content select="*"></content>',
'<a href="">Link</a><b>bold</b>');
testRender('select .a',
'<a class="a">a</a> <a class="b">b</a>',
'<content select=".a"></content>',
'<a class="a">a</a>');
testRender('select .b .a',
'<a class="a">a</a> <a class="b">b</a>',
'<content select=".b"></content><content select=".a"></content>',
'<a class="b">b</a><a class="a">a</a>');
testRender('select .b .a 2',
'<a class="a">a</a> <a class="b">b</a> <a class="b">c</a>',
'<content select=".b"></content><content select=".a"></content>',
'<a class="b">b</a><a class="b">c</a><a class="a">a</a>');
testRender('select [c] *',
'<span>a</span><span>b</span><span c>c</span><span>d</span>',
'<content select="[c]"></content><content></content>',
'<span c="">c</span><span>a</span><span>b</span><span>d</span>');
});
test('Reproject', function() {
registerTestElement();
var host = document.createElement('x-content-test');
setInnerHTML(host, '<a></a>');
var a = host.firstChild;
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<x-content-test id="p"></x-content-test>');
// force upgrade on polyfilled browsers
var p = host.shadyRoot.firstChild;
CustomElements.upgrade(p);
setInnerHTML(p, '<b></b><content></content>');
syncLightDOM(p);
//p.innerHTML = '<b></b><content></content>';
updateRootInsertionPoints(host.shadyRoot);
var b = p.firstChild;
var content = p.lastChild;
syncLightDOM(p);
setRootInnerHTML(p.shadyRoot,
'a: <content select=a></content>b: <content select=b></content>');
var textNodeA = p.shadyRoot.firstChild;
var contentA = p.shadyRoot.childNodes[1];
var textNodeB = p.shadyRoot.childNodes[2]
var contentB = p.shadyRoot.childNodes[3];
function testRender() {
// Simulate the correct ordering as "ready" would fire.
host.distributeContent();
// NOTE: needed only for this imperative test that needs
// to simulate distribution from `shadyRoot`
p.distributeContent();
assert.strictEqual(getComposedHTML(host),
'<x-content-test id="p">a: <a></a>b: <b></b></x-content-test>');
assertArrayEqual(host.lightChildren, [a]);
assert.strictEqual(a.lightParent, host);
assertArrayEqual(host.shadyRoot.lightChildren, [p]);
assert.strictEqual(p.lightParent, host.shadyRoot);
assertArrayEqual(p.lightChildren, [b, content]);
assert.strictEqual(b.lightParent, p);
assert.strictEqual(content.lightParent, p);
assertArrayEqual(p.shadyRoot.lightChildren,
[textNodeA, contentA, textNodeB, contentB]);
}
testRender();
//testRender();
});
suite('Mutate light DOM', function() {
test('removeAllChildNodes - mutate host', function() {
var host = document.createElement('x-content-test');
setInnerHTML(host, '<a>Hello</a>');
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content>fallback</content>');
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');
host.firstChild.textContent = '';
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<a></a>');
host.lightChildren = [];
host.distributeContent();
assert.strictEqual(getComposedHTML(host), 'fallback');
});
test('removeAllChildNodes - mutate shadow', function() {
var host = document.createElement('x-content-test');
setInnerHTML(host, '<a>Hello</a>');
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content></content><b>after</b>');
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b>after</b>');
host.shadyRoot.lightChildren[1].textContent = '';
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b></b>');
host.shadyRoot.lightChildren = [];
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '');
});
test('removeAllChildNodes - mutate shadow fallback', function() {
var host = document.createElement('x-content-test');
setInnerHTML(host, '<a>Hello</a>');
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content select="xxx"><b>fallback</b></content>');
var b = host.shadyRoot.firstChild.firstChild;
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<b>fallback</b>');
b.textContent = '';
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<b></b>');
host.shadyRoot.firstChild.lightChildren = [];
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '');
host.shadyRoot.lightChildren = [];
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '');
});
test('removeChild - mutate host', function() {
var host = document.createElement('x-content-test');
setInnerHTML(host, '<a>Hello</a>');
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content>fallback</content>');
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');
host.firstChild.removeChild(host.firstChild.firstChild);
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<a></a>');
host.lightChildren = [];
host.distributeContent();
assert.strictEqual(getComposedHTML(host), 'fallback');
});
test('removeChild - mutate host 2', function() {
var host = document.createElement('x-content-test');
setInnerHTML(host, '<a></a><b></b>');
var a = host.firstChild;
var b = a.nextSibling;
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content>fallback</content>');
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<a></a><b></b>');
Polymer.dom(host).removeChild(b);
Polymer.dom.flush();
assert.strictEqual(getComposedHTML(host), '<a></a>');
Polymer.dom(host).removeChild(a);
Polymer.dom.flush();
assert.strictEqual(getComposedHTML(host), 'fallback');
});
test('removeChild - mutate shadow', function() {
var host = document.createElement('x-content-test');
setInnerHTML(host, '<a>Hello</a>');
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content></content><b>after</b>');
var b = host.shadyRoot.lastChild;
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b>after</b>');
b.removeChild(b.firstChild);
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b></b>');
host.shadyRoot.lightChildren.splice(1, 1); // remove b
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');
host.shadyRoot.lightChildren = []; // remove a
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '');
});
test('setAttribute select', function() {
// TODO(arv): DOM bindings for select.
var host = document.createElement('x-content-test');
setInnerHTML(host, '<a>Hello</a><b>World</b>');
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content select="b">fallback b</content>' +
'<content select="a">fallback a</content>');
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<b>World</b><a>Hello</a>');
host.shadyRoot.firstChild.setAttribute('select', 'xxx');
host.distributeContent();
assert.strictEqual(getComposedHTML(host), 'fallback b<a>Hello</a>');
host.shadyRoot.firstChild.setAttribute('select', '');
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b>World</b>fallback a');
});
test('appendChild - mutate host', function() {
var host = document.createElement('x-content-test');
setInnerHTML(host, '<a>Hello</a>');
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content></content>');
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');
var b = document.createElement('b');
Polymer.dom(host).appendChild(b);
Polymer.dom.flush();
assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b></b>');
});
test('appendChild - mutate shadow', function() {
var host = document.createElement('x-content-test');
setInnerHTML(host, '<a>Hello</a>');
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content></content>');
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');
var b = document.createElement('b');
Polymer.dom(host.shadyRoot).appendChild(b);
Polymer.dom.flush();
//host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<a>Hello</a><b></b>');
});
test('insertBefore - mutate host', function() {
var host = document.createElement('x-content-test');
setInnerHTML(host, '<a>Hello</a>');
var a = host.firstChild;
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content></content>');
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');
var b = document.createElement('b');
Polymer.dom(host).insertBefore(b, a);
Polymer.dom.flush();
assert.strictEqual(getComposedHTML(host), '<b></b><a>Hello</a>');
});
test('insertBefore - mutate shadow', function() {
var host = document.createElement('x-content-test');
setInnerHTML(host, '<a>Hello</a>');
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content></content>');
var content = host.shadyRoot.firstChild;
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');
var b = document.createElement('b');
Polymer.dom(host.shadyRoot).insertBefore(b, content);
Polymer.dom.flush();
assert.strictEqual(getComposedHTML(host), '<b></b><a>Hello</a>');
});
test('replaceChild - mutate host', function() {
var host = document.createElement('x-content-test');
setInnerHTML(host, '<a>Hello</a>');
var a = host.firstChild;
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content></content>');
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');
var b = document.createElement('b');
host.lightChildren[0] = b;
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<b></b>');
});
test('replaceChild - mutate shadow', function() {
var host = document.createElement('x-content-test');
setInnerHTML(host, '<a>Hello</a>');
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content></content>');
var content = host.shadyRoot.firstChild;
host.distributeContent();
assert.strictEqual(getComposedHTML(host), '<a>Hello</a>');
var b = document.createElement('b');
Polymer.dom(host.shadyRoot).replaceChild(b, content);
Polymer.dom.flush();
assert.strictEqual(getComposedHTML(host), '<b></b>');
});
test('querySelectorAll (shadyRoot)', function() {
var host = document.createElement('x-content-test');
setInnerHTML(host, '<div id="main"></div>');
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content></content><span id="main"></span>' +
'<x-content-test></x-content-test>');
var hostLocalMain = host.shadyRoot.firstChild.nextSibling;
var child = host.shadyRoot.lastChild;
// force upgrade on polyfilled browsers
CustomElements.upgrade(child);
setInnerHTML(child, '<div id="sub"></div>');
var childLightSub = child.firstChild;
syncLightDOM(child);
setRootInnerHTML(child.shadyRoot, '<content></content><span id="sub"></span>');
var childLocalSub = child.shadyRoot.lastChild;
host.distributeContent();
// NOTE: needed only for this imperative test that needs
// to simulate distribution from `shadyRoot`
child._distributeContent();
assert.deepEqual(Polymer.dom(host.root).querySelectorAll('span#main'), [hostLocalMain]);
assert.deepEqual(Polymer.dom(host.root).querySelectorAll('div#sub'), [childLightSub]);
assert.deepEqual(Polymer.dom(child.root).querySelectorAll('span#sub'), [childLocalSub]);
});
test('querySelectorAll (light dom)', function() {
var host = document.createElement('x-content-test');
setInnerHTML(host, '<div id="main"></div>');
var hostLightMain = host.firstChild;
syncLightDOM(host);
setRootInnerHTML(host.shadyRoot, '<content></content><span id="main"></span>' +
'<x-content-test></x-content-test>');
var child = host.shadyRoot.lastChild;
// force upgrade on polyfilled browsers
CustomElements.upgrade(child);
setInnerHTML(child, '<div id="sub"></div>');
var childLightSub = child.lastChild;
syncLightDOM(child);
setRootInnerHTML(child.shadyRoot, '<content></content><span id="sub"></span>');
host.distributeContent();
assert.deepEqual(Polymer.dom(host).querySelectorAll('div#main'), [hostLightMain]);
assert.deepEqual(Polymer.dom(host).querySelectorAll('#sub'), []);
assert.deepEqual(Polymer.dom(child).querySelectorAll('div#sub'), [childLightSub]);
});
});
function syncLightDOM(n) {
if (n.lightChildren) {
var c$ = n.__patched ? n._composedChildren || [] : Array.prototype.slice.call(n.childNodes);
c$.forEach(function(c) {
if (n.lightChildren.indexOf(c) < 0) {
c.lightParent = n;
n.lightChildren.push(c);
}
});
}
}
var nativeAppendChild = Element.prototype.appendChild;
function setInnerHTML(node, value) {
node.textContent = '';
if (node._composedChildren) {
node._composedChildren = [];
}
var temp = node.ownerDocument.createElement('div');
temp.innerHTML = value;
var firstChild;
while (firstChild = temp.firstChild) {
nativeAppendChild.call(node, firstChild);
if (node._composedChildren) {
node._composedChildren.push(firstChild);
}
}
}
function setRootInnerHTML(root, value) {
setInnerHTML(root, value);
syncLightDOM(root);
updateRootInsertionPoints(root);
}
function updateRootInsertionPoints(root) {
root._insertionPoints = root.querySelectorAll('content');
}
function getComposedHTML(node) {
return node.__patched ? Polymer.domInnerHTML.getInnerHTML(node, true) : node.innerHTML;
}
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>