【发布时间】:2021-07-07 21:13:17
【问题描述】:
如何在 Node CLI 工具中实现验证 stdin.isTTY 不同行为的测试?
我在 Node 中实现了一个 CLI 工具,它期望数据通过终端管道传输或作为命令行参数传递:
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;
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);
});
从终端使用时,该工具按预期工作,例如管道数据到 CLI 脚本:
$ echo "hello" | ./cli.js
isTTY: undefined
Read from stdin
hello
并且将数据作为命令行参数传递也可以按预期工作:
$ ./cli.js hello
isTTY: true
Parse arguments
[
'/usr/local/Cellar/node/13.2.0/bin/node',
'[my local path]/cli.js',
'hello'
]
现在,我尝试编写一个测试来验证这些行为:
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);
});
});
pipe data to CLI tool 测试按预期工作(并提供与从命令行执行时相同的输出)。
pass data as CLI args 测试无限期挂起。查看输出,我发现
isTTY: undefined
Read from stdin
基于此观察,我得出结论,stdin.isTTY 未正确处理(这导致从 readFromStdin() 函数返回的承诺仍未解决,从而挂起测试)。
- 如何使测试
pass data as CLI args通过? - 是否可以在子进程中模拟
process.stdin.isTTY?
【问题讨论】:
标签: javascript node.js testing command-line command-line-interface