repl: do not cause side effects in tab completion · nodejs/node@0340fe9
1+'use strict';
2+3+const common = require('../common');
4+const ArrayStream = require('../common/arraystream');
5+const { describe, it } = require('node:test');
6+const assert = require('assert');
7+8+const repl = require('repl');
9+10+function prepareREPL() {
11+const input = new ArrayStream();
12+const replServer = repl.start({
13+prompt: '',
14+ input,
15+output: process.stdout,
16+allowBlockingCompletions: true,
17+});
18+19+// Some errors are passed to the domain, but do not callback
20+replServer._domain.on('error', assert.ifError);
21+22+return { replServer, input };
23+}
24+25+function getNoResultsFunction() {
26+return common.mustSucceed((data) => {
27+assert.deepStrictEqual(data[0], []);
28+});
29+}
30+31+describe('REPL tab completion without side effects', () => {
32+const setup = [
33+'globalThis.counter = 0;',
34+'function incCounter() { return counter++; }',
35+'const arr = [{ bar: "baz" }];',
36+];
37+// None of these expressions should affect the value of `counter`
38+for (const code of [
39+'incCounter().',
40+'a=(counter+=1).foo.',
41+'a=(counter++).foo.',
42+'for((counter)of[1])foo.',
43+'for((counter)in{1:1})foo.',
44+'arr[incCounter()].b',
45+]) {
46+it(`does not evaluate with side effects (${code})`, async () => {
47+const { replServer, input } = prepareREPL();
48+input.run(setup);
49+50+replServer.complete(code, getNoResultsFunction());
51+52+assert.strictEqual(replServer.context.counter, 0);
53+replServer.close();
54+});
55+}
56+});