node/test/parallel/test-repl-top-level-await.js
Aras Abbasi cc725a653a
errors: improve performance of instantiation
PR-URL: https://github.com/nodejs/node/pull/49654
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Raz Luvaton <rluvaton@gmail.com>
2023-09-28 09:57:38 +00:00

225 lines
6.3 KiB
JavaScript

'use strict';
const common = require('../common');
const ArrayStream = require('../common/arraystream');
const assert = require('assert');
const events = require('events');
const { stripVTControlCharacters } = require('internal/util/inspect');
const repl = require('repl');
common.skipIfInspectorDisabled();
// Flags: --expose-internals
const PROMPT = 'await repl > ';
class REPLStream extends ArrayStream {
constructor() {
super();
this.waitingForResponse = false;
this.lines = [''];
}
write(chunk, encoding, callback) {
if (Buffer.isBuffer(chunk)) {
chunk = chunk.toString(encoding);
}
const chunkLines = stripVTControlCharacters(chunk).split('\n');
this.lines[this.lines.length - 1] += chunkLines[0];
if (chunkLines.length > 1) {
this.lines.push(...chunkLines.slice(1));
}
this.emit('line', this.lines[this.lines.length - 1]);
if (callback) callback();
return true;
}
async wait() {
if (this.waitingForResponse) {
throw new Error('Currently waiting for response to another command');
}
this.lines = [''];
for await (const [line] of events.on(this, 'line')) {
if (line.includes(PROMPT)) {
return this.lines;
}
}
}
}
const putIn = new REPLStream();
const testMe = repl.start({
prompt: PROMPT,
stream: putIn,
terminal: true,
useColors: true,
breakEvalOnSigint: true
});
function runAndWait(cmds) {
const promise = putIn.wait();
for (const cmd of cmds) {
if (typeof cmd === 'string') {
putIn.run([cmd]);
} else {
testMe.write('', cmd);
}
}
return promise;
}
async function ordinaryTests() {
// These tests were created based on
// https://cs.chromium.org/chromium/src/third_party/WebKit/LayoutTests/http/tests/devtools/console/console-top-level-await.js?rcl=5d0ea979f0ba87655b7ef0e03b58fa3c04986ba6
putIn.run([
'function foo(x) { return x; }',
'function koo() { return Promise.resolve(4); }',
]);
const testCases = [
['await Promise.resolve(0)', '0'],
['{ a: await Promise.resolve(1) }', '{ a: 1 }'],
['_', '{ a: 1 }'],
['let { aa, bb } = await Promise.resolve({ aa: 1, bb: 2 }), f = 5;'],
['aa', '1'],
['bb', '2'],
['f', '5'],
['let cc = await Promise.resolve(2)'],
['cc', '2'],
['let dd;'],
['dd'],
['let [ii, { abc: { kk } }] = [0, { abc: { kk: 1 } }];'],
['ii', '0'],
['kk', '1'],
['var ll = await Promise.resolve(2);'],
['ll', '2'],
['foo(await koo())', '4'],
['_', '4'],
['const m = foo(await koo());'],
['m', '4'],
['const n = foo(await\nkoo());',
['const n = foo(await\r', '... koo());\r', 'undefined']],
['n', '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'],
['for (let i = 0; i < 2; ++i) { await i }'],
['await 0', '0'],
['await 0; function foo() {}'],
['foo', '[Function: foo]'],
['class Foo {}; await 1;', '1'],
['Foo', '[class Foo]'],
['if (await true) { function bar() {}; }'],
['bar', '[Function: bar]'],
['if (await true) { class Bar {}; }'],
['Bar', 'Uncaught ReferenceError: Bar is not defined'],
['await 0; function* gen(){}'],
['for (var i = 0; i < 10; ++i) { await i; }'],
['i', '10'],
['for (let j = 0; j < 5; ++j) { await j; }'],
['j', 'Uncaught ReferenceError: j is not defined', { line: 0 }],
['gen', '[GeneratorFunction: gen]'],
['return 42; await 5;', 'Uncaught SyntaxError: Illegal return statement',
{ line: 3 }],
['let o = await 1, p'],
['p'],
['let q = 1, s = await 2'],
['s', '2'],
['for await (let i of [1,2,3]) console.log(i)',
[
'for await (let i of [1,2,3]) console.log(i)\r',
'1',
'2',
'3',
'undefined',
],
],
['await Promise..resolve()',
[
'await Promise..resolve()\r',
'Uncaught SyntaxError: ',
'await Promise..resolve()',
' ^',
'',
'Unexpected token \'.\'',
],
],
['for (const x of [1,2,3]) {\nawait x\n}', [
'for (const x of [1,2,3]) {\r',
'... await x\r',
'... }\r',
'undefined',
]],
['for (const x of [1,2,3]) {\nawait x;\n}', [
'for (const x of [1,2,3]) {\r',
'... await x;\r',
'... }\r',
'undefined',
]],
['for await (const x of [1,2,3]) {\nconsole.log(x)\n}', [
'for await (const x of [1,2,3]) {\r',
'... console.log(x)\r',
'... }\r',
'1',
'2',
'3',
'undefined',
]],
['for await (const x of [1,2,3]) {\nconsole.log(x);\n}', [
'for await (const x of [1,2,3]) {\r',
'... console.log(x);\r',
'... }\r',
'1',
'2',
'3',
'undefined',
]],
// Regression test for https://github.com/nodejs/node/issues/43777.
['await Promise.resolve(123), Promise.resolve(456)', 'Promise {', { line: 0 }],
['await Promise.resolve(123), await Promise.resolve(456)', '456'],
['await (Promise.resolve(123), Promise.resolve(456))', '456'],
];
for (const [input, expected = [`${input}\r`], options = {}] of testCases) {
console.log(`Testing ${input}`);
const toBeRun = input.split('\n');
const lines = await runAndWait(toBeRun);
if (Array.isArray(expected)) {
if (expected.length === 1)
expected.push('undefined');
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`);
assert.deepStrictEqual(lines, [...echoed, expected, PROMPT]);
}
}
}
async function ctrlCTest() {
console.log('Testing Ctrl+C');
const output = await runAndWait([
'await new Promise(() => {})',
{ ctrl: true, name: 'c' },
]);
assert.deepStrictEqual(output.slice(0, 3), [
'await new Promise(() => {})\r',
'Uncaught:',
'[Error [ERR_SCRIPT_EXECUTION_INTERRUPTED]: ' +
'Script execution was interrupted by `SIGINT`] {',
]);
assert.deepStrictEqual(output.slice(-2), [
'}',
PROMPT,
]);
}
async function main() {
await ordinaryTests();
await ctrlCTest();
}
main().then(common.mustCall());