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+

});