node/test/parallel/test-event-capture-rejections.js
Rich Trott c3fe9072c6
test: add trailing commas in event tests
As much as I would like to do this everywhere and then modify the lint
rule to enforce it, the churn would be too big. However if we're going
to have relatively frequent nits for this sort of thing (as we do), I'd
prefer we migrate a few files at a time to never actually getting around
to doing it.

Ref: https://github.com/nodejs/node/pull/45448#pullrequestreview-1179370442
PR-URL: https://github.com/nodejs/node/pull/45466
Reviewed-By: James M Snell <jasnell@gmail.com>
2022-11-24 11:46:24 -05:00

320 lines
8 KiB
JavaScript

'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() {
}
// captureRejections param validation
{
[1, [], function() {}, {}, Infinity, Math.PI, 'meow'].forEach((arg) => {
assert.throws(
() => new EventEmitter({ captureRejections: arg }),
{
name: 'TypeError',
code: 'ERR_INVALID_ARG_TYPE',
message: 'The "options.captureRejections" property must be of type boolean.' +
common.invalidArgTypeHelper(arg),
}
);
});
}
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) {
const received = obj.constructor.name !== 'Number' ?
`an instance of ${obj.constructor.name}` :
`type number (${obj})`;
assert.throws(() => new EventEmitter({ captureRejections: obj }), {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "options.captureRejections" property must be of type ' +
`boolean. Received ${received}`,
});
assert.throws(() => EventEmitter.captureRejections = obj, {
code: 'ERR_INVALID_ARG_TYPE',
name: 'TypeError',
message: 'The "EventEmitter.captureRejections" property must be of ' +
`type boolean. Received ${received}`,
});
}
testType([]);
testType({ hello: 42 });
testType(42);
}
captureRejections();