How can I implement a test that verifies the different behaviours of stdin.isTTY
in a Node CLI tool?
I have implemented a CLI tool in Node that expects data to be either piped through the terminal or passed as command line args:
cli.js
#!/usr/bin/env node
const { stdin, exit } = require('process');
const parseCliArgs = (argv) => {
// parse args...
return argv;
};
const readFromStdin = async () => {
stdin.setEncoding('utf-8');
return new Promise(((resolve, reject) => {
let data = '';
stdin.on('readable', () => {
let chunk;
// eslint-disable-next-line no-cond-assign
while ((chunk = stdin.read()) !== null) {
data += chunk;
}
});
stdin.on('end', () => {
resolve(data);
});
stdin.on('error', err => reject(err));
}));
};
const main = async (argv) => {
let args;
console.info('isTTY: ', stdin.isTTY);
if (stdin.isTTY) {
console.info('Parse arguments');
args = parseCliArgs(argv);
} else {
console.info('Read from stdin');
args = await readFromStdin();
}
console.info(args);
};
main(process.argv)
.catch((err) => {
console.error(err);
exit(1);
});
The tool works as expected when used from the terminal, e.g. piping data to the CLI script:
$ echo "hello" | ./cli.js
isTTY: undefined
Read from stdin
hello
And passing data as command line arguments also works as expected:
$ ./cli.js hello
isTTY: true
Parse arguments
[
'/usr/local/Cellar/node/13.2.0/bin/node',
'[my local path]/cli.js',
'hello'
]
I have implemented a test that attempts to verify these behaviours:
cli.spec.js
const { execSync } = require('child_process');
// pipe stdio and stdout from child process to node's stdio and stdout
const CHILD_PROCESS_OPTIONS = { stdio: 'inherit' };
describe('cli test', () => {
it('pipe data to CLI tool', () => {
const command = `echo "hello" | ${__dirname}/cli.js`;
execSync(command, CHILD_PROCESS_OPTIONS);
});
it('pass data as CLI args', () => {
const command = `${__dirname}/cli.js "hello"`;
execSync(command, CHILD_PROCESS_OPTIONS);
});
});
The pipe data to CLI tool
test works as expected (and gives the same output as when executed from command line).
The pass data as CLI args
test hangs indefinitely. Looking at the output, I find that
isTTY: undefined
Read from stdin
Based on this observation I draw the conclusion that stdin.isTTY
is not handled correctly (which causes the promise returned from the readFromStdin()
function to remain unresolved, thus hanging the test).
Aucun commentaire:
Enregistrer un commentaire