<!DOCTYPE html>
<title>Custom Elements: Constructor Tests</title>
<link rel="help" href="https://html.spec.whatwg.org/multipage/dom.html#elements-in-the-dom">
<meta name="author" title="Dominic Cooney" href="mailto:[email protected]">
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="resources/custom-elements-helpers.js"></script>
<body>
<script>
'use strict';
setup({
allow_uncaught_exception: true,
});
test_with_window((w) => {
assert_throws_js(w.TypeError, () => {
w.HTMLElement();
}, 'calling the HTMLElement constructor should throw a TypeError');
}, 'HTMLElement constructor, invoke');
test_with_window((w) => {
assert_throws_js(w.TypeError, () => {
new w.HTMLElement();
}, 'invoking the HTMLElement constructor with a construct call should ' +
'throw a TypeError');
}, 'HTMLElement constructor, construct');
test_with_window((w) => {
class X extends w.HTMLElement {}
w.customElements.define('a-a', X);
assert_throws_js(TypeError, () => {
X();
}, 'calling a custom element constructor should throw a TypeError');
}, 'Custom element constructor, invoke');
test_with_window((w) => {
var num_constructor_invocations = 0;
class C extends w.HTMLElement {
constructor() {
super();
num_constructor_invocations++;
}
}
w.customElements.define('a-a', C);
let e = new C();
assert_true(e instanceof w.HTMLElement,
'the element should be an HTMLElement');
assert_equals(e.localName,
'a-a',
'the element tag name should be "a-a"');
assert_equals(e.namespaceURI,
'http://www.w3.org/1999/xhtml',
'the element should be in the HTML namespace');
assert_equals(e.prefix,
null,
'the element name should not have a prefix');
assert_equals(e.ownerDocument,
w.document,
'the element should be owned by the registry\'s associated ' +
'document');
assert_equals(num_constructor_invocations,
1,
'the constructor should have been invoked once');
assert_true(e.matches(':defined'), 'custom element constructed with new should be "custom"');
}, 'Custom element constructor, construct');
test_with_window((w) => {
class C extends w.HTMLElement { }
class D extends C {}
w.customElements.define('a-a', C); // Note: Not D.
assert_throws_js(w.TypeError, () => {
new D();
}, 'constructing a custom element with a new.target with no registry ' +
'entry should throw a TypeError');
assert_throws_js(TypeError, () => {
Reflect.construct(C, [], 42);
}, 'constructing a custom element with a non-object new.target should ' +
'throw a TypeError');
}, 'Custom element constructor, construct invalid new.target');
test_with_window((w) => {
w.customElements.define('a-a', w.HTMLButtonElement);
assert_reports_js(w, w.TypeError, () => {
w.document.createElement('a-a');
}, 'If NewTarget is equal to active function object, TypeError should be ' +
'reported');
}, 'Custom element constructor, NewTarget is equal to active function object');
test_with_window((w) => {
w.customElements.define('a-a', class extends w.HTMLButtonElement {} );
assert_reports_js(w, w.TypeError, () => {
w.document.createElement('a-a');
}, 'If NewTarget is equal to active function object, TypeError should be ' +
'reported');
}, 'Custom element constructor, active function object is not equal to HTMLElement');
test_with_window((w) => {
let flag = true;
class A extends w.HTMLElement {
constructor() {
if (flag) {
flag = false;
new A();
}
super();
}
}
w.customElements.define('a-a', A);
let e = new A();
assert_true(e.matches(':defined'),
'constructing a custom element with new should not throw InvalidStateError ' +
'and should return a "custom" element');
}, 'Already constructed marker, construct with new');
test_with_window((w) => {
let flag = true;
class A extends w.HTMLElement {
constructor() {
if (flag) {
flag = false;
new A();
}
super();
}
}
w.customElements.define('a-a', A);
let e = w.document.createElement('a-a');
assert_true(e.matches(':defined'),
'constructing an autonomous custom element with create element should ' +
'not throw InvalidStateError ' +
'and should return a "custom" element');
}, 'Already constructed marker, create element');
test_with_window((w) => {
let flag = true;
class A extends w.HTMLElement {
constructor() {
if (flag) {
flag = false;
new A();
}
super();
}
}
w.customElements.define('a-a', A);
let d = w.document.createElement('div');
assert_reports_js(window, w.TypeError, () => {
d.innerHTML = '<a-a>';
}, 'Creating an element that is already constructed marker should report ' +
'InvalidStateError');
}, 'Already constructed marker, fragment parsing should set marker');
test_with_window((w) => {
let errors = [];
window.onerror = function (event, source, lineno, colno, error) {
errors.push(error.name);
return true;
};
let flag = true;
let e = w.document.createElement('a-a');
class A extends w.HTMLElement {
constructor() {
if (flag) {
flag = false;
new A();
}
super();
}
}
w.customElements.define('a-a', A);
w.document.body.appendChild(e);
assert_array_equals(errors, ['TypeError'], 'Upgrading an element ' +
'that is already constructed marker should throw TypeError');
}, 'Already constructed marker, upgrade element');
</script>