Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: adding history regression test case #24843

Closed
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions test/parallel/test-repl-history-navigation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
'use strict';

// Flags: --expose-internals

const common = require('../common');
const stream = require('stream');
const REPL = require('internal/repl');
const assert = require('assert');
const fs = require('fs');
const path = require('path');

const tmpdir = require('../common/tmpdir');
tmpdir.refresh();

const defaultHistoryPath = path.join(tmpdir.path, '.node_repl_history');

// Create an input stream specialized for testing an array of actions
class ActionStream extends stream.Stream {
run(data) {
const _iter = data[Symbol.iterator]();
const doAction = () => {
const next = _iter.next();
if (next.done) {
// Close the repl. Note that it must have a clean prompt to do so.
this.emit('keypress', '', { ctrl: true, name: 'd' });
return;
}
const action = next.value;

if (typeof action === 'object') {
this.emit('keypress', '', action);
} else {
this.emit('data', `${action}`);
}
setImmediate(doAction);
};
setImmediate(doAction);
}
resume() {}
pause() {}
}
ActionStream.prototype.readable = true;


// Mock keys
const ENTER = { name: 'enter' };
const UP = { name: 'up' };
const DOWN = { name: 'down' };

const prompt = '> ';

const tests = [
{ // creates few history to navigate for
env: { NODE_REPL_HISTORY: defaultHistoryPath },
test: [ 'let ab = 45', ENTER,
'555 + 909', ENTER,
'{key : {key2 :[] }}', ENTER],
expected: [],
clean: false
},
{
env: { NODE_REPL_HISTORY: defaultHistoryPath },
test: [UP, UP, UP, UP, DOWN, DOWN, DOWN],
expected: [prompt,
`${prompt}{key : {key2 :[] }}`,
`${prompt}555 + 909`,
`${prompt}let ab = 45`,
`${prompt}555 + 909`,
`${prompt}{key : {key2 :[] }}`,
prompt],
clean: true
}
];
const numtests = tests.length;

const runTestWrap = common.mustCall(runTest, numtests);

function cleanupTmpFile() {
try {
// Write over the file, clearing any history
fs.writeFileSync(defaultHistoryPath, '');
} catch (err) {
if (err.code === 'ENOENT') return true;
throw err;
}
return true;
}

function runTest() {
const opts = tests.shift();
if (!opts) return; // All done

const env = opts.env;
const test = opts.test;
const expected = opts.expected;

REPL.createInternalRepl(env, {
input: new ActionStream(),
output: new stream.Writable({
write(chunk, _, next) {
const output = chunk.toString();

if (output.charCodeAt(0) === 27 || /^[\r\n]+$/.test(output)) {
return next();
}

if (expected.length) {
assert.strictEqual(output, expected[0]);
expected.shift();
}

next();
}
}),
prompt: prompt,
useColors: false,
terminal: true
}, function(err, repl) {
if (err) {
console.error(`Failed test # ${numtests - tests.length}`);
throw err;
}

repl.once('close', () => {
if (opts.clean)
cleanupTmpFile();

if (expected.length !== 0) {
throw new Error(`Failed test # ${numtests - tests.length}`);
}
setImmediate(runTestWrap, true);
});

repl.inputStream.run(test);
});
}

// run the tests
runTest();