<!DOCTYPE html>
<title>Custom Elements: report the exception</title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="resources/custom-elements-helpers.js"></script>
<body>
<!--
The spec has two places where it says to [report the exception]:
1. In [create an element for a token], step 6.1
This can occur when [create an element] is invoked from
[create an element for a token] with the synchronous custom elements flag
set, or from createElement.
2. In [invoke custom element reactions], step 2.1.
There are different code paths when:
1. Author script throws an exception that is rethrown.
2. The user agent throws an exception.
This test contains tests for the combination of the above 2x2.
[create an element]: https://dom.spec.whatwg.org/#concept-create-element
[create an element for a token]: https://html.spec.whatwg.org/multipage/syntax.html#create-an-element-for-the-token
[invoke custom element reactions]: https://html.spec.whatwg.org/multipage/scripting.html#invoke-custom-element-reactions
[report the exception]: https://html.spec.whatwg.org/multipage/webappapis.html#report-the-exception
-->
<template id="constructor-throws">
<script>
'use strict';
window.errors = [];
// https://html.spec.whatwg.org/multipage/webappapis.html#event-handler-attributes:handler-onerror
window.onerror = function (event, source, lineno, colno, error) {
errors.push({
event: event,
source: source,
lineno: lineno,
colno: colno,
error: error
});
return true; // Cancel the error event.
};
const rethrowErrorName = 'rethrown';
const rethrowErrorMessage = 'check this is rethrown';
customElements.define('a-a', class extends HTMLElement {
constructor() {
const error = new Error(rethrowErrorMessage);
error.name = rethrowErrorName;
throw error;
}
});
</script>
</template>
<template id="instantiate">
<a-a></a-a>
</template>
<template id="createElement">
<script>
window.e = document.createElement('a-a');
</script>
</template>
<script>
'use strict';
const rethrowErrorName = 'rethrown';
const rethrowErrorMessage = 'check this is rethrown';
function assert_not_muted_error_event(error) {
assert_not_equals(error, undefined, 'should fire error event');
// Report an error, 6. If script has muted errors, ...
// https://html.spec.whatwg.org/multipage/webappapis.html#report-the-error
assert_false(error.event === 'Script error.'
&& error.source === '' && error.lineno === 0 && error.colno === 0
&& error.error === null,
'the error should not be muted.');
assert_false(!error.event, 'event (1st arg) should not be null');
assert_false(!error.source, 'source (2nd arg) should not be null');
// The spec doesn't define valid values for lineno/colno.
assert_false(!error.error, 'error (5th arg) should not be null');
}
function assert_reported_error_event(error) {
assert_not_muted_error_event(error);
assert_equals(error.error.name, rethrowErrorName);
assert_equals(error.error.message, rethrowErrorMessage);
}
const constructor_throws =
document.getElementById('constructor-throws').innerHTML;
const instantiate = document.getElementById('instantiate').innerHTML;
const create_element = document.getElementById('createElement').innerHTML;
test_with_window((w) => {
assert_reported_error_event(w.errors[0]);
}, 'Document parser invokes the constructor that throws',
constructor_throws + instantiate);
test_with_window((w) => {
w.document.body.innerHTML = instantiate;
assert_reported_error_event(w.errors[0]);
}, 'Upgrade reaction invokes the constructor that throws',
constructor_throws);
test_with_window((w) => {
assert_reported_error_event(w.errors[0]);
assert_true(
w.e instanceof w.HTMLUnknownElement,
'the created element should be HTMLUnknownElement');
}, 'createElement invokes the constructor that throws',
constructor_throws + create_element);
</script>
<!--
Test when JavaScript returns without throwing errors, but the result is invalid
and thus UA should [report the exception].
-->
<template id="constructor-returns-bad-object">
<script>
'use strict';
window.errors = [];
// https://html.spec.whatwg.org/multipage/webappapis.html#event-handler-attributes:handler-onerror
window.onerror = function (event, source, lineno, colno, error) {
errors.push({
event: event,
source: source,
lineno: lineno,
colno: colno,
error: error
});
return true; // Cancel the error event.
};
customElements.define('a-a', class extends HTMLElement {
constructor() {
super();
return []; // returning objects other than "this" is invalid.
}
});
</script>
</template>
<script>
const constructor_returns_bad_object =
document.getElementById('constructor-returns-bad-object').innerHTML;
function assert_type_error_event(error) {
assert_not_muted_error_event(error);
assert_equals(error.error.name, 'TypeError');
}
test_with_window((w) => {
// "create an element" 6.1.3, throw a TypeError.
// https://dom.spec.whatwg.org/#concept-create-element
assert_type_error_event(w.errors[0]);
}, 'Document parser invokes the constructor that returns a bad object',
constructor_returns_bad_object + instantiate);
test_with_window((w) => {
// "upgrade an element" 10, throw a TypeError.
// https://html.spec.whatwg.org/multipage/scripting.html#upgrades
w.document.body.innerHTML = instantiate;
assert_type_error_event(w.errors[0]);
}, 'Upgrade reaction invokes the constructor that returns a bad object',
constructor_returns_bad_object);
</script>
</body>