| <!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> |