@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
359 lines (333 loc) • 13.2 kB
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>
<script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
<script>
Polymer = {
strictTemplatePolicy: true
};
// Errors thrown in custom element reactions are not thrown up
// the call stack to the dom methods that provoked them, so need
// to catch them here and prevent mocha from complaining about them
window.addEventListener('error', event => {
if (window.uncaughtErrorFilter && window.uncaughtErrorFilter(event)) {
event.preventDefault();
event.stopImmediatePropagation();
}
});
</script>
<script src="../../../web-component-tester/browser.js"></script>
<link rel="import" href="../../polymer.html">
<script>
HTMLImports.whenReady(() => {
// Errors thrown in Polymer's debouncer queue get re-thrown
// via setTimeout, making them particulary difficult to verify;
// Wrap debouncer callbacks and store on the globalError to test later
const debounce = Polymer.Debouncer.debounce;
Polymer.Debouncer.debounce = function(debouncer, asyncModule, callback) {
return debounce(debouncer, asyncModule, function() {
try {
callback();
} catch(error) {
if (!window.uncaughtErrorFilter || !window.uncaughtErrorFilter(error)) {
throw error;
}
}
});
};
});
</script>
</head>
<body>
<dom-module id="trusted-element">
<template>Trusted</template>
<script>
HTMLImports.whenReady(function() {
class TrustedElement extends Polymer.Element {
static get is() { return 'trusted-element'; }
}
customElements.define(TrustedElement.is, TrustedElement);
});
</script>
</dom-module>
<dom-module id="trusted-element-legacy">
<template>Trusted</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'trusted-element-legacy'});
});
</script>
</dom-module>
<dom-module id="trusted-templates">
<template>
<dom-repeat items="[0]">
<template>
<div id="dom-repeat-ok"></div>
<dom-if if>
<template><div id="nested-dom-if-ok"></div></template>
</dom-if>
</template>
</dom-repeat>
<dom-if if>
<template>
<div id="dom-if-ok"></div>
<dom-repeat items="[0]">
<template>
<div id="nested-dom-repeat-ok"></div>
</template>
</dom-repeat>
</template>
</dom-if>
</template>
<script>
HTMLImports.whenReady(function() {
class TrustedTemplates extends Polymer.Element {
static get is() { return 'trusted-templates'; }
}
customElements.define(TrustedTemplates.is, TrustedTemplates);
});
</script>
</dom-module>
<dom-module id="trusted-templates-legacy">
<template>
<template is="dom-repeat" items="[0]">
<div id="dom-repeat-ok"></div>
<template is="dom-if" if><div id="nested-dom-if-ok"></div></template>
</template>
<template is="dom-if" if>
<div id="dom-if-ok"></div>
<template is="dom-repeat" items="[0]"><div id="nested-dom-repeat-ok"></div></template>
</template>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({is: 'trusted-templates-legacy'});
});
</script>
</dom-module>
<div id="target"></div>
<script>
suite('strictTemplatePolicy', function() {
// Capture mocha's default onerror
const onerror = window.onerror;
const topOnerror = window.top.topOnerror;
function restoreOnError() {
window.onerror = onerror;
window.top.onerror = topOnerror;
window.uncaughtErrorFilter = window.top.uncaughtErrorFilter = null;
}
teardown(function() {
// Restore mocha's onerror
restoreOnError();
document.getElementById('target').textContent = '';
});
// Errors thrown in custom element reactions are not thrown up
// the call stack to the dom methods that provoked them, so this
// wraps Chai's assert.throws to re-throw uncaught errors
function assertThrows(fn, re) {
// Safari does not forward error messages
re = new RegExp('(' + re.toString().slice(1,-1) + ')|(Script error\\.)', re.flags);
// Catch uncaught errors; note when running in iframe sometimes
// Safari errors are thrown on the top window, sometimes not, so
// catch in both places
let uncaughtError = null;
window.onerror = window.top.onerror = window.uncaughtErrorFilter =
window.top.uncaughtErrorFilter = function(err) {
if (!uncaughtError) {
uncaughtError = err instanceof Error ? err : new Error(err.message || err);
}
return true;
};
assert.throws(function() {
fn();
// Re-throw any uncaughtErrors
if (uncaughtError) {
throw uncaughtError;
}
// Force polyfill reactions and/or async template stamping
Polymer.flush();
// Re-throw any uncaughtErrors
if (uncaughtError) {
throw uncaughtError;
}
}, re);
restoreOnError();
}
test('dom-bind', function() {
assertThrows(function() {
document.getElementById('target').innerHTML =
'<dom-bind>' +
' <template>' +
' <div id="injected"></div>'+
' </template>`' +
'</dom-bind>';
}, /dom-bind not allowed/);
assert.notOk(document.getElementById('injected'));
});
test('dom-if', function() {
assertThrows(function() {
document.getElementById('target').innerHTML =
'<dom-if if>' +
' <template>' +
' <div id="injected"></div>'+
' </template>' +
'</dom-if>';
}, /template owner not trusted/);
assert.notOk(document.getElementById('injected'));
});
test('dom-repeat', function() {
assertThrows(function() {
document.getElementById('target').innerHTML =
'<dom-repeat items="[0]">' +
' <template>' +
' <div id="injected"></div>'+
' </template>`' +
'</dom-repeat>';
}, /template owner not trusted/);
assert.notOk(document.getElementById('injected'));
});
test('dom-module after registration', function() {
assertThrows(function() {
document.getElementById('target').innerHTML =
'<dom-module id="trusted-element">' +
' <template>' +
' <div id="injected"></div>'+
' </template>`' +
'</dom-module>';
}, /trusted-element re-registered/);
let el;
assertThrows(function() {
el = document.createElement('trusted-element');
document.getElementById('target').appendChild(el);
}, /expecting dom-module or null template for trusted-element/);
assert.notOk(el && el.shadowRoot);
assert.notOk(document.getElementById('injected'));
});
test('dom-module after registration, again', function() {
assertThrows(function() {
document.getElementById('target').innerHTML =
'<dom-module id="trusted-element">' +
' <template>' +
' <div id="injected"></div>'+
' </template>`' +
'</dom-module>';
}, /trusted-element re-registered/);
const el = document.createElement('trusted-element');
document.getElementById('target').appendChild(el);
assert.notOk(el.shadowRoot);
assert.notOk(document.getElementById('injected'));
});
test('dom-module before registration', function() {
document.getElementById('target').innerHTML =
'<dom-module id="has-no-template">' +
' <template>' +
' <div id="injected"></div>'+
' </template>`' +
'</dom-module>';
class HasNoTemplate extends Polymer.Element {
static get is() { return 'has-no-template'; }
static get template() { return null; }
}
customElements.define(HasNoTemplate.is, HasNoTemplate);
let el = document.createElement('has-no-template');
document.getElementById('target').appendChild(el);
assert.notOk(el.shadowRoot);
assert.notOk(document.getElementById('injected'));
});
test('dom-module after registration (legacy)', function() {
assertThrows(function() {
document.getElementById('target').innerHTML =
'<dom-module id="trusted-element-legacy">' +
' <template>' +
' <div id="injected"></div>'+
' </template>`' +
'</dom-module>';
}, /trusted-element-legacy re-registered/);
let el;
assertThrows(function() {
el = document.createElement('trusted-element-legacy');
document.getElementById('target').appendChild(el);
}, /expecting dom-module or null template for trusted-element-legacy/);
assert.notOk(el && el.shadowRoot);
assert.notOk(document.getElementById('injected'));
});
test('dom-module after registration, again (legacy)', function() {
assertThrows(function() {
document.getElementById('target').innerHTML =
'<dom-module id="trusted-element-legacy">' +
' <template>' +
' <div id="injected"></div>'+
' </template>`' +
'</dom-module>';
}, /trusted-element-legacy re-registered/);
const el = document.createElement('trusted-element-legacy');
document.getElementById('target').appendChild(el);
assert.notOk(el.shadowRoot);
assert.notOk(document.getElementById('injected'));
});
test('dom-module before registration (legacy)', function() {
document.getElementById('target').innerHTML =
'<dom-module id="has-no-template-legacy">' +
' <template>' +
' <div id="injected"></div>'+
' </template>`' +
'</dom-module>';
Polymer({
is: 'has-no-template-legacy',
_template: null
});
let el = document.createElement('has-no-template-legacy');
document.getElementById('target').appendChild(el);
assert.notOk(el.shadowRoot);
assert.notOk(document.getElementById('injected'));
});
test('element without explicit template throws', function() {
assertThrows(function() {
class HasNoTemplateThrows extends Polymer.Element {
static get is() { return 'has-no-template-throws'; }
}
customElements.define(HasNoTemplateThrows.is, HasNoTemplateThrows);
var el = document.createElement('has-no-template-throws');
document.getElementById('target').appendChild(el);
}, /expecting dom-module or null template/);
});
test('element without explicit template throws (legacy)', function() {
assertThrows(function() {
Polymer({
is: 'has-no-template-throws-legacy'
});
var el = document.createElement('has-no-template-throws-legacy');
document.getElementById('target').appendChild(el);
}, /expecting dom-module or null template/);
});
test('template helpers in trusted templates work', function() {
var el = document.createElement('trusted-templates');
document.getElementById('target').appendChild(el);
Polymer.flush();
assert.ok(el.shadowRoot.querySelector('#dom-repeat-ok'));
assert.ok(el.shadowRoot.querySelector('#dom-if-ok'));
assert.ok(el.shadowRoot.querySelector('#nested-dom-repeat-ok'));
assert.ok(el.shadowRoot.querySelector('#nested-dom-if-ok'));
});
test('template helpers in trusted templates work (legacy)', function() {
var el = document.createElement('trusted-templates-legacy');
document.getElementById('target').appendChild(el);
Polymer.flush();
assert.ok(el.shadowRoot.querySelector('#dom-repeat-ok'));
assert.ok(el.shadowRoot.querySelector('#dom-if-ok'));
assert.ok(el.shadowRoot.querySelector('#nested-dom-repeat-ok'));
assert.ok(el.shadowRoot.querySelector('#nested-dom-if-ok'));
});
});
</script>
</body>
</html>