diff options
Diffstat (limited to 'testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/support')
2 files changed, 979 insertions, 0 deletions
diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/support/promise-access-control.py b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/support/promise-access-control.py new file mode 100644 index 0000000000..cf8ed5e492 --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/support/promise-access-control.py @@ -0,0 +1,18 @@ +def main(request, response): + allow = request.GET.first(b"allow", b"false") + + headers = [(b"Content-Type", b"application/javascript")] + if allow != b"false": + headers.append((b"Access-Control-Allow-Origin", b"*")) + + body = b""" + function handleRejectedPromise(promise) { + promise.catch(() => {}); + } + + (function() { + new Promise(function(resolve, reject) { reject(42); }); + })(); + """ + + return headers, body diff --git a/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/support/promise-rejection-events.js b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/support/promise-rejection-events.js new file mode 100644 index 0000000000..036e1784db --- /dev/null +++ b/testing/web-platform/tests/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/support/promise-rejection-events.js @@ -0,0 +1,961 @@ +'use strict'; + +if (self.importScripts) { + importScripts('/resources/testharness.js'); +} + +setup({ + allow_uncaught_exception: true +}); + +// +// Straightforward unhandledrejection tests +// +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + p = Promise.reject(e); +}, 'unhandledrejection: from Promise.reject'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + p = new Promise(function(_, reject) { + reject(e); + }); +}, 'unhandledrejection: from a synchronous rejection in new Promise'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + p = new Promise(function(_, reject) { + queueTask(function() { + reject(e); + }); + }); +}, 'unhandledrejection: from a task-delayed rejection'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + p = new Promise(function(_, reject) { + setTimeout(function() { + reject(e); + }, 1); + }); +}, 'unhandledrejection: from a setTimeout-delayed rejection'); + +async_test(function(t) { + var e = new Error(); + var e2 = new Error(); + var promise2; + + onUnhandledSucceed(t, e2, function() { return promise2; }); + + var unreached = t.unreached_func('promise should not be fulfilled'); + promise2 = Promise.reject(e).then(unreached, function(reason) { + t.step(function() { + assert_equals(reason, e); + }); + throw e2; + }); +}, 'unhandledrejection: from a throw in a rejection handler chained off of Promise.reject'); + +async_test(function(t) { + var e = new Error(); + var e2 = new Error(); + var promise2; + + onUnhandledSucceed(t, e2, function() { return promise2; }); + + var unreached = t.unreached_func('promise should not be fulfilled'); + promise2 = new Promise(function(_, reject) { + setTimeout(function() { + reject(e); + }, 1); + }).then(unreached, function(reason) { + t.step(function() { + assert_equals(reason, e); + }); + throw e2; + }); +}, 'unhandledrejection: from a throw in a rejection handler chained off of a setTimeout-delayed rejection'); + +async_test(function(t) { + var e = new Error(); + var e2 = new Error(); + var promise2; + + onUnhandledSucceed(t, e2, function() { return promise2; }); + + var promise = new Promise(function(_, reject) { + setTimeout(function() { + reject(e); + mutationObserverMicrotask(function() { + var unreached = t.unreached_func('promise should not be fulfilled'); + promise2 = promise.then(unreached, function(reason) { + t.step(function() { + assert_equals(reason, e); + }); + throw e2; + }); + }); + }, 1); + }); +}, 'unhandledrejection: from a throw in a rejection handler attached one microtask after a setTimeout-delayed rejection'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + p = Promise.resolve().then(function() { + return Promise.reject(e); + }); +}, 'unhandledrejection: from returning a Promise.reject-created rejection in a fulfillment handler'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + p = Promise.resolve().then(function() { + throw e; + }); +}, 'unhandledrejection: from a throw in a fulfillment handler'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + p = Promise.resolve().then(function() { + return new Promise(function(_, reject) { + setTimeout(function() { + reject(e); + }, 1); + }); + }); +}, 'unhandledrejection: from returning a setTimeout-delayed rejection in a fulfillment handler'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + p = Promise.all([Promise.reject(e)]); +}, 'unhandledrejection: from Promise.reject, indirected through Promise.all'); + +async_test(function(t) { + var p; + + var unhandled = function(ev) { + if (ev.promise === p) { + t.step(function() { + assert_equals(ev.reason.name, 'InvalidStateError'); + assert_equals(ev.promise, p); + }); + t.done(); + } + }; + addEventListener('unhandledrejection', unhandled); + ensureCleanup(t, unhandled); + + p = createImageBitmap(new Blob()); +}, 'unhandledrejection: from createImageBitmap which is UA triggered'); + +// +// Negative unhandledrejection/rejectionhandled tests with immediate attachment +// + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + var unreached = t.unreached_func('promise should not be fulfilled'); + p = Promise.reject(e).then(unreached, function() {}); +}, 'no unhandledrejection/rejectionhandled: rejection handler attached synchronously to a promise from Promise.reject'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + var unreached = t.unreached_func('promise should not be fulfilled'); + p = Promise.all([Promise.reject(e)]).then(unreached, function() {}); +}, 'no unhandledrejection/rejectionhandled: rejection handler attached synchronously to a promise from ' + + 'Promise.reject, indirecting through Promise.all'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + var unreached = t.unreached_func('promise should not be fulfilled'); + p = new Promise(function(_, reject) { + reject(e); + }).then(unreached, function() {}); +}, 'no unhandledrejection/rejectionhandled: rejection handler attached synchronously to a synchronously-rejected ' + + 'promise created with new Promise'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + var unreached = t.unreached_func('promise should not be fulfilled'); + p = Promise.resolve().then(function() { + throw e; + }).then(unreached, function(reason) { + t.step(function() { + assert_equals(reason, e); + }); + }); +}, 'no unhandledrejection/rejectionhandled: rejection handler attached synchronously to a promise created from ' + + 'throwing in a fulfillment handler'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + var unreached = t.unreached_func('promise should not be fulfilled'); + p = Promise.resolve().then(function() { + return Promise.reject(e); + }).then(unreached, function(reason) { + t.step(function() { + assert_equals(reason, e); + }); + }); +}, 'no unhandledrejection/rejectionhandled: rejection handler attached synchronously to a promise created from ' + + 'returning a Promise.reject-created promise in a fulfillment handler'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + var unreached = t.unreached_func('promise should not be fulfilled'); + p = Promise.resolve().then(function() { + return new Promise(function(_, reject) { + setTimeout(function() { + reject(e); + }, 1); + }); + }).then(unreached, function(reason) { + t.step(function() { + assert_equals(reason, e); + }); + }); +}, 'no unhandledrejection/rejectionhandled: rejection handler attached synchronously to a promise created from ' + + 'returning a setTimeout-delayed rejection in a fulfillment handler'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + queueTask(function() { + p = Promise.resolve().then(function() { + return Promise.reject(e); + }) + .catch(function() {}); + }); +}, 'no unhandledrejection/rejectionhandled: all inside a queued task, a rejection handler attached synchronously to ' + + 'a promise created from returning a Promise.reject-created promise in a fulfillment handler'); + +async_test(function(t) { + var p; + + onUnhandledFail(t, function() { return p; }); + + var unreached = t.unreached_func('promise should not be fulfilled'); + p = createImageBitmap(new Blob()).then(unreached, function() {}); +}, 'no unhandledrejection/rejectionhandled: rejection handler attached synchronously to a promise created from ' + + 'createImageBitmap'); + +// +// Negative unhandledrejection/rejectionhandled tests with microtask-delayed attachment +// + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + p = Promise.reject(e); + mutationObserverMicrotask(function() { + var unreached = t.unreached_func('promise should not be fulfilled'); + p.then(unreached, function() {}); + }); +}, 'delayed handling: a microtask delay before attaching a handler prevents both events (Promise.reject-created ' + + 'promise)'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + p = new Promise(function(_, reject) { + reject(e); + }); + mutationObserverMicrotask(function() { + var unreached = t.unreached_func('promise should not be fulfilled'); + p.then(unreached, function() {}); + }); +}, 'delayed handling: a microtask delay before attaching a handler prevents both events (immediately-rejected new ' + + 'Promise-created promise)'); + +async_test(function(t) { + var e = new Error(); + var p1; + var p2; + + onUnhandledFail(t, function() { return p1; }); + onUnhandledFail(t, function() { return p2; }); + + p1 = new Promise(function(_, reject) { + mutationObserverMicrotask(function() { + reject(e); + }); + }); + p2 = Promise.all([p1]); + mutationObserverMicrotask(function() { + var unreached = t.unreached_func('promise should not be fulfilled'); + p2.then(unreached, function() {}); + }); +}, 'delayed handling: a microtask delay before attaching the handler, and before rejecting the promise, indirected ' + + 'through Promise.all'); + +// +// Negative unhandledrejection/rejectionhandled tests with nested-microtask-delayed attachment +// + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + p = Promise.reject(e); + mutationObserverMicrotask(function() { + Promise.resolve().then(function() { + mutationObserverMicrotask(function() { + Promise.resolve().then(function() { + p.catch(function() {}); + }); + }); + }); + }); +}, 'microtask nesting: attaching a handler inside a combination of mutationObserverMicrotask + promise microtasks'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + queueTask(function() { + p = Promise.reject(e); + mutationObserverMicrotask(function() { + Promise.resolve().then(function() { + mutationObserverMicrotask(function() { + Promise.resolve().then(function() { + p.catch(function() {}); + }); + }); + }); + }); + }); +}, 'microtask nesting: attaching a handler inside a combination of mutationObserverMicrotask + promise microtasks, ' + + 'all inside a queueTask'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + setTimeout(function() { + p = Promise.reject(e); + mutationObserverMicrotask(function() { + Promise.resolve().then(function() { + mutationObserverMicrotask(function() { + Promise.resolve().then(function() { + p.catch(function() {}); + }); + }); + }); + }); + }, 0); +}, 'microtask nesting: attaching a handler inside a combination of mutationObserverMicrotask + promise microtasks, ' + + 'all inside a setTimeout'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + p = Promise.reject(e); + Promise.resolve().then(function() { + mutationObserverMicrotask(function() { + Promise.resolve().then(function() { + mutationObserverMicrotask(function() { + p.catch(function() {}); + }); + }); + }); + }); +}, 'microtask nesting: attaching a handler inside a combination of promise microtasks + mutationObserverMicrotask'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + queueTask(function() { + p = Promise.reject(e); + Promise.resolve().then(function() { + mutationObserverMicrotask(function() { + Promise.resolve().then(function() { + mutationObserverMicrotask(function() { + p.catch(function() {}); + }); + }); + }); + }); + }); +}, 'microtask nesting: attaching a handler inside a combination of promise microtasks + mutationObserverMicrotask, ' + + 'all inside a queueTask'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + setTimeout(function() { + p = Promise.reject(e); + Promise.resolve().then(function() { + mutationObserverMicrotask(function() { + Promise.resolve().then(function() { + mutationObserverMicrotask(function() { + p.catch(function() {}); + }); + }); + }); + }); + }, 0); +}, 'microtask nesting: attaching a handler inside a combination of promise microtasks + mutationObserverMicrotask, ' + + 'all inside a setTimeout'); + + +// For workers, queueTask() involves posting tasks to other threads, so +// the following tests don't work there. + +if ('document' in self) { + // + // Negative unhandledrejection/rejectionhandled tests with task-delayed attachment + // + + async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + var _reject; + p = new Promise(function(_, reject) { + _reject = reject; + }); + _reject(e); + queueTask(function() { + var unreached = t.unreached_func('promise should not be fulfilled'); + p.then(unreached, function() {}); + }); + }, 'delayed handling: a task delay before attaching a handler prevents unhandledrejection'); + + async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + p = Promise.reject(e); + queueTask(function() { + Promise.resolve().then(function() { + p.catch(function() {}); + }); + }); + }, 'delayed handling: queueTask after promise creation/rejection, plus promise microtasks, is not too late to ' + + 'attach a rejection handler'); + + async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + queueTask(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + p.catch(function() {}); + }); + }); + }); + }); + }); + p = Promise.reject(e); + }, 'delayed handling: queueTask before promise creation/rejection, plus many promise microtasks, is not too ' + + 'late to attach a rejection handler'); + + async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledFail(t, function() { return p; }); + + p = Promise.reject(e); + queueTask(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + p.catch(function() {}); + }); + }); + }); + }); + }); + }, 'delayed handling: queueTask after promise creation/rejection, plus many promise microtasks, is not too ' + + 'late to attach a rejection handler'); +} + +// +// Positive unhandledrejection/rejectionhandled tests with delayed attachment +// + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + var _reject; + p = new Promise(function(_, reject) { + _reject = reject; + }); + _reject(e); + queueTask(function() { + queueTask(function() { + var unreached = t.unreached_func('promise should not be fulfilled'); + p.then(unreached, function() {}); + }); + }); +}, 'delayed handling: a nested-task delay before attaching a handler causes unhandledrejection'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + p = Promise.reject(e); + queueTask(function() { + queueTask(function() { + Promise.resolve().then(function() { + p.catch(function() {}); + }); + }); + }); +}, 'delayed handling: a nested-queueTask after promise creation/rejection, plus promise microtasks, is too ' + + 'late to attach a rejection handler'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + queueTask(function() { + queueTask(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + p.catch(function() {}); + }); + }); + }); + }); + }); + }); + p = Promise.reject(e); +}, 'delayed handling: a nested-queueTask before promise creation/rejection, plus many promise microtasks, is ' + + 'too late to attach a rejection handler'); + +async_test(function(t) { + var e = new Error(); + var p; + + onUnhandledSucceed(t, e, function() { return p; }); + + p = Promise.reject(e); + queueTask(function() { + queueTask(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + Promise.resolve().then(function() { + p.catch(function() {}); + }); + }); + }); + }); + }); + }); +}, 'delayed handling: a nested-queueTask after promise creation/rejection, plus many promise microtasks, is ' + + 'too late to attach a rejection handler'); + +async_test(function(t) { + var unhandledPromises = []; + var unhandledReasons = []; + var e = new Error(); + var p; + + var unhandled = function(ev) { + if (ev.promise === p) { + t.step(function() { + unhandledPromises.push(ev.promise); + unhandledReasons.push(ev.reason); + }); + } + }; + var handled = function(ev) { + if (ev.promise === p) { + t.step(function() { + assert_array_equals(unhandledPromises, [p]); + assert_array_equals(unhandledReasons, [e]); + assert_equals(ev.promise, p); + assert_equals(ev.reason, e); + }); + } + }; + addEventListener('unhandledrejection', unhandled); + addEventListener('rejectionhandled', handled); + ensureCleanup(t, unhandled, handled); + + p = new Promise(function() { + throw e; + }); + setTimeout(function() { + var unreached = t.unreached_func('promise should not be fulfilled'); + p.then(unreached, function(reason) { + assert_equals(reason, e); + setTimeout(function() { t.done(); }, 10); + }); + }, 10); +}, 'delayed handling: delaying handling by setTimeout(,10) will cause both events to fire'); + +async_test(function(t) { + var unhandledPromises = []; + var unhandledReasons = []; + var p; + + var unhandled = function(ev) { + if (ev.promise === p) { + t.step(function() { + unhandledPromises.push(ev.promise); + unhandledReasons.push(ev.reason.name); + }); + } + }; + var handled = function(ev) { + if (ev.promise === p) { + t.step(function() { + assert_array_equals(unhandledPromises, [p]); + assert_array_equals(unhandledReasons, ['InvalidStateError']); + assert_equals(ev.promise, p); + assert_equals(ev.reason.name, 'InvalidStateError'); + }); + } + }; + addEventListener('unhandledrejection', unhandled); + addEventListener('rejectionhandled', handled); + ensureCleanup(t, unhandled, handled); + + p = createImageBitmap(new Blob()); + setTimeout(function() { + var unreached = t.unreached_func('promise should not be fulfilled'); + p.then(unreached, function(reason) { + assert_equals(reason.name, 'InvalidStateError'); + setTimeout(function() { t.done(); }, 10); + }); + }, 10); +}, 'delayed handling: delaying handling rejected promise created from createImageBitmap will cause both events to fire'); + +// +// Miscellaneous tests about integration with the rest of the platform +// + +async_test(function(t) { + var e = new Error(); + var l = function(ev) { + var order = []; + mutationObserverMicrotask(function() { + order.push(1); + }); + setTimeout(function() { + order.push(2); + t.step(function() { + assert_array_equals(order, [1, 2]); + }); + t.done(); + }, 1); + }; + addEventListener('unhandledrejection', l); + ensureCleanup(t, l); + Promise.reject(e); +}, 'mutationObserverMicrotask vs. queueTask ordering is not disturbed inside unhandledrejection events'); + +// For workers, queueTask() involves posting tasks to other threads, so +// the following tests don't work there. + +if ('document' in self) { + + // For the next two see https://github.com/domenic/unhandled-rejections-browser-spec/issues/2#issuecomment-121121695 + // and the following comments. + + async_test(function(t) { + var sequenceOfEvents = []; + + addEventListener('unhandledrejection', l); + ensureCleanup(t, l); + + var p1 = Promise.reject(); + var p2; + queueTask(function() { + p2 = Promise.reject(); + queueTask(function() { + sequenceOfEvents.push('queueTask'); + checkSequence(); + }); + }); + + function l(ev) { + if (ev.promise === p1 || ev.promise === p2) { + sequenceOfEvents.push(ev.promise); + checkSequence(); + } + } + + function checkSequence() { + if (sequenceOfEvents.length === 3) { + t.step(function() { + assert_array_equals(sequenceOfEvents, [p1, 'queueTask', p2]); + }); + t.done(); + } + } + }, 'queueTask ordering vs. the task queued for unhandled rejection notification (1)'); + + async_test(function(t) { + var sequenceOfEvents = []; + + addEventListener('unhandledrejection', l); + ensureCleanup(t, l); + + var p2; + queueTask(function() { + p2 = Promise.reject(); + queueTask(function() { + sequenceOfEvents.push('queueTask'); + checkSequence(); + }); + }); + + function l(ev) { + if (ev.promise == p2) { + sequenceOfEvents.push(ev.promise); + checkSequence(); + } + } + + function checkSequence() { + if (sequenceOfEvents.length === 2) { + t.step(function() { + assert_array_equals(sequenceOfEvents, ['queueTask', p2]); + }); + t.done(); + } + } + }, 'queueTask ordering vs. the task queued for unhandled rejection notification (2)'); + + async_test(function(t) { + var sequenceOfEvents = []; + + + addEventListener('unhandledrejection', unhandled); + addEventListener('rejectionhandled', handled); + ensureCleanup(t, unhandled, handled); + + var p = Promise.reject(); + + function unhandled(ev) { + if (ev.promise === p) { + sequenceOfEvents.push('unhandled'); + checkSequence(); + setTimeout(function() { + queueTask(function() { + sequenceOfEvents.push('task before catch'); + checkSequence(); + }); + + p.catch(function() { + sequenceOfEvents.push('catch'); + checkSequence(); + }); + + queueTask(function() { + sequenceOfEvents.push('task after catch'); + checkSequence(); + }); + + sequenceOfEvents.push('after catch'); + checkSequence(); + }, 10); + } + } + + function handled(ev) { + if (ev.promise === p) { + sequenceOfEvents.push('handled'); + checkSequence(); + } + } + + function checkSequence() { + if (sequenceOfEvents.length === 6) { + t.step(function() { + assert_array_equals(sequenceOfEvents, + ['unhandled', 'after catch', 'catch', 'task before catch', 'handled', 'task after catch']); + }); + t.done(); + } + } + }, 'rejectionhandled is dispatched from a queued task, and not immediately'); +} + +// +// HELPERS +// + +// This function queues a task in "DOM manipulation task source" in window +// context, but not in workers. +function queueTask(f) { + if ('document' in self) { + var d = document.createElement("details"); + d.ontoggle = function() { + f(); + }; + d.setAttribute("open", ""); + } else { + // We need to fix this to use something that can queue tasks in + // "DOM manipulation task source" to ensure the order is correct + var channel = new MessageChannel(); + channel.port1.onmessage = function() { channel.port1.close(); f(); }; + channel.port2.postMessage('abusingpostmessageforfunandprofit'); + channel.port2.close(); + } +} + +function mutationObserverMicrotask(f) { + if ('document' in self) { + var observer = new MutationObserver(function() { f(); }); + var node = document.createTextNode(''); + observer.observe(node, { characterData: true }); + node.data = 'foo'; + } else { + // We don't have mutation observers on workers, so just post a promise-based + // microtask. + Promise.resolve().then(function() { f(); }); + } +} + +function onUnhandledSucceed(t, expectedReason, expectedPromiseGetter) { + var l = function(ev) { + if (ev.promise === expectedPromiseGetter()) { + t.step(function() { + assert_equals(ev.reason, expectedReason); + assert_equals(ev.promise, expectedPromiseGetter()); + }); + t.done(); + } + }; + addEventListener('unhandledrejection', l); + ensureCleanup(t, l); +} + +function onUnhandledFail(t, expectedPromiseGetter) { + var unhandled = function(evt) { + if (evt.promise === expectedPromiseGetter()) { + t.step(function() { + assert_unreached('unhandledrejection event is not supposed to be triggered'); + }); + } + }; + var handled = function(evt) { + if (evt.promise === expectedPromiseGetter()) { + t.step(function() { + assert_unreached('rejectionhandled event is not supposed to be triggered'); + }); + } + }; + addEventListener('unhandledrejection', unhandled); + addEventListener('rejectionhandled', handled); + ensureCleanup(t, unhandled, handled); + setTimeout(function() { + t.done(); + }, 10); +} + +function ensureCleanup(t, unhandled, handled) { + t.add_cleanup(function() { + if (unhandled) + removeEventListener('unhandledrejection', unhandled); + if (handled) + removeEventListener('rejectionhandled', handled); + }); +} + +done(); |