| Index: LayoutTests/http/tests/dom/resources/promise-rejection-events.js
|
| diff --git a/LayoutTests/http/tests/dom/resources/promise-rejection-events.js b/LayoutTests/http/tests/dom/resources/promise-rejection-events.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8c1555588ae4e1d7c0c84647d32ecdd92e118744
|
| --- /dev/null
|
| +++ b/LayoutTests/http/tests/dom/resources/promise-rejection-events.js
|
| @@ -0,0 +1,668 @@
|
| +'use strict';
|
| +
|
| +if (self.importScripts) {
|
| + if ('ServiceWorkerGlobalScope' in self && self instanceof ServiceWorkerGlobalScope) {
|
| + importScripts('../../serviceworker/resources/worker-testharness.js');
|
| + } else {
|
| + importScripts('../../resources/testharness.js');
|
| + }
|
| +}
|
| +
|
| +//
|
| +// 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) {
|
| + postMessageTask(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');
|
| +
|
| +//
|
| +// 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; });
|
| +
|
| + postMessageTask(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');
|
| +
|
| +//
|
| +// Negative unhandledrejection/rejectionhandled tests with 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; });
|
| +
|
| + postMessageTask(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 postMessageTask');
|
| +
|
| +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; });
|
| +
|
| + postMessageTask(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 postMessageTask');
|
| +
|
| +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');
|
| +
|
| +//
|
| +// 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);
|
| + postMessageTask(function() {
|
| + var unreached = t.unreached_func('promise should not be fulfilled');
|
| + p.then(unreached, function() {});
|
| + });
|
| +}, 'delayed handling: a task delay before attaching a handler does not prevent unhandledrejection');
|
| +
|
| +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 e = new Error();
|
| + var p;
|
| +
|
| + onUnhandledSucceed(t, e, function() { return p; });
|
| +
|
| + p = Promise.reject(e);
|
| + postMessageTask(function() {
|
| + Promise.resolve().then(function() {
|
| + p.catch(function() {});
|
| + });
|
| + });
|
| +}, 'delayed handling: postMessageTask 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; });
|
| + postMessageTask(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: postMessageTask 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);
|
| + postMessageTask(function() {
|
| + Promise.resolve().then(function() {
|
| + Promise.resolve().then(function() {
|
| + Promise.resolve().then(function() {
|
| + Promise.resolve().then(function() {
|
| + p.catch(function() {});
|
| + });
|
| + });
|
| + });
|
| + });
|
| + });
|
| +}, 'delayed handling: postMessageTask after promise creation/rejection, plus many promise microtasks, is too late ' +
|
| + 'to attach a rejection handler');
|
| +
|
| +//
|
| +// 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. postMessageTask ordering is not disturbed inside unhandledrejection events');
|
| +
|
| +//
|
| +// HELPERS
|
| +//
|
| +
|
| +function postMessageTask(f) {
|
| + if ('document' in self) {
|
| + var l = function() {
|
| + removeEventListener('message', l);
|
| + f();
|
| + };
|
| + addEventListener('message', l);
|
| + postMessage('abusingpostmessageforfunandprofit', '*');
|
| + } else {
|
| + 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.unreached_func('unhandledrejection event is not supposed to be triggered');
|
| + }
|
| + };
|
| + var handled = function(evt) {
|
| + if (evt.promise === expectedPromiseGetter()) {
|
| + t.unreached_func('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();
|
|
|