首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >测试侦听stdin.isTTY的Node工具?

测试侦听stdin.isTTY的Node工具?
EN

Stack Overflow用户
提问于 2019-12-10 15:34:44
回答 2查看 636关注 0票数 1

如何在Node工具中实现验证stdin.isTTY不同行为的测试?

我在Node中实现了一个CLI工具,它希望数据通过终端管道传输,或者作为命令行args传递:

cli.js

代码语言:javascript
复制
#!/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脚本:

代码语言:javascript
复制
$ echo "hello" | ./cli.js
isTTY:  undefined
Read from stdin
hello

并且将数据作为命令行参数传递也如预期的那样工作:

代码语言:javascript
复制
$ ./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

代码语言:javascript
复制
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测试无限期挂起。看看输出,我发现

代码语言:javascript
复制
isTTY:  undefined
Read from stdin

基于这一观察,我得出结论,stdin.isTTY没有得到正确的处理(这导致readFromStdin()函数返回的承诺仍未得到解决,因此挂起了测试)。

  • 怎样才能使考试pass data as CLI args通过?
  • 可以在子进程中模拟process.stdin.isTTY吗?
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-12-13 13:31:59

事实证明,这些测试是按预期工作的,但并不是在所有环境中都能工作。在从终端(例如npm test和朋友)执行时,测试按预期通过。但是,最初的实现没有通过,从那时起,我尝试使用IDE中的调试器来找到解决方案,但它仍然不起作用。如果在所有环境中都有另一个解决方案,请提交另一个答案。

票数 -1
EN

Stack Overflow用户

发布于 2021-07-05 18:38:17

对于任何遇到这种情况的人来说,这都与Node.js如何生成子进程有关。具体来说,这是stdio选项 API支持的child_process。与此相关的问题在Node.js核心中是开放的。

当您在Node.js中生成子进程时,它在它和父进程之间有管道/流来处理stdio 默认情况下。因此,父程序可以调用child.stdin.write()将数据发送到子节点的stdin,还可以读取child.stderrchild.stdout流。

在使用同步child_process API时,stdin (AFAICT)非常令人困惑,因为您根本不能对子write()进行write()。您可以向每个文档传递一个Stream引用,但我无法使用tty.Read/WriteStream来计算它。

我遇到了这个问题,发现将options.stdio[0]设置为inherit解决了这个问题。这是因为我的父进程(测试)进程没有通过stdin传递任何内容,因此设置了TTY标志,子进程将继承它并按预期工作。我认为ignore可能有用,但没有用。

这里是我的完整测试用例,下面是一个例子。要测试Node.js CLI,其中您的CLI通过isTTY检测管道,但也支持文件args,请尝试如下:

代码语言:javascript
复制
try {
  const stdout = execSync('your-cli.js some-file.txt', {
    stdio: [
      // Child will inherit process.stdin of
      // this parent process. This has isTTY
      // set to true, so the child will also
      // be set to true and parse the "some-file.txt"
      // arg instead of waiting on stdin
      'inherit',
      // Capture stdout from child. This is returned from
      // the call, and attached to an exception if one is
      // thrown, i.e error.stdout
      'pipe',
      // Capture stderr from child. This will be attached
      // as a "stderr" property if an exception is raised
      'pipe'
    ]
  });
  console.log('Child Process stdout was:', stdout)
} catch (e) {
  console.log('Error in child. Child stderr was:', e.stderr) 
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59270696

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档