diff --git a/lib/internal/repl.js b/lib/internal/repl.js index 76412c3b118a8c..812af56ed2e046 100644 --- a/lib/internal/repl.js +++ b/lib/internal/repl.js @@ -8,7 +8,7 @@ const os = require('os'); const util = require('util'); const debug = util.debuglog('repl'); module.exports = Object.create(REPL); -module.exports.createInternalRepl = createInternalRepl; +module.exports.createInternalRepl = createRepl; // XXX(chrisdickinson): The 15ms debounce value is somewhat arbitrary. // The debounce is to guard against code pasted into the REPL. @@ -19,7 +19,7 @@ function _writeToOutput(repl, message) { repl._refreshLine(); } -function createInternalRepl(env, opts, cb) { +function createRepl(env, opts, cb) { if (typeof opts === 'function') { cb = opts; opts = null; diff --git a/lib/repl.js b/lib/repl.js index 2227953fa86468..84682b1b63e6cc 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -109,11 +109,6 @@ writer.options = Object.assign({}, exports._builtinLibs = internalModule.builtinLibs; -const sep = '\u0000\u0000\u0000'; -const regExMatcher = new RegExp(`^${sep}(.*)${sep}(.*)${sep}(.*)${sep}(.*)` + - `${sep}(.*)${sep}(.*)${sep}(.*)${sep}(.*)` + - `${sep}(.*)$`); - function REPLServer(prompt, stream, eval_, @@ -154,7 +149,6 @@ function REPLServer(prompt, } var self = this; - replMap.set(self, self); self._domain = dom || domain.create(); self.useGlobal = !!useGlobal; @@ -171,6 +165,41 @@ function REPLServer(prompt, self.rli = this; const savedRegExMatches = ['', '', '', '', '', '', '', '', '', '']; + const sep = '\u0000\u0000\u0000'; + const regExMatcher = new RegExp(`^${sep}(.*)${sep}(.*)${sep}(.*)${sep}(.*)` + + `${sep}(.*)${sep}(.*)${sep}(.*)${sep}(.*)` + + `${sep}(.*)$`); + + eval_ = eval_ || defaultEval; + + // Pause taking in new input, and store the keys in a buffer. + const pausedBuffer = []; + let paused = false; + function pause() { + paused = true; + } + function unpause() { + if (!paused) return; + paused = false; + let entry; + while (entry = pausedBuffer.shift()) { + const [type, payload] = entry; + switch (type) { + case 'key': { + const [d, key] = payload; + self._ttyWrite(d, key); + break; + } + case 'close': + self.emit('exit'); + break; + } + if (paused) { + break; + } + } + } + function defaultEval(code, context, file, cb) { var err, result, script, wrappedErr; var wrappedCmd = false; @@ -302,6 +331,7 @@ function REPLServer(prompt, if (awaitPromise && !err) { let sigintListener; + pause(); let promise = result; if (self.breakEvalOnSigint) { const interrupt = new Promise((resolve, reject) => { @@ -320,6 +350,7 @@ function REPLServer(prompt, prioritizedSigintQueue.delete(sigintListener); finishExecution(undefined, result); + unpause(); }, (err) => { // Remove prioritized SIGINT listener if it was not called. prioritizedSigintQueue.delete(sigintListener); @@ -329,6 +360,7 @@ function REPLServer(prompt, Object.defineProperty(err, 'stack', { value: '' }); } + unpause(); if (err && process.domain) { debug('not recoverable, send to domain'); process.domain.emit('error', err); @@ -345,36 +377,6 @@ function REPLServer(prompt, } } - eval_ = eval_ || defaultEval; - - // Pause taking in new input, and store the keys in a buffer. - const pausedBuffer = []; - let paused = false; - function pause() { - paused = true; - } - function unpause() { - if (!paused) return; - paused = false; - let entry; - while (entry = pausedBuffer.shift()) { - const [type, payload] = entry; - switch (type) { - case 'key': { - const [d, key] = payload; - self._ttyWrite(d, key); - break; - } - case 'close': - self.emit('exit'); - break; - } - if (paused) { - break; - } - } - } - self.eval = self._domain.bind(eval_); self._domain.on('error', function debugDomainError(e) { @@ -403,7 +405,6 @@ function REPLServer(prompt, top.clearBufferedCommand(); top.lines.level = []; top.displayPrompt(); - unpause(); }); if (!input && !output) { @@ -592,7 +593,6 @@ function REPLServer(prompt, const evalCmd = self[kBufferedCommandSymbol] + cmd + '\n'; debug('eval %j', evalCmd); - pause(); self.eval(evalCmd, self.context, 'repl', finish); function finish(e, ret) { @@ -605,7 +605,6 @@ function REPLServer(prompt, '(Press Control-D to exit.)\n'); self.clearBufferedCommand(); self.displayPrompt(); - unpause(); return; } @@ -643,7 +642,6 @@ function REPLServer(prompt, // Display prompt again self.displayPrompt(); - unpause(); } }); @@ -726,6 +724,7 @@ exports.start = function(prompt, ignoreUndefined, replMode); if (!exports.repl) exports.repl = repl; + replMap.set(repl, repl); return repl; }; diff --git a/test/parallel/test-repl-autolibs.js b/test/parallel/test-repl-autolibs.js index 68f8402ddbfdaa..52234deb5e732e 100644 --- a/test/parallel/test-repl-autolibs.js +++ b/test/parallel/test-repl-autolibs.js @@ -29,22 +29,7 @@ const repl = require('repl'); common.globalCheck = false; const putIn = new common.ArrayStream(); - - -const replserver = repl.start('', putIn, null, true); -const callbacks = []; -const $eval = replserver.eval; -replserver.eval = function(code, context, file, cb) { - const expected = callbacks.shift(); - return $eval.call(this, code, context, file, (...args) => { - try { - expected(cb, ...args); - } catch (e) { - console.error(e); - process.exit(1); - } - }); -}; +repl.start('', putIn, null, true); test1(); @@ -63,11 +48,6 @@ function test1() { } }; assert(!gotWrite); - callbacks.push(common.mustCall((cb, err, result) => { - assert.ifError(err); - assert.strictEqual(result, require('fs')); - cb(err, result); - })); putIn.run(['fs']); assert(gotWrite); } @@ -86,11 +66,6 @@ function test2() { const val = {}; global.url = val; assert(!gotWrite); - callbacks.push(common.mustCall((cb, err, result) => { - assert.ifError(err); - assert.strictEqual(result, val); - cb(err, result); - })); putIn.run(['url']); assert(gotWrite); } diff --git a/test/parallel/test-repl-context.js b/test/parallel/test-repl-context.js index 90364cee694bb5..9d18067bc2aca4 100644 --- a/test/parallel/test-repl-context.js +++ b/test/parallel/test-repl-context.js @@ -27,57 +27,40 @@ function testContext(repl) { repl.close(); } -const replserver = repl.start({ input: stream, output: stream }); -const callbacks = []; -const $eval = replserver.eval; -replserver.eval = function(code, context, file, cb) { - const expected = callbacks.shift(); - return $eval.call(this, code, context, file, (...args) => { - try { - expected(cb, ...args); - } catch (e) { - console.error(e); - process.exit(1); - } - }); -}; -testContextSideEffects(replserver); +testContextSideEffects(repl.start({ input: stream, output: stream })); function testContextSideEffects(server) { assert.ok(!server.underscoreAssigned); assert.strictEqual(server.lines.length, 0); // an assignment to '_' in the repl server - callbacks.push(common.mustCall((cb, ...args) => { - assert.ok(server.underscoreAssigned); - assert.strictEqual(server.last, 500); - cb(...args); - assert.strictEqual(server.lines.length, 1); - assert.strictEqual(server.lines[0], '_ = 500;'); + server.write('_ = 500;\n'); + assert.ok(server.underscoreAssigned); + assert.strictEqual(server.lines.length, 1); + assert.strictEqual(server.lines[0], '_ = 500;'); + assert.strictEqual(server.last, 500); - // use the server to create a new context - const context = server.createContext(); + // use the server to create a new context + const context = server.createContext(); - // ensure that creating a new context does not - // have side effects on the server - assert.ok(server.underscoreAssigned); - assert.strictEqual(server.lines.length, 1); - assert.strictEqual(server.lines[0], '_ = 500;'); - assert.strictEqual(server.last, 500); + // ensure that creating a new context does not + // have side effects on the server + assert.ok(server.underscoreAssigned); + assert.strictEqual(server.lines.length, 1); + assert.strictEqual(server.lines[0], '_ = 500;'); + assert.strictEqual(server.last, 500); - // reset the server context - server.resetContext(); - assert.ok(!server.underscoreAssigned); - assert.strictEqual(server.lines.length, 0); + // reset the server context + server.resetContext(); + assert.ok(!server.underscoreAssigned); + assert.strictEqual(server.lines.length, 0); - // ensure that assigning to '_' in the new context - // does not change the value in our server. - assert.ok(!server.underscoreAssigned); - vm.runInContext('_ = 1000;\n', context); + // ensure that assigning to '_' in the new context + // does not change the value in our server. + assert.ok(!server.underscoreAssigned); + vm.runInContext('_ = 1000;\n', context); - assert.ok(!server.underscoreAssigned); - assert.strictEqual(server.lines.length, 0); - server.close(); - })); - server.write('_ = 500;\n'); + assert.ok(!server.underscoreAssigned); + assert.strictEqual(server.lines.length, 0); + server.close(); } diff --git a/test/parallel/test-repl-end-emits-exit.js b/test/parallel/test-repl-end-emits-exit.js index dd9ad5c1eb0e56..67f667eeb3d8db 100644 --- a/test/parallel/test-repl-end-emits-exit.js +++ b/test/parallel/test-repl-end-emits-exit.js @@ -21,7 +21,10 @@ 'use strict'; const common = require('../common'); +const assert = require('assert'); const repl = require('repl'); +let terminalExit = 0; +let regularExit = 0; // Create a dummy stream that does nothing const stream = new common.ArrayStream(); @@ -38,10 +41,11 @@ function testTerminalMode() { stream.emit('data', '\u0004'); }); - r1.on('exit', common.mustCall(function() { + r1.on('exit', function() { // should be fired from the simulated ^D keypress + terminalExit++; testRegularMode(); - })); + }); } function testRegularMode() { @@ -55,11 +59,17 @@ function testRegularMode() { stream.emit('end'); }); - r2.on('exit', common.mustCall(function() { + r2.on('exit', function() { // should be fired from the simulated 'end' event - })); + regularExit++; + }); } +process.on('exit', function() { + assert.strictEqual(terminalExit, 1); + assert.strictEqual(regularExit, 1); +}); + // start testTerminalMode(); diff --git a/test/parallel/test-repl-eval-scope.js b/test/parallel/test-repl-eval-scope.js index 83311fd92cd67b..00b577cba73f76 100644 --- a/test/parallel/test-repl-eval-scope.js +++ b/test/parallel/test-repl-eval-scope.js @@ -3,27 +3,21 @@ const common = require('../common'); const assert = require('assert'); const repl = require('repl'); -const exitTests = []; -process.on('exit', () => { - for (const test of exitTests) test(); -}); -const CONTEXT = { animal: 'Sterrance' }; -const stream = new common.ArrayStream(); -const options = { - eval: common.mustCall((cmd, context) => { - // need to escape the domain - exitTests.push(common.mustCall(() => { - assert.strictEqual(cmd, '.scope'); - assert.ok(context === CONTEXT); - })); - }), - input: stream, - output: stream, - terminal: true -}; +{ + const stream = new common.ArrayStream(); + const options = { + eval: common.mustCall((cmd, context) => { + assert.strictEqual(cmd, '.scope\n'); + assert.deepStrictEqual(context, { animal: 'Sterrance' }); + }), + input: stream, + output: stream, + terminal: true + }; -const r = repl.start(options); -r.context = CONTEXT; + const r = repl.start(options); + r.context = { animal: 'Sterrance' }; -stream.emit('data', '\t'); -stream.emit('.exit\n'); + stream.emit('data', '\t'); + stream.emit('.exit\n'); +} diff --git a/test/parallel/test-repl-eval.js b/test/parallel/test-repl-eval.js index d7290a1583da58..d775423fb74a52 100644 --- a/test/parallel/test-repl-eval.js +++ b/test/parallel/test-repl-eval.js @@ -3,31 +3,31 @@ const common = require('../common'); const assert = require('assert'); const repl = require('repl'); -const exitTests = []; -process.on('exit', () => { - for (const test of exitTests) test(); -}); -const options = { - eval: common.mustCall((cmd, context) => { - // Assertions here will not cause the test to exit with an error code - // so set a boolean that is checked later instead. - exitTests.push(common.mustCall(() => { - assert.strictEqual(cmd, 'function f() {}\n'); - assert.strictEqual(context.foo, 'bar'); - })); - }) -}; +{ + let evalCalledWithExpectedArgs = false; -const r = repl.start(options); -r.context = { foo: 'bar' }; + const options = { + eval: common.mustCall((cmd, context) => { + // Assertions here will not cause the test to exit with an error code + // so set a boolean that is checked later instead. + evalCalledWithExpectedArgs = (cmd === 'function f() {}\n' && + context.foo === 'bar'); + }) + }; -try { - // Default preprocessor transforms - // function f() {} to - // var f = function f() {} - // Test to ensure that original input is preserved. - // Reference: https://github.com/nodejs/node/issues/9743 - r.write('function f() {}\n'); -} finally { - r.write('.exit\n'); + const r = repl.start(options); + r.context = { foo: 'bar' }; + + try { + // Default preprocessor transforms + // function f() {} to + // var f = function f() {} + // Test to ensure that original input is preserved. + // Reference: https://github.com/nodejs/node/issues/9743 + r.write('function f() {}\n'); + } finally { + r.write('.exit\n'); + } + + assert(evalCalledWithExpectedArgs); } diff --git a/test/parallel/test-repl-function-definition-edge-case.js b/test/parallel/test-repl-function-definition-edge-case.js index bda40594a8876a..1e3063e3db53ff 100644 --- a/test/parallel/test-repl-function-definition-edge-case.js +++ b/test/parallel/test-repl-function-definition-edge-case.js @@ -7,47 +7,32 @@ const stream = require('stream'); common.globalCheck = false; -const input = new stream(); -input.write = input.pause = input.resume = () => {}; -input.readable = true; - -const output = new stream(); -output.writable = true; -output.accumulator = []; - -output.write = (data) => output.accumulator.push(data); - -const replserver = repl.start({ - input, - output, - useColors: false, - terminal: false, - prompt: '' -}); -const callbacks = []; -const $eval = replserver.eval; -replserver.eval = function(code, context, file, cb) { - const expected = callbacks.shift(); - return $eval.call(this, code, context, file, (...args) => { - try { - expected(...args); - } catch (e) { - console.error(e); - process.exit(1); - } - cb(...args); +const r = initRepl(); + +r.input.emit('data', 'function a() { return 42; } (1)\n'); +r.input.emit('data', 'a\n'); +r.input.emit('data', '.exit'); + +const expected = '1\n[Function: a]\n'; +const got = r.output.accumulator.join(''); +assert.strictEqual(got, expected); + +function initRepl() { + const input = new stream(); + input.write = input.pause = input.resume = () => {}; + input.readable = true; + + const output = new stream(); + output.writable = true; + output.accumulator = []; + + output.write = (data) => output.accumulator.push(data); + + return repl.start({ + input, + output, + useColors: false, + terminal: false, + prompt: '' }); -}; - -callbacks.push(common.mustCall((err, result) => { - assert.ifError(err); - assert.strictEqual(result, 1); -})); -replserver.input.emit('data', 'function a() { return 42; } (1)\n'); -callbacks.push(common.mustCall((err, result) => { - assert.ifError(err); - assert.strictEqual(typeof result, 'function'); - assert.strictEqual(result.toString(), 'function a() { return 42; }'); -})); -replserver.input.emit('data', 'a\n'); -replserver.input.emit('data', '.exit'); +} diff --git a/test/parallel/test-repl-load-multiline.js b/test/parallel/test-repl-load-multiline.js index 922aef3d493901..8ab878ae768ddd 100644 --- a/test/parallel/test-repl-load-multiline.js +++ b/test/parallel/test-repl-load-multiline.js @@ -36,7 +36,5 @@ const r = repl.start({ }); r.write(`${command}\n`); -r.on('exit', common.mustCall(() => { - assert.strictEqual(accum.replace(terminalCodeRegex, ''), expected); -})); +assert.strictEqual(accum.replace(terminalCodeRegex, ''), expected); r.close(); diff --git a/test/parallel/test-repl-mode.js b/test/parallel/test-repl-mode.js index 39d7ff88cce905..60b430d8c7ee31 100644 --- a/test/parallel/test-repl-mode.js +++ b/test/parallel/test-repl-mode.js @@ -19,49 +19,35 @@ tests.forEach(function(test) { function testSloppyMode() { const cli = initRepl(repl.REPL_MODE_SLOPPY); - cli.callbacks.push(common.mustCall((err, result) => { - assert.ifError(err); - assert.strictEqual(result, 3); - })); cli.input.emit('data', 'x = 3\n'); + assert.strictEqual(cli.output.accumulator.join(''), '> 3\n> '); + cli.output.accumulator.length = 0; - cli.callbacks.push(common.mustCall((err, result) => { - assert.ifError(err); - assert.strictEqual(result, undefined); - })); cli.input.emit('data', 'let y = 3\n'); + assert.strictEqual(cli.output.accumulator.join(''), 'undefined\n> '); } function testStrictMode() { const cli = initRepl(repl.REPL_MODE_STRICT); - cli._domain.once('error', common.mustCall((err) => { - assert.ok(err); - assert.ok(/ReferenceError: x is not defined/.test(err.message)); - })); cli.input.emit('data', 'x = 3\n'); + assert.ok(/ReferenceError: x is not defined/.test( + cli.output.accumulator.join(''))); + cli.output.accumulator.length = 0; - cli.callbacks.push(common.mustCall((err, result) => { - assert.ifError(err); - assert.strictEqual(result, undefined); - })); cli.input.emit('data', 'let y = 3\n'); + assert.strictEqual(cli.output.accumulator.join(''), 'undefined\n> '); } function testAutoMode() { const cli = initRepl(repl.REPL_MODE_MAGIC); - cli.callbacks.push(common.mustCall((err, result) => { - assert.ifError(err); - assert.strictEqual(result, 3); - })); cli.input.emit('data', 'x = 3\n'); + assert.strictEqual(cli.output.accumulator.join(''), '> 3\n> '); + cli.output.accumulator.length = 0; - cli.callbacks.push(common.mustCall((err, result) => { - assert.ifError(err); - assert.strictEqual(result, undefined); - })); cli.input.emit('data', 'let y = 3\n'); + assert.strictEqual(cli.output.accumulator.join(''), 'undefined\n> '); } function initRepl(mode) { @@ -76,28 +62,11 @@ function initRepl(mode) { output.accumulator = []; output.writable = true; - const replserver = repl.start({ + return repl.start({ input: input, output: output, useColors: false, terminal: false, replMode: mode }); - const callbacks = []; - const $eval = replserver.eval; - replserver.eval = function(code, context, file, cb) { - const expected = callbacks.shift(); - return $eval.call(this, code, context, file, (...args) => { - console.log('EVAL RET', args); - try { - expected(...args); - } catch (e) { - console.error(e); - process.exit(1); - } - cb(...args); - }); - }; - replserver.callbacks = callbacks; - return replserver; } diff --git a/test/parallel/test-repl-null-thrown.js b/test/parallel/test-repl-null-thrown.js index 9b78b0b1dc4d6d..1fe5d30396d534 100644 --- a/test/parallel/test-repl-null-thrown.js +++ b/test/parallel/test-repl-null-thrown.js @@ -1,5 +1,5 @@ 'use strict'; -const common = require('../common'); +require('../common'); const repl = require('repl'); const assert = require('assert'); const Stream = require('stream'); @@ -18,6 +18,7 @@ const replserver = repl.start({ replserver.emit('line', 'process.nextTick(() => { throw null; })'); replserver.emit('line', '.exit'); -replserver.on('exit', common.mustCall(() => { +setTimeout(() => { + console.log(text); assert(text.includes('Thrown: null')); -})); +}, 0); diff --git a/test/parallel/test-repl-null.js b/test/parallel/test-repl-null.js index 2748cfa780ee16..66d09b28f28b84 100644 --- a/test/parallel/test-repl-null.js +++ b/test/parallel/test-repl-null.js @@ -1,28 +1,9 @@ 'use strict'; -const common = require('../common'); +require('../common'); const repl = require('repl'); const assert = require('assert'); -const callbacks = [ - common.mustCall((err, value) => { - assert.ifError(err); - assert.strictEqual(value, undefined); - }) -]; const replserver = new repl.REPLServer(); -const $eval = replserver.eval; -replserver.eval = function(code, context, file, cb) { - const expected = callbacks.shift(); - return $eval.call(this, code, context, file, (...args) => { - try { - expected(...args); - } catch (e) { - console.error(e); - process.exit(1); - } - cb(...args); - }); -}; replserver._inTemplateLiteral = true; diff --git a/test/parallel/test-repl-pretty-custom-stack.js b/test/parallel/test-repl-pretty-custom-stack.js index 0ca4039a5f8e36..be102c1d677a9c 100644 --- a/test/parallel/test-repl-pretty-custom-stack.js +++ b/test/parallel/test-repl-pretty-custom-stack.js @@ -22,9 +22,7 @@ function run({ command, expected }) { }); r.write(`${command}\n`); - r.on('exit', common.mustCall(() => { - assert.strictEqual(accum, expected); - })); + assert.strictEqual(accum, expected); r.close(); } diff --git a/test/parallel/test-repl-pretty-stack.js b/test/parallel/test-repl-pretty-stack.js index 55f37e1703e52d..0fc6b3ada04c79 100644 --- a/test/parallel/test-repl-pretty-stack.js +++ b/test/parallel/test-repl-pretty-stack.js @@ -22,9 +22,7 @@ function run({ command, expected }) { }); r.write(`${command}\n`); - r.on('exit', common.mustCall(() => { - assert.strictEqual(accum, expected); - })); + assert.strictEqual(accum, expected); r.close(); } diff --git a/test/parallel/test-repl-recoverable.js b/test/parallel/test-repl-recoverable.js index c1767bbc4db03b..6788d84595066c 100644 --- a/test/parallel/test-repl-recoverable.js +++ b/test/parallel/test-repl-recoverable.js @@ -4,11 +4,14 @@ const common = require('../common'); const assert = require('assert'); const repl = require('repl'); +let evalCount = 0; let recovered = false; let rendered = false; function customEval(code, context, file, cb) { - return cb(!recovered ? new repl.Recoverable() : null, true); + evalCount++; + + return cb(evalCount === 1 ? new repl.Recoverable() : null, true); } const putIn = new common.ArrayStream(); @@ -23,7 +26,7 @@ putIn.write = function(msg) { } }; -repl.start('', putIn, common.mustCall(customEval, 2)); +repl.start('', putIn, customEval); // https://github.com/nodejs/node/issues/2939 // Expose recoverable errors to the consumer. @@ -33,4 +36,5 @@ putIn.emit('data', '2\n'); process.on('exit', function() { assert(recovered, 'REPL never recovered'); assert(rendered, 'REPL never rendered the result'); + assert.strictEqual(evalCount, 2); }); diff --git a/test/parallel/test-repl-throw-null-or-undefined.js b/test/parallel/test-repl-throw-null-or-undefined.js index ef25dbe015de88..fd2fd202b5bcb6 100644 --- a/test/parallel/test-repl-throw-null-or-undefined.js +++ b/test/parallel/test-repl-throw-null-or-undefined.js @@ -1,20 +1,18 @@ 'use strict'; -const common = require('../common'); +require('../common'); // This test ensures that the repl does not // crash or emit error when throwing `null|undefined` // ie `throw null` or `throw undefined` +const assert = require('assert'); const repl = require('repl'); -const replserver = repl.start(); -const $eval = replserver.eval; -replserver.eval = function(code, context, file, cb) { - return $eval.call(this, code, context, file, - common.mustNotCall( - 'repl crashes/throw error on `throw null|undefined`')); -}; -replserver.write('throw null\n'); -replserver.write('throw undefined\n'); +const r = repl.start(); -replserver.write('.exit\n'); +assert.doesNotThrow(() => { + r.write('throw null\n'); + r.write('throw undefined\n'); +}, TypeError, 'repl crashes/throw error on `throw null|undefined`'); + +r.write('.exit\n'); diff --git a/test/parallel/test-repl-underscore.js b/test/parallel/test-repl-underscore.js index 1b22dcc7221a7f..91f32223e180b9 100644 --- a/test/parallel/test-repl-underscore.js +++ b/test/parallel/test-repl-underscore.js @@ -28,22 +28,20 @@ function testSloppyMode() { _; // remains 30 from user input `); - r.on('exit', () => { - assertOutput(r.output, [ - 'undefined', - 'undefined', - 'undefined', - '10', - '10', - 'Expression assignment to _ now disabled.', - '20', - '20', - '30', - '30', - '40', - '30' - ]); - }); + assertOutput(r.output, [ + 'undefined', + 'undefined', + 'undefined', + '10', + '10', + 'Expression assignment to _ now disabled.', + '20', + '20', + '30', + '30', + '40', + '30' + ]); } function testStrictMode() { @@ -63,22 +61,20 @@ function testStrictMode() { _; // remains 30 from user input `); - r.on('exit', () => { - assertOutput(r.output, [ - 'undefined', - 'undefined', - 'undefined', - 'undefined', - '20', - '30', - '30', - 'undefined', - '30', - 'undefined', - 'undefined', - '30' - ]); - }); + assertOutput(r.output, [ + 'undefined', + 'undefined', + 'undefined', + 'undefined', + '20', + '30', + '30', + 'undefined', + '30', + 'undefined', + 'undefined', + '30' + ]); } function testMagicMode() { @@ -98,22 +94,20 @@ function testMagicMode() { _; // remains 30 from user input `); - r.on('exit', () => { - assertOutput(r.output, [ - 'undefined', - '10', - '10', - 'undefined', - '20', - '30', - '30', - 'undefined', - '30', - 'undefined', - '50', - '30' - ]); - }); + assertOutput(r.output, [ + 'undefined', + '10', + '10', + 'undefined', + '20', + '30', + '30', + 'undefined', + '30', + 'undefined', + '50', + '30' + ]); } function testResetContext() { @@ -127,17 +121,15 @@ function testResetContext() { _; // expect 20 `); - r.on('exit', () => { - assertOutput(r.output, [ - 'Expression assignment to _ now disabled.', - '10', - '10', - 'Clearing context...', - '10', - '20', - '20' - ]); - }); + assertOutput(r.output, [ + 'Expression assignment to _ now disabled.', + '10', + '10', + 'Clearing context...', + '10', + '20', + '20' + ]); } function testResetContextGlobal() { @@ -149,14 +141,12 @@ function testResetContextGlobal() { _; // remains 10 `); - r.on('exit', () => { - assertOutput(r.output, [ - 'Expression assignment to _ now disabled.', - '10', - '10', - '10', - ]); - }); + assertOutput(r.output, [ + 'Expression assignment to _ now disabled.', + '10', + '10', + '10', + ]); // delete globals leaked by REPL when `useGlobal` is `true` delete global.module; diff --git a/test/parallel/test-repl-use-global.js b/test/parallel/test-repl-use-global.js index 75646a9c00aae7..c76505272b2682 100644 --- a/test/parallel/test-repl-use-global.js +++ b/test/parallel/test-repl-use-global.js @@ -7,6 +7,13 @@ const stream = require('stream'); const repl = require('internal/repl'); const assert = require('assert'); +// Array of [useGlobal, expectedResult] pairs +const globalTestCases = [ + [false, 'undefined'], + [true, '\'tacos\''], + [undefined, 'undefined'] +]; + const globalTest = (useGlobal, cb, output) => (err, repl) => { if (err) return cb(err); @@ -19,12 +26,26 @@ const globalTest = (useGlobal, cb, output) => (err, repl) => { global.lunch = 'tacos'; repl.write('global.lunch;\n'); repl.close(); - repl.on('exit', common.mustCall(() => { - delete global.lunch; - cb(null, str.trim()); - })); + delete global.lunch; + cb(null, str.trim()); }; +// Test how the global object behaves in each state for useGlobal +for (const [option, expected] of globalTestCases) { + runRepl(option, globalTest, common.mustCall((err, output) => { + assert.ifError(err); + assert.strictEqual(output, expected); + })); +} + +// Test how shadowing the process object via `let` +// behaves in each useGlobal state. Note: we can't +// actually test the state when useGlobal is true, +// because the exception that's generated is caught +// (see below), but errors are printed, and the test +// suite is aware of it, causing a failure to be flagged. +// +const processTestCases = [false, undefined]; const processTest = (useGlobal, cb, output) => (err, repl) => { if (err) return cb(err); @@ -36,37 +57,15 @@ const processTest = (useGlobal, cb, output) => (err, repl) => { repl.write('let process;\n'); repl.write('21 * 2;\n'); repl.close(); - repl.on('exit', common.mustCall((err) => { - assert.ifError(err); - cb(null, str.trim()); - })); + cb(null, str.trim()); }; -// Array of [useGlobal, expectedResult, fn] pairs -const testCases = [ - // Test how the global object behaves in each state for useGlobal - [false, 'undefined', globalTest], - [true, '\'tacos\'', globalTest], - [undefined, 'undefined', globalTest], - // Test how shadowing the process object via `let` - // behaves in each useGlobal state. Note: we can't - // actually test the state when useGlobal is true, - // because the exception that's generated is caught - // (see below), but errors are printed, and the test - // suite is aware of it, causing a failure to be flagged. - [false, 'undefined\n42', processTest] -]; - -const next = common.mustCall(() => { - if (testCases.length) { - const [option, expected, runner] = testCases.shift(); - runRepl(option, runner, common.mustCall((err, output) => { - assert.strictEqual(output, expected); - next(); - })); - } -}, testCases.length + 1); -next(); +for (const option of processTestCases) { + runRepl(option, processTest, common.mustCall((err, output) => { + assert.ifError(err); + assert.strictEqual(output, 'undefined\n42'); + })); +} function runRepl(useGlobal, testFunc, cb) { const inputStream = new stream.PassThrough();