summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/parallel/test-repl-history-navigation.js28
-rw-r--r--test/parallel/test-repl-multiline.js62
-rw-r--r--test/parallel/test-repl-preview.js131
-rw-r--r--test/parallel/test-repl-top-level-await.js101
4 files changed, 255 insertions, 67 deletions
diff --git a/test/parallel/test-repl-history-navigation.js b/test/parallel/test-repl-history-navigation.js
index b00f932aa9..3bd198880f 100644
--- a/test/parallel/test-repl-history-navigation.js
+++ b/test/parallel/test-repl-history-navigation.js
@@ -46,28 +46,50 @@ ActionStream.prototype.readable = true;
const ENTER = { name: 'enter' };
const UP = { name: 'up' };
const DOWN = { name: 'down' };
+const LEFT = { name: 'left' };
+const DELETE = { name: 'delete' };
const prompt = '> ';
+const prev = process.features.inspector;
+
const tests = [
{ // Creates few history to navigate for
env: { NODE_REPL_HISTORY: defaultHistoryPath },
test: [ 'let ab = 45', ENTER,
'555 + 909', ENTER,
- '{key : {key2 :[] }}', ENTER],
+ '{key : {key2 :[] }}', ENTER,
+ 'Array(100).fill(1).map((e, i) => i ** i)', LEFT, LEFT, DELETE,
+ '2', ENTER],
expected: [],
clean: false
},
{
env: { NODE_REPL_HISTORY: defaultHistoryPath },
- test: [UP, UP, UP, UP, DOWN, DOWN, DOWN],
+ test: [UP, UP, UP, UP, UP, DOWN, DOWN, DOWN, DOWN],
expected: [prompt,
+ `${prompt}Array(100).fill(1).map((e, i) => i ** 2)`,
+ prev && '\n// [ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, ' +
+ '144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529,' +
+ ' 576, 625, 676, 729, 784, 841, 900, 961, 1024, 1089, 1156, ' +
+ '1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936,' +
+ ' 2025, 2116, 2209, ...',
`${prompt}{key : {key2 :[] }}`,
+ prev && '\n// { key: { key2: [] } }',
`${prompt}555 + 909`,
+ prev && '\n// 1464',
`${prompt}let ab = 45`,
`${prompt}555 + 909`,
+ prev && '\n// 1464',
`${prompt}{key : {key2 :[] }}`,
- prompt],
+ prev && '\n// { key: { key2: [] } }',
+ `${prompt}Array(100).fill(1).map((e, i) => i ** 2)`,
+ prev && '\n// [ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, ' +
+ '144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529,' +
+ ' 576, 625, 676, 729, 784, 841, 900, 961, 1024, 1089, 1156, ' +
+ '1225, 1296, 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936,' +
+ ' 2025, 2116, 2209, ...',
+ prompt].filter((e) => typeof e === 'string'),
clean: true
}
];
diff --git a/test/parallel/test-repl-multiline.js b/test/parallel/test-repl-multiline.js
index 454d5b1019..6498923b62 100644
--- a/test/parallel/test-repl-multiline.js
+++ b/test/parallel/test-repl-multiline.js
@@ -3,34 +3,44 @@ const common = require('../common');
const ArrayStream = require('../common/arraystream');
const assert = require('assert');
const repl = require('repl');
-const inputStream = new ArrayStream();
-const outputStream = new ArrayStream();
-const input = ['const foo = {', '};', 'foo;'];
-let output = '';
+const input = ['const foo = {', '};', 'foo'];
-outputStream.write = (data) => { output += data.replace('\r', ''); };
+function run({ useColors }) {
+ const inputStream = new ArrayStream();
+ const outputStream = new ArrayStream();
+ let output = '';
-const r = repl.start({
- prompt: '',
- input: inputStream,
- output: outputStream,
- terminal: true,
- useColors: false
-});
+ outputStream.write = (data) => { output += data.replace('\r', ''); };
-r.on('exit', common.mustCall(() => {
- const actual = output.split('\n');
+ const r = repl.start({
+ prompt: '',
+ input: inputStream,
+ output: outputStream,
+ terminal: true,
+ useColors
+ });
- // Validate the output, which contains terminal escape codes.
- assert.strictEqual(actual.length, 6);
- assert.ok(actual[0].endsWith(input[0]));
- assert.ok(actual[1].includes('... '));
- assert.ok(actual[1].endsWith(input[1]));
- assert.strictEqual(actual[2], 'undefined');
- assert.ok(actual[3].endsWith(input[2]));
- assert.strictEqual(actual[4], '{}');
- // Ignore the last line, which is nothing but escape codes.
-}));
+ r.on('exit', common.mustCall(() => {
+ const actual = output.split('\n');
-inputStream.run(input);
-r.close();
+ // Validate the output, which contains terminal escape codes.
+ assert.strictEqual(actual.length, 6 + process.features.inspector);
+ assert.ok(actual[0].endsWith(input[0]));
+ assert.ok(actual[1].includes('... '));
+ assert.ok(actual[1].endsWith(input[1]));
+ assert.ok(actual[2].includes('undefined'));
+ assert.ok(actual[3].endsWith(input[2]));
+ if (process.features.inspector) {
+ assert.ok(actual[4].includes(actual[5]));
+ assert.strictEqual(actual[4].includes('//'), !useColors);
+ }
+ assert.strictEqual(actual[4 + process.features.inspector], '{}');
+ // Ignore the last line, which is nothing but escape codes.
+ }));
+
+ inputStream.run(input);
+ r.close();
+}
+
+run({ useColors: true });
+run({ useColors: false });
diff --git a/test/parallel/test-repl-preview.js b/test/parallel/test-repl-preview.js
new file mode 100644
index 0000000000..92e73dd245
--- /dev/null
+++ b/test/parallel/test-repl-preview.js
@@ -0,0 +1,131 @@
+'use strict';
+
+const common = require('../common');
+const ArrayStream = require('../common/arraystream');
+const assert = require('assert');
+const Repl = require('repl');
+
+common.skipIfInspectorDisabled();
+
+const PROMPT = 'repl > ';
+
+class REPLStream extends ArrayStream {
+ constructor() {
+ super();
+ this.lines = [''];
+ }
+ write(chunk) {
+ const chunkLines = chunk.toString('utf8').split('\n');
+ this.lines[this.lines.length - 1] += chunkLines[0];
+ if (chunkLines.length > 1) {
+ this.lines.push(...chunkLines.slice(1));
+ }
+ this.emit('line');
+ return true;
+ }
+ wait() {
+ this.lines = [''];
+ return new Promise((resolve, reject) => {
+ const onError = (err) => {
+ this.removeListener('line', onLine);
+ reject(err);
+ };
+ const onLine = () => {
+ if (this.lines[this.lines.length - 1].includes(PROMPT)) {
+ this.removeListener('error', onError);
+ this.removeListener('line', onLine);
+ resolve(this.lines);
+ }
+ };
+ this.once('error', onError);
+ this.on('line', onLine);
+ });
+ }
+}
+
+function runAndWait(cmds, repl) {
+ const promise = repl.inputStream.wait();
+ for (const cmd of cmds) {
+ repl.inputStream.run([cmd]);
+ }
+ return promise;
+}
+
+async function tests(options) {
+ const repl = Repl.start({
+ prompt: PROMPT,
+ stream: new REPLStream(),
+ ignoreUndefined: true,
+ useColors: true,
+ ...options
+ });
+
+ repl.inputStream.run([
+ 'function foo(x) { return x; }',
+ 'function koo() { console.log("abc"); }',
+ 'a = undefined;'
+ ]);
+ const testCases = [
+ ['foo', [2, 4], '[Function: foo]',
+ 'foo',
+ '\x1B[90m[Function: foo]\x1B[39m\x1B[1A\x1B[11G\x1B[1B\x1B[2K\x1B[1A\r',
+ '\x1B[36m[Function: foo]\x1B[39m',
+ '\x1B[1G\x1B[0Jrepl > \x1B[8G'],
+ ['koo', [2, 4], '[Function: koo]',
+ 'koo',
+ '\x1B[90m[Function: koo]\x1B[39m\x1B[1A\x1B[11G\x1B[1B\x1B[2K\x1B[1A\r',
+ '\x1B[36m[Function: koo]\x1B[39m',
+ '\x1B[1G\x1B[0Jrepl > \x1B[8G'],
+ ['a', [1, 2], undefined],
+ ['{ a: true }', [2, 3], '{ a: \x1B[33mtrue\x1B[39m }',
+ '{ a: true }\r',
+ '{ a: \x1B[33mtrue\x1B[39m }',
+ '\x1B[1G\x1B[0Jrepl > \x1B[8G'],
+ ['1n + 2n', [2, 5], '\x1B[33m3n\x1B[39m',
+ '1n + 2',
+ '\x1B[90mType[39m\x1B[1A\x1B[14G\x1B[1B\x1B[2K\x1B[1An',
+ '\x1B[90m3n\x1B[39m\x1B[1A\x1B[15G\x1B[1B\x1B[2K\x1B[1A\r',
+ '\x1B[33m3n\x1B[39m',
+ '\x1B[1G\x1B[0Jrepl > \x1B[8G'],
+ ['{ a: true };', [2, 4], '\x1B[33mtrue\x1B[39m',
+ '{ a: true };',
+ '\x1B[90mtrue\x1B[39m\x1B[1A\x1B[20G\x1B[1B\x1B[2K\x1B[1A\r',
+ '\x1B[33mtrue\x1B[39m',
+ '\x1B[1G\x1B[0Jrepl > \x1B[8G'],
+ [' \t { a: true};', [2, 5], '\x1B[33mtrue\x1B[39m',
+ ' \t { a: true}',
+ '\x1B[90m{ a: true }\x1B[39m\x1B[1A\x1B[21G\x1B[1B\x1B[2K\x1B[1A;',
+ '\x1B[90mtrue\x1B[39m\x1B[1A\x1B[22G\x1B[1B\x1B[2K\x1B[1A\r',
+ '\x1B[33mtrue\x1B[39m',
+ '\x1B[1G\x1B[0Jrepl > \x1B[8G']
+ ];
+
+ const hasPreview = repl.terminal &&
+ (options.preview !== undefined ? !!options.preview : true);
+
+ for (const [input, length, expected, ...preview] of testCases) {
+ console.log(`Testing ${input}`);
+
+ const toBeRun = input.split('\n');
+ let lines = await runAndWait(toBeRun, repl);
+
+ assert.strictEqual(lines.length, length[+hasPreview]);
+ if (expected === undefined) {
+ assert(!lines.some((e) => e.includes('undefined')));
+ } else if (hasPreview) {
+ // Remove error messages. That allows the code to run in different
+ // engines.
+ // eslint-disable-next-line no-control-regex
+ lines = lines.map((line) => line.replace(/Error: .+?\x1B/, ''));
+ assert.deepStrictEqual(lines, preview);
+ } else {
+ assert.ok(lines[0].includes(expected), lines);
+ }
+ }
+}
+
+tests({ terminal: false }); // No preview
+tests({ terminal: true }); // Preview
+tests({ terminal: false, preview: false }); // No preview
+tests({ terminal: false, preview: true }); // No preview
+tests({ terminal: true, preview: true }); // Preview
diff --git a/test/parallel/test-repl-top-level-await.js b/test/parallel/test-repl-top-level-await.js
index 5c8aa95d40..cecbd3ab45 100644
--- a/test/parallel/test-repl-top-level-await.js
+++ b/test/parallel/test-repl-top-level-await.js
@@ -1,11 +1,13 @@
'use strict';
-require('../common');
+const common = require('../common');
const ArrayStream = require('../common/arraystream');
const assert = require('assert');
const { stripVTControlCharacters } = require('internal/readline/utils');
const repl = require('repl');
+common.skipIfInspectorDisabled();
+
// Flags: --expose-internals --experimental-repl-await
const PROMPT = 'await repl > ';
@@ -84,61 +86,84 @@ async function ordinaryTests() {
const testCases = [
[ 'await Promise.resolve(0)', '0' ],
[ '{ a: await Promise.resolve(1) }', '{ a: 1 }' ],
- [ '_', '{ a: 1 }' ],
- [ 'let { a, b } = await Promise.resolve({ a: 1, b: 2 }), f = 5;',
+ [ '_', '// { a: 1 }\r', { line: 0 } ],
+ [ 'let { aa, bb } = await Promise.resolve({ aa: 1, bb: 2 }), f = 5;',
'undefined' ],
- [ 'a', '1' ],
- [ 'b', '2' ],
- [ 'f', '5' ],
- [ 'let c = await Promise.resolve(2)', 'undefined' ],
- [ 'c', '2' ],
- [ 'let d;', 'undefined' ],
- [ 'd', 'undefined' ],
- [ 'let [i, { abc: { k } }] = [0, { abc: { k: 1 } }];', 'undefined' ],
- [ 'i', '0' ],
- [ 'k', '1' ],
- [ 'var l = await Promise.resolve(2);', 'undefined' ],
- [ 'l', '2' ],
- [ 'foo(await koo())', '4' ],
- [ '_', '4' ],
- [ 'const m = foo(await koo());', 'undefined' ],
- [ 'm', '4' ],
- [ 'const n = foo(await\nkoo());', 'undefined' ],
- [ 'n', '4' ],
+ [ 'aa', ['// 1\r', '1'] ],
+ [ 'bb', ['// 2\r', '2'] ],
+ [ 'f', ['// 5\r', '5'] ],
+ [ 'let cc = await Promise.resolve(2)', 'undefined' ],
+ [ 'cc', ['// 2\r', '2'] ],
+ [ 'let dd;', 'undefined' ],
+ [ 'dd', 'undefined' ],
+ [ 'let [ii, { abc: { kk } }] = [0, { abc: { kk: 1 } }];', 'undefined' ],
+ [ 'ii', ['// 0\r', '0'] ],
+ [ 'kk', ['// 1\r', '1'] ],
+ [ 'var ll = await Promise.resolve(2);', 'undefined' ],
+ [ 'll', ['// 2\r', '2'] ],
+ [ 'foo(await koo())',
+ [ 'f', '// 5oo', '// [Function: foo](await koo())\r', '4' ] ],
+ [ '_', ['// 4\r', '4'] ],
+ [ 'const m = foo(await koo());',
+ [ 'const m = foo(await koo());\r', 'undefined' ] ],
+ [ 'm', ['// 4\r', '4' ] ],
+ [ 'const n = foo(await\nkoo());',
+ [ 'const n = foo(await\r', '... koo());\r', 'undefined' ] ],
+ [ 'n', ['// 4\r', '4' ] ],
// eslint-disable-next-line no-template-curly-in-string
[ '`status: ${(await Promise.resolve({ status: 200 })).status}`',
"'status: 200'"],
- [ 'for (let i = 0; i < 2; ++i) await i', 'undefined' ],
- [ 'for (let i = 0; i < 2; ++i) { await i }', 'undefined' ],
- [ 'await 0', '0' ],
- [ 'await 0; function foo() {}', 'undefined' ],
- [ 'foo', '[Function: foo]' ],
- [ 'class Foo {}; await 1;', '1' ],
- [ 'Foo', '[Function: Foo]' ],
- [ 'if (await true) { function bar() {}; }', 'undefined' ],
- [ 'bar', '[Function: bar]' ],
+ [ 'for (let i = 0; i < 2; ++i) await i',
+ ['f', '// 5or (let i = 0; i < 2; ++i) await i\r', 'undefined'] ],
+ [ 'for (let i = 0; i < 2; ++i) { await i }',
+ [ 'f', '// 5or (let i = 0; i < 2; ++i) { await i }\r', 'undefined' ] ],
+ [ 'await 0', ['await 0\r', '0'] ],
+ [ 'await 0; function foo() {}',
+ ['await 0; function foo() {}\r', 'undefined'] ],
+ [ 'foo',
+ ['f', '// 5oo', '// [Function: foo]\r', '[Function: foo]'] ],
+ [ 'class Foo {}; await 1;', ['class Foo {}; await 1;\r', '1'] ],
+ [ 'Foo', ['// [Function: Foo]\r', '[Function: Foo]'] ],
+ [ 'if (await true) { function bar() {}; }',
+ ['if (await true) { function bar() {}; }\r', 'undefined'] ],
+ [ 'bar', ['// [Function: bar]\r', '[Function: bar]'] ],
[ 'if (await true) { class Bar {}; }', 'undefined' ],
[ 'Bar', 'Uncaught ReferenceError: Bar is not defined' ],
[ 'await 0; function* gen(){}', 'undefined' ],
- [ 'for (var i = 0; i < 10; ++i) { await i; }', 'undefined' ],
- [ 'i', '10' ],
- [ 'for (let j = 0; j < 5; ++j) { await j; }', 'undefined' ],
- [ 'j', 'Uncaught ReferenceError: j is not defined' ],
- [ 'gen', '[GeneratorFunction: gen]' ],
+ [ 'for (var i = 0; i < 10; ++i) { await i; }',
+ ['f', '// 5or (var i = 0; i < 10; ++i) { await i; }\r', 'undefined'] ],
+ [ 'i', ['// 10\r', '10'] ],
+ [ 'for (let j = 0; j < 5; ++j) { await j; }',
+ ['f', '// 5or (let j = 0; j < 5; ++j) { await j; }\r', 'undefined'] ],
+ [ 'j', 'Uncaught ReferenceError: j is not defined', { line: 0 } ],
+ [ 'gen', ['// [GeneratorFunction: gen]\r', '[GeneratorFunction: gen]'] ],
[ 'return 42; await 5;', 'Uncaught SyntaxError: Illegal return statement',
{ line: 3 } ],
[ 'let o = await 1, p', 'undefined' ],
[ 'p', 'undefined' ],
[ 'let q = 1, s = await 2', 'undefined' ],
- [ 's', '2' ],
- [ 'for await (let i of [1,2,3]) console.log(i)', 'undefined', { line: 3 } ]
+ [ 's', ['// 2\r', '2'] ],
+ [ 'for await (let i of [1,2,3]) console.log(i)',
+ [
+ 'f',
+ '// 5or await (let i of [1,2,3]) console.log(i)\r',
+ '1',
+ '2',
+ '3',
+ 'undefined'
+ ]
+ ]
];
for (const [input, expected, options = {}] of testCases) {
console.log(`Testing ${input}`);
const toBeRun = input.split('\n');
const lines = await runAndWait(toBeRun);
- if ('line' in options) {
+ if (Array.isArray(expected)) {
+ if (lines[0] === input)
+ lines.shift();
+ assert.deepStrictEqual(lines, [...expected, PROMPT]);
+ } else if ('line' in options) {
assert.strictEqual(lines[toBeRun.length + options.line], expected);
} else {
const echoed = toBeRun.map((a, i) => `${i > 0 ? '... ' : ''}${a}\r`);