mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
1c7795e52e
PR-URL: https://github.com/nodejs/node/pull/54705 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
634 lines
21 KiB
JavaScript
634 lines
21 KiB
JavaScript
import * as common from '../common/index.mjs';
|
|
import * as fixtures from '../common/fixtures.mjs';
|
|
import { join } from 'node:path';
|
|
import { describe, it, run } from 'node:test';
|
|
import { dot, spec, tap } from 'node:test/reporters';
|
|
import assert from 'node:assert';
|
|
import util from 'node:util';
|
|
|
|
const testFixtures = fixtures.path('test-runner');
|
|
|
|
describe('require(\'node:test\').run', { concurrency: true }, () => {
|
|
it('should run with no tests', async () => {
|
|
const stream = run({ files: [] });
|
|
stream.on('test:fail', common.mustNotCall());
|
|
stream.on('test:pass', common.mustNotCall());
|
|
// eslint-disable-next-line no-unused-vars
|
|
for await (const _ of stream);
|
|
});
|
|
|
|
it('should fail with non existing file', async () => {
|
|
const stream = run({ files: ['a-random-file-that-does-not-exist.js'] });
|
|
stream.on('test:fail', common.mustCall(1));
|
|
stream.on('test:pass', common.mustNotCall());
|
|
// eslint-disable-next-line no-unused-vars
|
|
for await (const _ of stream);
|
|
});
|
|
|
|
it('should succeed with a file', async () => {
|
|
const stream = run({ files: [join(testFixtures, 'default-behavior/test/random.cjs')] });
|
|
stream.on('test:fail', common.mustNotCall());
|
|
stream.on('test:pass', common.mustCall(1));
|
|
// eslint-disable-next-line no-unused-vars
|
|
for await (const _ of stream);
|
|
});
|
|
|
|
const argPrintingFile = join(testFixtures, 'print-arguments.js');
|
|
it('should allow custom arguments via execArgv', async () => {
|
|
const result = await run({ files: [argPrintingFile], execArgv: ['-p', '"Printed"'] }).compose(spec).toArray();
|
|
assert.strictEqual(result[0].toString(), 'Printed\n');
|
|
});
|
|
|
|
it('should allow custom arguments via argv', async () => {
|
|
const stream = run({ files: [argPrintingFile], argv: ['--a-custom-argument'] });
|
|
stream.on('test:fail', common.mustNotCall());
|
|
stream.on('test:pass', common.mustCall());
|
|
// eslint-disable-next-line no-unused-vars
|
|
for await (const _ of stream);
|
|
});
|
|
|
|
it('should run same file twice', async () => {
|
|
const stream = run({
|
|
files: [
|
|
join(testFixtures, 'default-behavior/test/random.cjs'),
|
|
join(testFixtures, 'default-behavior/test/random.cjs'),
|
|
]
|
|
});
|
|
stream.on('test:fail', common.mustNotCall());
|
|
stream.on('test:pass', common.mustCall(2));
|
|
// eslint-disable-next-line no-unused-vars
|
|
for await (const _ of stream);
|
|
});
|
|
|
|
it('should run a failed test', async () => {
|
|
const stream = run({ files: [testFixtures] });
|
|
stream.on('test:fail', common.mustCall(1));
|
|
stream.on('test:pass', common.mustNotCall());
|
|
// eslint-disable-next-line no-unused-vars
|
|
for await (const _ of stream);
|
|
});
|
|
|
|
it('should support timeout', async () => {
|
|
const stream = run({ timeout: 50, files: [
|
|
fixtures.path('test-runner', 'never_ending_sync.js'),
|
|
fixtures.path('test-runner', 'never_ending_async.js'),
|
|
] });
|
|
stream.on('test:fail', common.mustCall(2));
|
|
stream.on('test:pass', common.mustNotCall());
|
|
// eslint-disable-next-line no-unused-vars
|
|
for await (const _ of stream);
|
|
});
|
|
|
|
it('should be piped with dot', async () => {
|
|
const result = await run({
|
|
files: [join(testFixtures, 'default-behavior/test/random.cjs')]
|
|
}).compose(dot).toArray();
|
|
|
|
assert.strictEqual(result.length, 2);
|
|
assert.strictEqual(util.stripVTControlCharacters(result[0]), '.');
|
|
assert.strictEqual(result[1], '\n');
|
|
});
|
|
|
|
describe('should be piped with spec reporter', () => {
|
|
it('new spec', async () => {
|
|
const specReporter = new spec();
|
|
const result = await run({
|
|
files: [join(testFixtures, 'default-behavior/test/random.cjs')]
|
|
}).compose(specReporter).toArray();
|
|
const stringResults = result.map((bfr) => bfr.toString());
|
|
assert.match(stringResults[0], /this should pass/);
|
|
assert.match(stringResults[1], /tests 1/);
|
|
assert.match(stringResults[1], /pass 1/);
|
|
});
|
|
|
|
it('spec()', async () => {
|
|
const specReporter = spec();
|
|
const result = await run({
|
|
files: [join(testFixtures, 'default-behavior/test/random.cjs')]
|
|
}).compose(specReporter).toArray();
|
|
const stringResults = result.map((bfr) => bfr.toString());
|
|
assert.match(stringResults[0], /this should pass/);
|
|
assert.match(stringResults[1], /tests 1/);
|
|
assert.match(stringResults[1], /pass 1/);
|
|
});
|
|
|
|
it('spec', async () => {
|
|
const result = await run({
|
|
files: [join(testFixtures, 'default-behavior/test/random.cjs')]
|
|
}).compose(spec).toArray();
|
|
const stringResults = result.map((bfr) => bfr.toString());
|
|
assert.match(stringResults[0], /this should pass/);
|
|
assert.match(stringResults[1], /tests 1/);
|
|
assert.match(stringResults[1], /pass 1/);
|
|
});
|
|
});
|
|
|
|
it('should be piped with tap', async () => {
|
|
const result = await run({
|
|
files: [join(testFixtures, 'default-behavior/test/random.cjs')]
|
|
}).compose(tap).toArray();
|
|
assert.strictEqual(result.length, 13);
|
|
assert.strictEqual(result[0], 'TAP version 13\n');
|
|
assert.strictEqual(result[1], '# Subtest: this should pass\n');
|
|
assert.strictEqual(result[2], 'ok 1 - this should pass\n');
|
|
assert.match(result[3], /duration_ms: \d+\.?\d*/);
|
|
assert.strictEqual(result[4], '1..1\n');
|
|
assert.strictEqual(result[5], '# tests 1\n');
|
|
assert.strictEqual(result[6], '# suites 0\n');
|
|
assert.strictEqual(result[7], '# pass 1\n');
|
|
assert.strictEqual(result[8], '# fail 0\n');
|
|
assert.strictEqual(result[9], '# cancelled 0\n');
|
|
assert.strictEqual(result[10], '# skipped 0\n');
|
|
assert.strictEqual(result[11], '# todo 0\n');
|
|
assert.match(result[12], /# duration_ms \d+\.?\d*/);
|
|
});
|
|
|
|
it('should skip tests not matching testNamePatterns - RegExp', async () => {
|
|
const result = await run({
|
|
files: [join(testFixtures, 'default-behavior/test/skip_by_name.cjs')],
|
|
testNamePatterns: [/executed/]
|
|
})
|
|
.compose(tap)
|
|
.toArray();
|
|
|
|
assert.strictEqual(result[2], 'ok 1 - this should be executed\n');
|
|
assert.strictEqual(result[4], '1..1\n');
|
|
assert.strictEqual(result[5], '# tests 1\n');
|
|
});
|
|
|
|
it('should skip tests not matching testNamePatterns - string', async () => {
|
|
const result = await run({
|
|
files: [join(testFixtures, 'default-behavior/test/skip_by_name.cjs')],
|
|
testNamePatterns: ['executed']
|
|
})
|
|
.compose(tap)
|
|
.toArray();
|
|
assert.strictEqual(result[2], 'ok 1 - this should be executed\n');
|
|
assert.strictEqual(result[4], '1..1\n');
|
|
assert.strictEqual(result[5], '# tests 1\n');
|
|
});
|
|
|
|
it('should pass only to children', async () => {
|
|
const result = await run({
|
|
files: [join(testFixtures, 'test_only.js')],
|
|
only: true
|
|
})
|
|
.compose(tap)
|
|
.toArray();
|
|
|
|
assert.strictEqual(result[2], 'ok 1 - this should be executed\n');
|
|
assert.strictEqual(result[4], '1..1\n');
|
|
assert.strictEqual(result[5], '# tests 1\n');
|
|
});
|
|
|
|
it('should emit "test:watch:drained" event on watch mode', async () => {
|
|
const controller = new AbortController();
|
|
await run({
|
|
files: [join(testFixtures, 'default-behavior/test/random.cjs')],
|
|
watch: true,
|
|
signal: controller.signal,
|
|
}).on('data', function({ type }) {
|
|
if (type === 'test:watch:drained') {
|
|
controller.abort();
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('AbortSignal', () => {
|
|
it('should accept a signal', async () => {
|
|
const stream = run({ signal: AbortSignal.timeout(50), files: [
|
|
fixtures.path('test-runner', 'never_ending_sync.js'),
|
|
fixtures.path('test-runner', 'never_ending_async.js'),
|
|
] });
|
|
stream.on('test:fail', common.mustCall(2));
|
|
stream.on('test:pass', common.mustNotCall());
|
|
// eslint-disable-next-line no-unused-vars
|
|
for await (const _ of stream);
|
|
});
|
|
|
|
it('should stop watch mode when abortSignal aborts', async () => {
|
|
const controller = new AbortController();
|
|
const result = await run({
|
|
files: [join(testFixtures, 'default-behavior/test/random.cjs')],
|
|
watch: true,
|
|
signal: controller.signal,
|
|
})
|
|
.compose(async function* (source) {
|
|
let waitForCancel = 2;
|
|
for await (const chunk of source) {
|
|
if (chunk.type === 'test:watch:drained' ||
|
|
(chunk.type === 'test:diagnostic' && chunk.data.message.startsWith('duration_ms'))) {
|
|
waitForCancel--;
|
|
}
|
|
if (waitForCancel === 0) {
|
|
controller.abort();
|
|
}
|
|
if (chunk.type === 'test:pass') {
|
|
yield chunk.data.name;
|
|
}
|
|
}
|
|
})
|
|
.toArray();
|
|
assert.deepStrictEqual(result, ['this should pass']);
|
|
});
|
|
|
|
it('should abort when test succeeded', async () => {
|
|
const stream = run({
|
|
files: [
|
|
fixtures.path(
|
|
'test-runner',
|
|
'aborts',
|
|
'successful-test-still-call-abort.js'
|
|
),
|
|
],
|
|
});
|
|
|
|
let passedTestCount = 0;
|
|
let failedTestCount = 0;
|
|
|
|
let output = '';
|
|
for await (const data of stream) {
|
|
if (data.type === 'test:stdout') {
|
|
output += data.data.message.toString();
|
|
}
|
|
if (data.type === 'test:fail') {
|
|
failedTestCount++;
|
|
}
|
|
if (data.type === 'test:pass') {
|
|
passedTestCount++;
|
|
}
|
|
}
|
|
|
|
assert.match(output, /abort called for test 1/);
|
|
assert.match(output, /abort called for test 2/);
|
|
assert.strictEqual(failedTestCount, 0, new Error('no tests should fail'));
|
|
assert.strictEqual(passedTestCount, 2);
|
|
});
|
|
|
|
it('should abort when test failed', async () => {
|
|
const stream = run({
|
|
files: [
|
|
fixtures.path(
|
|
'test-runner',
|
|
'aborts',
|
|
'failed-test-still-call-abort.js'
|
|
),
|
|
],
|
|
});
|
|
|
|
let passedTestCount = 0;
|
|
let failedTestCount = 0;
|
|
|
|
let output = '';
|
|
for await (const data of stream) {
|
|
if (data.type === 'test:stdout') {
|
|
output += data.data.message.toString();
|
|
}
|
|
if (data.type === 'test:fail') {
|
|
failedTestCount++;
|
|
}
|
|
if (data.type === 'test:pass') {
|
|
passedTestCount++;
|
|
}
|
|
}
|
|
|
|
assert.match(output, /abort called for test 1/);
|
|
assert.match(output, /abort called for test 2/);
|
|
assert.strictEqual(passedTestCount, 0, new Error('no tests should pass'));
|
|
assert.strictEqual(failedTestCount, 2);
|
|
});
|
|
});
|
|
|
|
describe('sharding', () => {
|
|
const shardsTestsFixtures = fixtures.path('test-runner', 'shards');
|
|
const shardsTestsFiles = [
|
|
'a.cjs',
|
|
'b.cjs',
|
|
'c.cjs',
|
|
'd.cjs',
|
|
'e.cjs',
|
|
'f.cjs',
|
|
'g.cjs',
|
|
'h.cjs',
|
|
'i.cjs',
|
|
'j.cjs',
|
|
].map((file) => join(shardsTestsFixtures, file));
|
|
|
|
describe('validation', () => {
|
|
it('should require shard.total when having shard option', () => {
|
|
assert.throws(() => run({ files: shardsTestsFiles, shard: {} }), {
|
|
name: 'TypeError',
|
|
code: 'ERR_INVALID_ARG_TYPE',
|
|
message: 'The "options.shard.total" property must be of type number. Received undefined'
|
|
});
|
|
});
|
|
|
|
it('should require shard.index when having shards option', () => {
|
|
assert.throws(() => run({
|
|
files: shardsTestsFiles,
|
|
shard: {
|
|
total: 5
|
|
}
|
|
}), {
|
|
name: 'TypeError',
|
|
code: 'ERR_INVALID_ARG_TYPE',
|
|
message: 'The "options.shard.index" property must be of type number. Received undefined'
|
|
});
|
|
});
|
|
|
|
it('should require shard.total to be greater than 0 when having shard option', () => {
|
|
assert.throws(() => run({
|
|
files: shardsTestsFiles,
|
|
shard: {
|
|
total: 0,
|
|
index: 1
|
|
}
|
|
}), {
|
|
name: 'RangeError',
|
|
code: 'ERR_OUT_OF_RANGE',
|
|
message:
|
|
'The value of "options.shard.total" is out of range. It must be >= 1 && <= 9007199254740991. Received 0'
|
|
});
|
|
});
|
|
|
|
it('should require shard.index to be greater than 0 when having shard option', () => {
|
|
assert.throws(() => run({
|
|
files: shardsTestsFiles,
|
|
shard: {
|
|
total: 6,
|
|
index: 0
|
|
}
|
|
}), {
|
|
name: 'RangeError',
|
|
code: 'ERR_OUT_OF_RANGE',
|
|
message: 'The value of "options.shard.index" is out of range. It must be >= 1 && <= 6. Received 0'
|
|
});
|
|
});
|
|
|
|
it('should require shard.index to not be greater than the shards total when having shard option', () => {
|
|
assert.throws(() => run({
|
|
files: shardsTestsFiles,
|
|
shard: {
|
|
total: 6,
|
|
index: 7
|
|
}
|
|
}), {
|
|
name: 'RangeError',
|
|
code: 'ERR_OUT_OF_RANGE',
|
|
message: 'The value of "options.shard.index" is out of range. It must be >= 1 && <= 6. Received 7'
|
|
});
|
|
});
|
|
|
|
it('should require watch mode to be disabled when having shard option', () => {
|
|
assert.throws(() => run({
|
|
files: shardsTestsFiles,
|
|
watch: true,
|
|
shard: {
|
|
total: 6,
|
|
index: 1
|
|
}
|
|
}), {
|
|
name: 'TypeError',
|
|
code: 'ERR_INVALID_ARG_VALUE',
|
|
message: 'The property \'options.shard\' shards not supported with watch mode. Received true'
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should run only the tests files matching the shard index', async () => {
|
|
const stream = run({
|
|
files: shardsTestsFiles,
|
|
shard: {
|
|
total: 5,
|
|
index: 1
|
|
}
|
|
});
|
|
|
|
const executedTestFiles = [];
|
|
stream.on('test:fail', common.mustNotCall());
|
|
stream.on('test:pass', (passedTest) => {
|
|
executedTestFiles.push(passedTest.file);
|
|
});
|
|
// eslint-disable-next-line no-unused-vars
|
|
for await (const _ of stream) ;
|
|
|
|
assert.deepStrictEqual(executedTestFiles, [
|
|
join(shardsTestsFixtures, 'a.cjs'),
|
|
join(shardsTestsFixtures, 'f.cjs'),
|
|
]);
|
|
});
|
|
|
|
it('different shards should not run the same file', async () => {
|
|
const executedTestFiles = [];
|
|
|
|
const testStreams = [];
|
|
const shards = 5;
|
|
for (let i = 1; i <= shards; i++) {
|
|
const stream = run({
|
|
files: shardsTestsFiles,
|
|
shard: {
|
|
total: shards,
|
|
index: i
|
|
}
|
|
});
|
|
stream.on('test:fail', common.mustNotCall());
|
|
stream.on('test:pass', (passedTest) => {
|
|
executedTestFiles.push(passedTest.file);
|
|
});
|
|
testStreams.push(stream);
|
|
}
|
|
|
|
await Promise.all(testStreams.map(async (stream) => {
|
|
// eslint-disable-next-line no-unused-vars
|
|
for await (const _ of stream) ;
|
|
}));
|
|
|
|
assert.deepStrictEqual(executedTestFiles, [...new Set(executedTestFiles)]);
|
|
});
|
|
|
|
it('combination of all shards should be all the tests', async () => {
|
|
const executedTestFiles = [];
|
|
|
|
const testStreams = [];
|
|
const shards = 5;
|
|
for (let i = 1; i <= shards; i++) {
|
|
const stream = run({
|
|
files: shardsTestsFiles,
|
|
shard: {
|
|
total: shards,
|
|
index: i
|
|
}
|
|
});
|
|
stream.on('test:fail', common.mustNotCall());
|
|
stream.on('test:pass', (passedTest) => {
|
|
executedTestFiles.push(passedTest.file);
|
|
});
|
|
testStreams.push(stream);
|
|
}
|
|
|
|
await Promise.all(testStreams.map(async (stream) => {
|
|
// eslint-disable-next-line no-unused-vars
|
|
for await (const _ of stream) ;
|
|
}));
|
|
|
|
assert.deepStrictEqual(executedTestFiles.sort(), [...shardsTestsFiles].sort());
|
|
});
|
|
});
|
|
|
|
describe('validation', () => {
|
|
it('should only allow array in options.files', async () => {
|
|
[Symbol(), {}, () => {}, 0, 1, 0n, 1n, '', '1', Promise.resolve([]), true, false]
|
|
.forEach((files) => assert.throws(() => run({ files }), {
|
|
code: 'ERR_INVALID_ARG_TYPE'
|
|
}));
|
|
});
|
|
|
|
it('should only allow array in options.globPatterns', async () => {
|
|
[Symbol(), {}, () => {}, 0, 1, 0n, 1n, '', '1', Promise.resolve([]), true, false]
|
|
.forEach((globPatterns) => assert.throws(() => run({ globPatterns }), {
|
|
code: 'ERR_INVALID_ARG_TYPE'
|
|
}));
|
|
});
|
|
|
|
it('should not allow files and globPatterns used together', () => {
|
|
assert.throws(() => run({ files: ['a.js'], globPatterns: ['*.js'] }), {
|
|
code: 'ERR_INVALID_ARG_VALUE'
|
|
});
|
|
});
|
|
|
|
it('should only allow a string in options.cwd', async () => {
|
|
[Symbol(), {}, [], () => {}, 0, 1, 0n, 1n, true, false]
|
|
.forEach((cwd) => assert.throws(() => run({ cwd }), {
|
|
code: 'ERR_INVALID_ARG_TYPE'
|
|
}));
|
|
});
|
|
|
|
it('should only allow object as options', () => {
|
|
[Symbol(), [], () => {}, 0, 1, 0n, 1n, '', '1', true, false]
|
|
.forEach((options) => assert.throws(() => run(options), {
|
|
code: 'ERR_INVALID_ARG_TYPE'
|
|
}));
|
|
});
|
|
|
|
it('should pass instance of stream to setup', async () => {
|
|
const stream = run({
|
|
files: [join(testFixtures, 'default-behavior/test/random.cjs')],
|
|
setup: common.mustCall((root) => {
|
|
assert.strictEqual(root.constructor.name, 'TestsStream');
|
|
}),
|
|
});
|
|
stream.on('test:fail', common.mustNotCall());
|
|
stream.on('test:pass', common.mustCall());
|
|
// eslint-disable-next-line no-unused-vars
|
|
for await (const _ of stream);
|
|
});
|
|
});
|
|
|
|
it('should avoid running recursively', async () => {
|
|
const stream = run({ files: [join(testFixtures, 'recursive_run.js')] });
|
|
let stderr = '';
|
|
stream.on('test:fail', common.mustNotCall());
|
|
stream.on('test:pass', common.mustCall(1));
|
|
stream.on('test:stderr', (c) => { stderr += c.message; });
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
for await (const _ of stream);
|
|
assert.match(stderr, /Warning: node:test run\(\) is being called recursively/);
|
|
});
|
|
|
|
it('should run with different cwd', async () => {
|
|
const stream = run({
|
|
cwd: fixtures.path('test-runner', 'cwd')
|
|
});
|
|
stream.on('test:fail', common.mustNotCall());
|
|
stream.on('test:pass', common.mustCall(1));
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
for await (const _ of stream);
|
|
});
|
|
|
|
it('should handle a non-existent directory being provided as cwd', async () => {
|
|
const diagnostics = [];
|
|
const stream = run({
|
|
cwd: fixtures.path('test-runner', 'cwd', 'non-existing')
|
|
});
|
|
stream.on('test:fail', common.mustNotCall());
|
|
stream.on('test:pass', common.mustNotCall());
|
|
stream.on('test:stderr', common.mustNotCall());
|
|
stream.on('test:diagnostic', ({ message }) => {
|
|
diagnostics.push(message);
|
|
});
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
for await (const _ of stream);
|
|
for (const entry of [
|
|
'tests 0',
|
|
'suites 0',
|
|
'pass 0',
|
|
'fail 0',
|
|
'cancelled 0',
|
|
'skipped 0',
|
|
'todo 0',
|
|
]
|
|
) {
|
|
assert.strictEqual(diagnostics.includes(entry), true);
|
|
}
|
|
});
|
|
|
|
it('should handle a non-existent file being provided as cwd', async () => {
|
|
const diagnostics = [];
|
|
const stream = run({
|
|
cwd: fixtures.path('test-runner', 'default-behavior', 'test', 'random.cjs')
|
|
});
|
|
stream.on('test:fail', common.mustNotCall());
|
|
stream.on('test:pass', common.mustNotCall());
|
|
stream.on('test:stderr', common.mustNotCall());
|
|
stream.on('test:diagnostic', ({ message }) => {
|
|
diagnostics.push(message);
|
|
});
|
|
|
|
// eslint-disable-next-line no-unused-vars
|
|
for await (const _ of stream);
|
|
for (const entry of [
|
|
'tests 0',
|
|
'suites 0',
|
|
'pass 0',
|
|
'fail 0',
|
|
'cancelled 0',
|
|
'skipped 0',
|
|
'todo 0',
|
|
]
|
|
) {
|
|
assert.strictEqual(diagnostics.includes(entry), true);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe('forceExit', () => {
|
|
it('throws for non-boolean values', () => {
|
|
[Symbol(), {}, 0, 1, '1', Promise.resolve([])].forEach((forceExit) => {
|
|
assert.throws(() => run({ forceExit }), {
|
|
code: 'ERR_INVALID_ARG_TYPE',
|
|
message: /The "options\.forceExit" property must be of type boolean\./
|
|
});
|
|
});
|
|
});
|
|
|
|
it('throws if enabled with watch mode', () => {
|
|
assert.throws(() => run({ forceExit: true, watch: true }), {
|
|
code: 'ERR_INVALID_ARG_VALUE',
|
|
message: /The property 'options\.forceExit' is not supported with watch mode\./
|
|
});
|
|
});
|
|
});
|
|
|
|
|
|
// exitHandler doesn't run until after the tests / after hooks finish.
|
|
process.on('exit', () => {
|
|
assert.strictEqual(process.listeners('uncaughtException').length, 0);
|
|
assert.strictEqual(process.listeners('unhandledRejection').length, 0);
|
|
assert.strictEqual(process.listeners('beforeExit').length, 0);
|
|
assert.strictEqual(process.listeners('SIGINT').length, 0);
|
|
assert.strictEqual(process.listeners('SIGTERM').length, 0);
|
|
});
|