2018-06-26 12:34:08 -07:00
|
|
|
<!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>
|
|
|
|
|
<script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
|
|
|
|
|
<script>
|
2018-07-06 17:30:07 -07:00
|
|
|
Polymer = {
|
|
|
|
|
strictTemplatePolicy: true
|
|
|
|
|
};
|
2018-06-26 12:34:08 -07:00
|
|
|
// 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
|
2018-07-09 21:33:59 -07:00
|
|
|
window.addEventListener('error', event => {
|
2018-07-23 22:43:05 -07:00
|
|
|
if (window.uncaughtErrorFilter && window.uncaughtErrorFilter(event)) {
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
event.stopImmediatePropagation();
|
2018-06-26 12:34:08 -07:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
</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) {
|
2018-07-23 22:43:05 -07:00
|
|
|
if (!window.uncaughtErrorFilter || !window.uncaughtErrorFilter(error)) {
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
2018-06-26 12:34:08 -07:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
</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>
|
2018-07-20 20:29:52 -07:00
|
|
|
|
2018-07-23 22:43:05 -07:00
|
|
|
<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>
|
|
|
|
|
|
2018-06-26 12:34:08 -07:00
|
|
|
<div id="target"></div>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
suite('strictTemplatePolicy', function() {
|
|
|
|
|
|
2018-07-09 21:33:59 -07:00
|
|
|
// Capture mocha's default onerror
|
|
|
|
|
const onerror = window.onerror;
|
|
|
|
|
const topOnerror = window.top.topOnerror;
|
|
|
|
|
|
2018-07-24 11:47:29 -07:00
|
|
|
function restoreOnError() {
|
2018-07-09 21:33:59 -07:00
|
|
|
window.onerror = onerror;
|
|
|
|
|
window.top.onerror = topOnerror;
|
2018-07-23 22:43:05 -07:00
|
|
|
window.uncaughtErrorFilter = window.top.uncaughtErrorFilter = null;
|
2018-07-24 11:47:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
teardown(function() {
|
|
|
|
|
// Restore mocha's onerror
|
|
|
|
|
restoreOnError();
|
2018-07-23 22:43:05 -07:00
|
|
|
document.getElementById('target').textContent = '';
|
2018-06-26 12:34:08 -07:00
|
|
|
});
|
|
|
|
|
|
2018-07-09 21:33:59 -07:00
|
|
|
// 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
|
2018-06-26 12:34:08 -07:00
|
|
|
function assertThrows(fn, re) {
|
|
|
|
|
// Safari does not forward error messages
|
|
|
|
|
re = new RegExp('(' + re.toString().slice(1,-1) + ')|(Script error\\.)', re.flags);
|
2018-07-09 21:33:59 -07:00
|
|
|
// Catch uncaught errors; note when running in iframe sometimes
|
|
|
|
|
// Safari errors are thrown on the top window, sometimes not, so
|
|
|
|
|
// catch in both places
|
2018-07-23 22:43:05 -07:00
|
|
|
let uncaughtError = null;
|
|
|
|
|
window.onerror = window.top.onerror = window.uncaughtErrorFilter =
|
|
|
|
|
window.top.uncaughtErrorFilter = function(err) {
|
|
|
|
|
if (!uncaughtError) {
|
2018-07-24 18:46:00 -07:00
|
|
|
uncaughtError = err instanceof Error ? err : new Error(err.message || err);
|
2018-07-09 21:33:59 -07:00
|
|
|
}
|
2018-07-23 22:43:05 -07:00
|
|
|
return true;
|
2018-07-18 10:00:50 -07:00
|
|
|
};
|
2018-06-26 12:34:08 -07:00
|
|
|
assert.throws(function() {
|
|
|
|
|
fn();
|
2018-07-09 21:33:59 -07:00
|
|
|
// Re-throw any uncaughtErrors
|
2018-07-23 22:43:05 -07:00
|
|
|
if (uncaughtError) {
|
|
|
|
|
throw uncaughtError;
|
2018-06-26 12:34:08 -07:00
|
|
|
}
|
|
|
|
|
// Force polyfill reactions and/or async template stamping
|
|
|
|
|
Polymer.flush();
|
2018-07-09 21:33:59 -07:00
|
|
|
// Re-throw any uncaughtErrors
|
2018-07-23 22:43:05 -07:00
|
|
|
if (uncaughtError) {
|
|
|
|
|
throw uncaughtError;
|
2018-06-26 12:34:08 -07:00
|
|
|
}
|
|
|
|
|
}, re);
|
2018-07-24 11:47:29 -07:00
|
|
|
restoreOnError();
|
2018-06-26 12:34:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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>`' +
|
2018-07-23 21:13:53 -07:00
|
|
|
'</dom-module>';
|
2018-07-20 20:29:52 -07:00
|
|
|
}, /trusted-element re-registered/);
|
2018-07-24 11:47:29 -07:00
|
|
|
let el;
|
|
|
|
|
assertThrows(function() {
|
|
|
|
|
el = document.createElement('trusted-element');
|
|
|
|
|
document.getElementById('target').appendChild(el);
|
2018-10-31 16:25:16 -07:00
|
|
|
}, /expecting dom-module or null template for trusted-element/);
|
2018-07-24 11:47:29 -07:00
|
|
|
assert.notOk(el && el.shadowRoot);
|
2018-07-23 21:13:53 -07:00
|
|
|
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);
|
2018-10-31 16:25:16 -07:00
|
|
|
assert.notOk(el.shadowRoot);
|
2018-07-23 21:13:53 -07:00
|
|
|
assert.notOk(document.getElementById('injected'));
|
2018-06-26 12:34:08 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
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);
|
2018-07-23 21:13:53 -07:00
|
|
|
assert.notOk(document.getElementById('injected'));
|
2018-06-26 12:34:08 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
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>`' +
|
2018-07-23 21:13:53 -07:00
|
|
|
'</dom-module>';
|
2018-07-20 20:29:52 -07:00
|
|
|
}, /trusted-element-legacy re-registered/);
|
2018-07-24 11:47:29 -07:00
|
|
|
let el;
|
|
|
|
|
assertThrows(function() {
|
|
|
|
|
el = document.createElement('trusted-element-legacy');
|
|
|
|
|
document.getElementById('target').appendChild(el);
|
2018-10-31 16:25:16 -07:00
|
|
|
}, /expecting dom-module or null template for trusted-element-legacy/);
|
2018-07-24 11:47:29 -07:00
|
|
|
assert.notOk(el && el.shadowRoot);
|
2018-07-23 21:13:53 -07:00
|
|
|
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/);
|
2018-10-31 16:25:16 -07:00
|
|
|
const el = document.createElement('trusted-element-legacy');
|
2018-07-23 21:13:53 -07:00
|
|
|
document.getElementById('target').appendChild(el);
|
2018-10-31 16:25:16 -07:00
|
|
|
assert.notOk(el.shadowRoot);
|
2018-07-23 21:13:53 -07:00
|
|
|
assert.notOk(document.getElementById('injected'));
|
2018-06-26 12:34:08 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
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
|
2018-10-31 16:25:16 -07:00
|
|
|
});
|
2018-07-20 20:29:52 -07:00
|
|
|
let el = document.createElement('has-no-template-legacy');
|
2018-06-26 12:34:08 -07:00
|
|
|
document.getElementById('target').appendChild(el);
|
2018-07-23 21:13:53 -07:00
|
|
|
assert.notOk(el.shadowRoot);
|
|
|
|
|
assert.notOk(document.getElementById('injected'));
|
2018-06-26 12:34:08 -07:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('element without explicit template throws', function() {
|
|
|
|
|
assertThrows(function() {
|
|
|
|
|
class HasNoTemplateThrows extends Polymer.Element {
|
|
|
|
|
static get is() { return 'has-no-template-throws'; }
|
2018-07-06 18:08:22 -07:00
|
|
|
}
|
2018-06-26 12:34:08 -07:00
|
|
|
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);
|
2018-07-20 20:29:52 -07:00
|
|
|
}, /expecting dom-module or null template/);
|
2018-06-26 12:34:08 -07:00
|
|
|
});
|
|
|
|
|
|
2018-10-31 16:25:16 -07:00
|
|
|
test('template helpers in trusted templates work', function() {
|
2018-07-23 22:43:05 -07:00
|
|
|
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'));
|
|
|
|
|
});
|
|
|
|
|
|
2018-06-26 12:34:08 -07:00
|
|
|
});
|
2018-10-31 16:25:16 -07:00
|
|
|
|
2018-06-26 12:34:08 -07:00
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|