summaryrefslogtreecommitdiff
path: root/test/parallel/test-event-capture-rejections.js
diff options
context:
space:
mode:
authorMatteo Collina <hello@matteocollina.com>2019-05-19 13:55:18 +0200
committerMatteo Collina <hello@matteocollina.com>2019-12-03 12:14:46 +0100
commitae8f20ec5eee55f648823392c9c4e9491c958b60 (patch)
treef9ef3febfd46bf4ac19678e2f5e14b45105e8f09 /test/parallel/test-event-capture-rejections.js
parent8cf8eb16ac873c11a6b1051c3a71a91659d431e3 (diff)
downloadandroid-node-v8-ae8f20ec5eee55f648823392c9c4e9491c958b60.tar.gz
android-node-v8-ae8f20ec5eee55f648823392c9c4e9491c958b60.tar.bz2
android-node-v8-ae8f20ec5eee55f648823392c9c4e9491c958b60.zip
events: add captureRejection option
PR-URL: https://github.com/nodejs/node/pull/27867 Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Michaƫl Zasso <targos@protonmail.com>
Diffstat (limited to 'test/parallel/test-event-capture-rejections.js')
-rw-r--r--test/parallel/test-event-capture-rejections.js297
1 files changed, 297 insertions, 0 deletions
diff --git a/test/parallel/test-event-capture-rejections.js b/test/parallel/test-event-capture-rejections.js
new file mode 100644
index 0000000000..83da3184a6
--- /dev/null
+++ b/test/parallel/test-event-capture-rejections.js
@@ -0,0 +1,297 @@
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const { EventEmitter, captureRejectionSymbol } = require('events');
+const { inherits } = require('util');
+
+// Inherits from EE without a call to the
+// parent constructor.
+function NoConstructor() {
+}
+
+inherits(NoConstructor, EventEmitter);
+
+function captureRejections() {
+ const ee = new EventEmitter({ captureRejections: true });
+ const _err = new Error('kaboom');
+ ee.on('something', common.mustCall(async (value) => {
+ throw _err;
+ }));
+
+ ee.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, _err);
+ process.nextTick(captureRejectionsTwoHandlers);
+ }));
+
+ ee.emit('something');
+}
+
+function captureRejectionsTwoHandlers() {
+ const ee = new EventEmitter({ captureRejections: true });
+ const _err = new Error('kaboom');
+
+ ee.on('something', common.mustCall(async (value) => {
+ throw _err;
+ }));
+
+ // throw twice
+ ee.on('something', common.mustCall(async (value) => {
+ throw _err;
+ }));
+
+ let count = 0;
+
+ ee.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, _err);
+ if (++count === 2) {
+ process.nextTick(defaultValue);
+ }
+ }, 2));
+
+ ee.emit('something');
+}
+
+function defaultValue() {
+ const ee = new EventEmitter();
+ const _err = new Error('kaboom');
+ ee.on('something', common.mustCall(async (value) => {
+ throw _err;
+ }));
+
+ process.removeAllListeners('unhandledRejection');
+
+ process.once('unhandledRejection', common.mustCall((err) => {
+ // restore default
+ process.on('unhandledRejection', (err) => { throw err; });
+
+ assert.strictEqual(err, _err);
+ process.nextTick(globalSetting);
+ }));
+
+ ee.emit('something');
+}
+
+function globalSetting() {
+ assert.strictEqual(EventEmitter.captureRejections, false);
+ EventEmitter.captureRejections = true;
+ const ee = new EventEmitter();
+ const _err = new Error('kaboom');
+ ee.on('something', common.mustCall(async (value) => {
+ throw _err;
+ }));
+
+ ee.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, _err);
+
+ // restore default
+ EventEmitter.captureRejections = false;
+ process.nextTick(configurable);
+ }));
+
+ ee.emit('something');
+}
+
+// We need to be able to configure this for streams, as we would
+// like to call destro(err) there.
+function configurable() {
+ const ee = new EventEmitter({ captureRejections: true });
+ const _err = new Error('kaboom');
+ ee.on('something', common.mustCall(async (...args) => {
+ assert.deepStrictEqual(args, [42, 'foobar']);
+ throw _err;
+ }));
+
+ assert.strictEqual(captureRejectionSymbol, Symbol.for('nodejs.rejection'));
+
+ ee[captureRejectionSymbol] = common.mustCall((err, type, ...args) => {
+ assert.strictEqual(err, _err);
+ assert.strictEqual(type, 'something');
+ assert.deepStrictEqual(args, [42, 'foobar']);
+ process.nextTick(globalSettingNoConstructor);
+ });
+
+ ee.emit('something', 42, 'foobar');
+}
+
+function globalSettingNoConstructor() {
+ assert.strictEqual(EventEmitter.captureRejections, false);
+ EventEmitter.captureRejections = true;
+ const ee = new NoConstructor();
+ const _err = new Error('kaboom');
+ ee.on('something', common.mustCall(async (value) => {
+ throw _err;
+ }));
+
+ ee.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, _err);
+
+ // restore default
+ EventEmitter.captureRejections = false;
+ process.nextTick(thenable);
+ }));
+
+ ee.emit('something');
+}
+
+function thenable() {
+ const ee = new EventEmitter({ captureRejections: true });
+ const _err = new Error('kaboom');
+ ee.on('something', common.mustCall((value) => {
+ const obj = {};
+
+ Object.defineProperty(obj, 'then', {
+ get: common.mustCall(() => {
+ return common.mustCall((resolved, rejected) => {
+ assert.strictEqual(resolved, undefined);
+ rejected(_err);
+ });
+ }, 1) // Only 1 call for Promises/A+ compat.
+ });
+
+ return obj;
+ }));
+
+ ee.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, _err);
+ process.nextTick(avoidLoopOnRejection);
+ }));
+
+ ee.emit('something');
+}
+
+function avoidLoopOnRejection() {
+ const ee = new EventEmitter({ captureRejections: true });
+ const _err1 = new Error('kaboom');
+ const _err2 = new Error('kaboom2');
+ ee.on('something', common.mustCall(async (value) => {
+ throw _err1;
+ }));
+
+ ee[captureRejectionSymbol] = common.mustCall(async (err) => {
+ assert.strictEqual(err, _err1);
+ throw _err2;
+ });
+
+ process.removeAllListeners('unhandledRejection');
+
+ process.once('unhandledRejection', common.mustCall((err) => {
+ // restore default
+ process.on('unhandledRejection', (err) => { throw err; });
+
+ assert.strictEqual(err, _err2);
+ process.nextTick(avoidLoopOnError);
+ }));
+
+ ee.emit('something');
+}
+
+function avoidLoopOnError() {
+ const ee = new EventEmitter({ captureRejections: true });
+ const _err1 = new Error('kaboom');
+ const _err2 = new Error('kaboom2');
+ ee.on('something', common.mustCall(async (value) => {
+ throw _err1;
+ }));
+
+ ee.on('error', common.mustCall(async (err) => {
+ assert.strictEqual(err, _err1);
+ throw _err2;
+ }));
+
+ process.removeAllListeners('unhandledRejection');
+
+ process.once('unhandledRejection', common.mustCall((err) => {
+ // restore default
+ process.on('unhandledRejection', (err) => { throw err; });
+
+ assert.strictEqual(err, _err2);
+ process.nextTick(thenableThatThrows);
+ }));
+
+ ee.emit('something');
+}
+
+function thenableThatThrows() {
+ const ee = new EventEmitter({ captureRejections: true });
+ const _err = new Error('kaboom');
+ ee.on('something', common.mustCall((value) => {
+ const obj = {};
+
+ Object.defineProperty(obj, 'then', {
+ get: common.mustCall(() => {
+ throw _err;
+ }, 1) // Only 1 call for Promises/A+ compat.
+ });
+
+ return obj;
+ }));
+
+ ee.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, _err);
+ process.nextTick(resetCaptureOnThrowInError);
+ }));
+
+ ee.emit('something');
+}
+
+function resetCaptureOnThrowInError() {
+ const ee = new EventEmitter({ captureRejections: true });
+ ee.on('something', common.mustCall(async (value) => {
+ throw new Error('kaboom');
+ }));
+
+ ee.once('error', common.mustCall((err) => {
+ throw err;
+ }));
+
+ process.removeAllListeners('uncaughtException');
+
+ process.once('uncaughtException', common.mustCall((err) => {
+ process.nextTick(next);
+ }));
+
+ ee.emit('something');
+
+ function next() {
+ process.on('uncaughtException', common.mustNotCall());
+
+ const _err = new Error('kaboom2');
+ ee.on('something2', common.mustCall(async (value) => {
+ throw _err;
+ }));
+
+ ee.on('error', common.mustCall((err) => {
+ assert.strictEqual(err, _err);
+
+ process.removeAllListeners('uncaughtException');
+
+ // restore default
+ process.on('uncaughtException', (err) => { throw err; });
+
+ process.nextTick(argValidation);
+ }));
+
+ ee.emit('something2');
+ }
+}
+
+function argValidation() {
+
+ function testType(obj) {
+ common.expectsError(() => new EventEmitter({ captureRejections: obj }), {
+ code: 'ERR_INVALID_ARG_TYPE',
+ type: TypeError
+ });
+
+ common.expectsError(() => EventEmitter.captureRejections = obj, {
+ code: 'ERR_INVALID_ARG_TYPE',
+ type: TypeError
+ });
+ }
+
+ testType([]);
+ testType({ hello: 42 });
+ testType(42);
+}
+
+captureRejections();