Skip to content

Commit

Permalink
Add WPT for error reporting during custom element upgrade
Browse files Browse the repository at this point in the history
This test currently fails in Chromium. 3/4 subtests fail with:

  error event should target definition's global but instead
  targets test harness global"

See also: whatwg/dom#1303

Bug: 359909516
Change-Id: I0cc589735d9f8c8ec2c4b55c89aabdb4f7500e17
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5789341
Commit-Queue: Jeremy Roman <[email protected]>
Reviewed-by: Mason Freed <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1342635}
  • Loading branch information
jeremyroman authored and chromium-wpt-export-bot committed Aug 16, 2024
1 parent 170c212 commit f74dcae
Showing 1 changed file with 84 additions and 0 deletions.
84 changes: 84 additions & 0 deletions custom-elements/upgrading/upgrade-custom-element-error-event.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<!DOCTYPE html>
<link rel="help" href="https://dom.spec.whatwg.org/#concept-create-element">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/custom-elements-helpers.js"></script>
<body>
<script>
// Returns a promise which will resolve with the next error event fired at any
// of `windows`, after the invocation of this function. Once one does, this
// function removes its listeners and produces that error event so that it can
// be examined (most notably for which global proxy it was targeted at).
async function nextErrorEvent(windows) {
let listener;
let p = new Promise((resolve, reject) => {
listener = (event) => { resolve(event); event.preventDefault(); };
});
for (let w of windows) {
w.addEventListener('error', listener);
}
try {
return await p;
} finally {
for (let w of windows) {
w.removeEventListener('error', listener);
}
}
}
const supportsCustomizedBuiltinElements = (function() {
let supported = false;
customElements.define('feature-detect', class extends HTMLDivElement {}, { get extends() { supported = true; return "div"; } });
return supported;
})();

promise_test(async t => {
let w = await create_window_in_test(t, `<script>self.MyElement = class extends HTMLElement { constructor() { throw new Error(); } };</`+`script>`);
let w2 = await create_window_in_test(t);
w2.customElements.define('my-element', w.MyElement);
let nextErrorPromise = nextErrorEvent([self, w, w2]);
let elem = w2.document.createElement('my-element');
let errorEvent = await nextErrorPromise;
assert_true(elem instanceof w2.HTMLUnknownElement, 'element should be an HTMLUnknownElement');
if (errorEvent.error) {
assert_true(errorEvent.error instanceof w.Error, 'error should be an instance created inside the MyElement constructor (if it was not muted)');
}
assert_equals(errorEvent.target, w, `error event should target definition's global but instead targets ${event.target === w2 ? 'document\'s global' : 'test harness global'}`);
}, 'autonomous: exception thrown in constructor is reported to definition\'s global');

promise_test(async t => {
let w = await create_window_in_test(t, `<script>self.MyElement = class extends HTMLElement { constructor() { this.textContent = 'hello!'; } };</`+`script>`);
let w2 = await create_window_in_test(t);
w2.customElements.define('my-element', w.MyElement);
let nextErrorPromise = nextErrorEvent([self, w, w2]);
let elem = w2.document.createElement('my-element');
let errorEvent = await nextErrorPromise;
assert_true(elem instanceof w2.HTMLUnknownElement, 'element should be an HTMLUnknownElement');
assert_equals(errorEvent.target, w, `error event should target definition's global but instead targets ${event.currentTarget === w2 ? 'document\'s global' : 'test harness global'}`);
}, 'autonomous: exception thrown by spec due to invalid element state is reported to definition\'s global');

promise_test(async t => {
assert_implements(supportsCustomizedBuiltinElements, 'customized built-in elements not supported');
let w = await create_window_in_test(t, `<script>self.MyDivElement = class extends HTMLDivElement { constructor() { throw new Error(); } };</`+`script>`);
let w2 = await create_window_in_test(t);
w2.customElements.define('my-div', w.MyDivElement, {extends: 'div'});
let nextErrorPromise = nextErrorEvent([self, w, w2]);
let elem = w2.document.createElement('div', {is: 'my-div'});
let errorEvent = await nextErrorPromise;
assert_equals(Object.getPrototypeOf(elem), w2.HTMLDivElement.prototype, 'element should be an HTMLDivElement (and not inherited from it)');
assert_true(errorEvent.error instanceof w.Error, 'error should be an instance created inside the MyElement constructor');
assert_equals(errorEvent.target, w, `error event should target definition's global but instead targets ${event.target === w2 ? 'document\'s global' : 'test harness global'}`);
}, 'customized built-in: exception thrown in constructor is reported to definition\'s global');

promise_test(async t => {
assert_implements(supportsCustomizedBuiltinElements, 'customized built-in elements not supported');
let w = await create_window_in_test(t, `<script>self.MyDivElement = class extends HTMLDivElement { constructor() { return document.createElement('div'); } };</`+`script>`);
let w2 = await create_window_in_test(t);
w2.customElements.define('my-div', w.MyDivElement, {extends: 'div'});
let nextErrorPromise = nextErrorEvent([self, w, w2]);
let elem = w2.document.createElement('div', {is: 'my-div'});
let errorEvent = await nextErrorPromise;
assert_equals(Object.getPrototypeOf(elem), w2.HTMLDivElement.prototype, 'element should be an HTMLDivElement (and not inherited from it)');
assert_equals(errorEvent.target, w, `error event should target definition's global but instead targets ${event.currentTarget === w2 ? 'document\'s global' : 'test harness global'}`);
}, 'customized built-in: exception thrown by spec due to not returning the same value is reported to definition\'s global');
</script>
</body>

0 comments on commit f74dcae

Please sign in to comment.