diff --git a/test/parallel/test-repl-user-error-handler.js b/test/parallel/test-repl-user-error-handler.js deleted file mode 100644 index 1b9e591e629a6a..00000000000000 --- a/test/parallel/test-repl-user-error-handler.js +++ /dev/null @@ -1,87 +0,0 @@ -'use strict'; -const common = require('../common'); -const { start } = require('node:repl'); -const assert = require('node:assert'); -const { PassThrough } = require('node:stream'); -const { once } = require('node:events'); -const test = require('node:test'); -const { spawn } = require('node:child_process'); - -common.skipIfInspectorDisabled(); - -function* generateCases() { - for (const async of [false, true]) { - for (const handleErrorReturn of ['ignore', 'print', 'unhandled', 'badvalue']) { - if (handleErrorReturn === 'badvalue') { - // Handled through a separate test using a child process - continue; - } - yield { async, handleErrorReturn }; - } - } -} - -for (const { async, handleErrorReturn } of generateCases()) { - test(`async: ${async}, handleErrorReturn: ${handleErrorReturn}`, async () => { - let err; - const options = { - input: new PassThrough(), - output: new PassThrough().setEncoding('utf8'), - handleError: common.mustCall((e) => { - err = e; - queueMicrotask(() => repl.emit('handled-error')); - return handleErrorReturn; - }) - }; - - let uncaughtExceptionEvent; - if (handleErrorReturn === 'unhandled' && async) { - process.removeAllListeners('uncaughtException'); // Remove the test runner's handler - uncaughtExceptionEvent = once(process, 'uncaughtException'); - } - - const repl = start(options); - - let outputString = ''; - options.output.on('data', (chunk) => { outputString += chunk; }); - - const inputString = async ? - 'setImmediate(() => { throw new Error("testerror") })\n42\n' : - 'throw new Error("testerror")\n42\n'; - options.input.end(inputString); - - await once(repl, 'handled-error'); - assert.strictEqual(err.message, 'testerror'); - while (!/42/.test(outputString)) { - await once(options.output, 'data'); - } - - if (handleErrorReturn === 'print') { - assert.match(outputString, /testerror/); - } else { - assert.doesNotMatch(outputString, /testerror/); - } - - if (uncaughtExceptionEvent) { - const [uncaughtErr] = await uncaughtExceptionEvent; - assert.strictEqual(uncaughtErr, err); - } - }); -} - -test('async: true, handleErrorReturn: badvalue', async () => { - // Can't test this the same way as the other combinations - // since this will take the process down in a way that - // cannot be caught. - const proc = spawn(process.execPath, ['-e', ` - require('node:repl').start({ - handleError: () => 'badvalue' - }) - `], { encoding: 'utf8', stdio: 'pipe' }); - proc.stdin.end('throw new Error("foo");'); - let stderr = ''; - proc.stderr.setEncoding('utf8').on('data', (data) => stderr += data); - const [exit] = await once(proc, 'close'); - assert.strictEqual(exit, 1); - assert.match(stderr, /ERR_INVALID_STATE.+badvalue/); -}); diff --git a/test/parallel/test-repl-user-error-handler.mjs b/test/parallel/test-repl-user-error-handler.mjs new file mode 100644 index 00000000000000..28bd61084ebf2c --- /dev/null +++ b/test/parallel/test-repl-user-error-handler.mjs @@ -0,0 +1,88 @@ +import * as common from '../common/index.mjs'; +import { start } from 'node:repl'; +import assert from 'node:assert'; +import { PassThrough } from 'node:stream'; +import { once } from 'node:events'; +import test from 'node:test'; +import { spawn } from 'node:child_process'; + +common.skipIfInspectorDisabled(); + +function* generateCases() { + for (const async of [false, true]) { + for (const handleErrorReturn of ['ignore', 'print', 'unhandled', 'badvalue']) { + if (handleErrorReturn === 'badvalue') { + // Handled through a separate test using a child process + continue; + } + yield { async, handleErrorReturn }; + } + } +} + +test('repl handleError', async (t) => { + for (const { async, handleErrorReturn } of generateCases()) { + await t.test(`async: ${async}, handleErrorReturn: ${handleErrorReturn}`, async () => { + let err; + const options = { + input: new PassThrough(), + output: new PassThrough().setEncoding('utf8'), + handleError: common.mustCall((e) => { + err = e; + queueMicrotask(() => repl.emit('handled-error')); + return handleErrorReturn; + }) + }; + + let uncaughtExceptionEvent; + if (handleErrorReturn === 'unhandled' && async) { + process.removeAllListeners('uncaughtException'); // Remove the test runner's handler + uncaughtExceptionEvent = once(process, 'uncaughtException'); + } + + const repl = start(options); + + let outputString = ''; + options.output.on('data', (chunk) => { outputString += chunk; }); + + const inputString = async ? + 'setImmediate(() => { throw new Error("testerror") })\n42\n' : + 'throw new Error("testerror")\n42\n'; + options.input.end(inputString); + + await once(repl, 'handled-error'); + assert.strictEqual(err.message, 'testerror'); + while (!/42/.test(outputString)) { + await once(options.output, 'data'); + } + + if (handleErrorReturn === 'print') { + assert.match(outputString, /testerror/); + } else { + assert.doesNotMatch(outputString, /testerror/); + } + + if (uncaughtExceptionEvent) { + const [uncaughtErr] = await uncaughtExceptionEvent; + assert.strictEqual(uncaughtErr, err); + } + }); + } + + await t.test('async: true, handleErrorReturn: badvalue', async () => { + // Can't test this the same way as the other combinations + // since this will take the process down in a way that + // cannot be caught. + const proc = spawn(process.execPath, ['-e', ` + require('node:repl').start({ + handleError: () => 'badvalue' + }) + `], { encoding: 'utf8', stdio: 'pipe' }); + proc.stdin.end('throw new Error("foo");'); + let stderr = ''; + proc.stderr.setEncoding('utf8').on('data', (data) => stderr += data); + const [exit] = await once(proc, 'close'); + assert.strictEqual(exit, 1); + assert.match(stderr, /ERR_INVALID_STATE.+badvalue/); + }); +});