diff --git a/lib/internal/test_runner/test.js b/lib/internal/test_runner/test.js index 1663958f9b7..89b8c196038 100644 --- a/lib/internal/test_runner/test.js +++ b/lib/internal/test_runner/test.js @@ -19,6 +19,7 @@ const { once } = require('events'); const { AbortController } = require('internal/abort_controller'); const { codes: { + ERR_INVALID_ARG_TYPE, ERR_TEST_FAILURE, }, kIsNodeError, @@ -33,9 +34,9 @@ const { } = require('internal/util'); const { isPromise } = require('internal/util/types'); const { - isUint32, validateAbortSignal, validateNumber, + validateUint32, } = require('internal/validators'); const { setTimeout } = require('timers/promises'); const { TIMEOUT_MAX } = require('internal/timers'); @@ -149,14 +150,23 @@ class Test extends AsyncResource { this.timeout = parent.timeout; } - if (isUint32(concurrency) && concurrency !== 0) { - this.concurrency = concurrency; - } else if (typeof concurrency === 'boolean') { - if (concurrency) { - this.concurrency = isTestRunner ? MathMax(cpus().length - 1, 1) : Infinity; - } else { - this.concurrency = 1; - } + switch (typeof concurrency) { + case 'number': + validateUint32(concurrency, 'options.concurrency', 1); + this.concurrency = concurrency; + break; + + case 'boolean': + if (concurrency) { + this.concurrency = isTestRunner ? MathMax(cpus().length - 1, 1) : Infinity; + } else { + this.concurrency = 1; + } + break; + + default: + if (concurrency != null) + throw new ERR_INVALID_ARG_TYPE('options.concurrency', ['boolean', 'number'], concurrency); } if (timeout != null && timeout !== Infinity) { diff --git a/test/parallel/test-runner-option-validation.js b/test/parallel/test-runner-option-validation.js index a6b7cb1826b..9d012925361 100644 --- a/test/parallel/test-runner-option-validation.js +++ b/test/parallel/test-runner-option-validation.js @@ -13,3 +13,14 @@ const test = require('node:test'); // Valid values should not throw. test({ timeout }); }); + +[Symbol(), {}, [], () => {}, 1n, '1'].forEach((concurrency) => { + assert.throws(() => test({ concurrency }), { code: 'ERR_INVALID_ARG_TYPE' }); +}); +[-1, 0, 1.1, -Infinity, NaN, 2 ** 33, Number.MAX_SAFE_INTEGER].forEach((concurrency) => { + assert.throws(() => test({ concurrency }), { code: 'ERR_OUT_OF_RANGE' }); +}); +[null, undefined, 1, 2 ** 31, true, false].forEach((concurrency) => { + // Valid values should not throw. + test({ concurrency }); +});