node/test/parallel/test-repl-preview.js
Adam Majer df8db42082
test: skip some console tests on dumb terminal
Add capabilities to common test module to detect and skip tests
on dumb terminals.

In some of our build environments, like s390x, the terminal
is a dumb terminal meaning it has very rudimentary capabilities.
These in turn prevent some of the tests from completing with errors
as below.

    not ok 1777 parallel/test-readline-tab-complete
      ---
      duration_ms: 0.365
      severity: fail
      exitcode: 1
      stack: |-
        assert.js:103
          throw new AssertionError(obj);
          ^

        AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:

        '\t' !== ''

            at /home/abuild/rpmbuild/BUILD/node-git.8698dd98bb/test/parallel/test-readline-tab-complete.js:63:14
            at Array.forEach (<anonymous>)
            at /home/abuild/rpmbuild/BUILD/node-git.8698dd98bb/test/parallel/test-readline-tab-complete.js:18:17
            at Array.forEach (<anonymous>)
            at Object.<anonymous> (/home/abuild/rpmbuild/BUILD/node-git.8698dd98bb/test/parallel/test-readline-tab-complete.js:17:3)
            at Module._compile (internal/modules/cjs/loader.js:1176:30)
            at Object.Module._extensions..js (internal/modules/cjs/loader.js:1196:10)
            at Module.load (internal/modules/cjs/loader.js:1040:32)
            at Function.Module._load (internal/modules/cjs/loader.js:929:14)
            at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12) {
          generatedMessage: true,
          code: 'ERR_ASSERTION',
          actual: '\t',
          expected: '',
          operator: 'strictEqual'
        }
      ...

PR-URL: https://github.com/nodejs/node/pull/33165
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
2020-05-08 01:26:01 +02:00

195 lines
5.4 KiB
JavaScript

'use strict';
const common = require('../common');
const assert = require('assert');
const { REPLServer } = require('repl');
const { Stream } = require('stream');
const { inspect } = require('util');
common.skipIfInspectorDisabled();
common.skipIfDumbTerminal();
const PROMPT = 'repl > ';
class REPLStream extends Stream {
readable = true;
writable = true;
constructor() {
super();
this.lines = [''];
}
run(data) {
for (const entry of data) {
this.emit('data', entry);
}
this.emit('data', '\n');
}
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);
});
}
pause() {}
resume() {}
}
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 = REPLServer({
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 = [{
input: 'foo',
noPreview: '[Function: foo]',
preview: [
'foo',
'\x1B[90m[Function: foo]\x1B[39m\x1B[11G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r',
'\x1B[36m[Function: foo]\x1B[39m'
]
}, {
input: 'koo',
noPreview: '[Function: koo]',
preview: [
'k\x1B[90moo\x1B[39m\x1B[9G\x1B[0Ko\x1B[90mo\x1B[39m\x1B[10G\x1B[0Ko',
'\x1B[90m[Function: koo]\x1B[39m\x1B[11G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r',
'\x1B[36m[Function: koo]\x1B[39m'
]
}, {
input: 'a',
noPreview: 'repl > ', // No "undefined" output.
preview: ['a\r'] // No "undefined" preview.
}, {
input: " { b: 1 }['b'] === 1",
noPreview: '\x1B[33mtrue\x1B[39m',
preview: [
" { b: 1 }['b']",
'\x1B[90m1\x1B[39m\x1B[22G\x1B[1A\x1B[1B\x1B[2K\x1B[1A ',
'\x1B[90m1\x1B[39m\x1B[23G\x1B[1A\x1B[1B\x1B[2K\x1B[1A=== 1',
'\x1B[90mtrue\x1B[39m\x1B[28G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r',
'\x1B[33mtrue\x1B[39m'
]
}, {
input: "{ b: 1 }['b'] === 1;",
noPreview: '\x1B[33mfalse\x1B[39m',
preview: [
"{ b: 1 }['b']",
'\x1B[90m1\x1B[39m\x1B[21G\x1B[1A\x1B[1B\x1B[2K\x1B[1A ',
'\x1B[90m1\x1B[39m\x1B[22G\x1B[1A\x1B[1B\x1B[2K\x1B[1A=== 1',
'\x1B[90mtrue\x1B[39m\x1B[27G\x1B[1A\x1B[1B\x1B[2K\x1B[1A;',
'\x1B[90mfalse\x1B[39m\x1B[28G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r',
'\x1B[33mfalse\x1B[39m'
]
}, {
input: '{ a: true }',
noPreview: '{ a: \x1B[33mtrue\x1B[39m }',
preview: [
'{ a: tru\x1B[90me\x1B[39m\x1B[16G\x1B[0Ke }\r',
'{ a: \x1B[33mtrue\x1B[39m }'
]
}, {
input: '{ a: true };',
noPreview: '\x1B[33mtrue\x1B[39m',
preview: [
'{ a: tru\x1B[90me\x1B[39m\x1B[16G\x1B[0Ke };',
'\x1B[90mtrue\x1B[39m\x1B[20G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r',
'\x1B[33mtrue\x1B[39m'
]
}, {
input: ' \t { a: true};',
noPreview: '\x1B[33mtrue\x1B[39m',
preview: [
' { a: tru\x1B[90me\x1B[39m\x1B[18G\x1B[0Ke}',
'\x1B[90m{ a: true }\x1B[39m\x1B[20G\x1B[1A\x1B[1B\x1B[2K\x1B[1A;',
'\x1B[90mtrue\x1B[39m\x1B[21G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r',
'\x1B[33mtrue\x1B[39m'
]
}, {
input: '1n + 2n',
noPreview: '\x1B[33m3n\x1B[39m',
preview: [
'1n + 2',
'\x1B[90mType[39m\x1B[14G\x1B[1A\x1B[1B\x1B[2K\x1B[1An',
'\x1B[90m3n\x1B[39m\x1B[15G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r',
'\x1B[33m3n\x1B[39m'
]
}, {
input: '{};1',
noPreview: '\x1B[33m1\x1B[39m',
preview: [
'{};1',
'\x1B[90m1\x1B[39m\x1B[12G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r',
'\x1B[33m1\x1B[39m'
]
}];
const hasPreview = repl.terminal &&
(options.preview !== undefined ? !!options.preview : true);
for (const { input, noPreview, preview } of testCases) {
console.log(`Testing ${input}`);
const toBeRun = input.split('\n');
let lines = await runAndWait(toBeRun, repl);
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.strictEqual(lines.pop(), '\x1B[1G\x1B[0Jrepl > \x1B[8G');
assert.deepStrictEqual(lines, preview);
} else {
assert.ok(lines[0].includes(noPreview), lines.map(inspect));
if (preview.length !== 1 || preview[0] !== `${input}\r`)
assert.strictEqual(lines.length, 2);
}
}
}
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