xudafeng / command-line-test

command-line test tool for Node.js

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to test for correct stdout and stderr when program exits with non-zero error code

axelpale opened this issue · comments

I have a case where our CLI program exits with exit code 1 and produces output relating to the error.

How can I test the output? It seems that currently command-line-test nullifies both result.stdout and result.stderr whenever the program exits with a code other than 0 (success).

To explain why this is useful, take for example the javascript linter standard. It is common to use scripts property in package.json to run linters and builds. It is also common to pipe commands so that if the first fails than the second is not executed. In the package.json snippet below the webpack build is not executed if standard exits with code other than 0, thanks to && operator.

  ...
  "scripts": {
    "build": "standard && webpack",
    ...
  }

Although exiting with 1, the linter outputs the found issues to stdout (or stderr, I'm not sure). It would be very important for the developers of the linter to test for the output.

Almost three years later, I again face the same issue. I wanted to test error output of genversion's command line interface but because the error code from genversion is 1, the result object from command-line-test has stdout and stderr equal to null, regardless they should not be null.

The problem (and solution) can be found in lib/command-line-test.js at line 131.

The cause is this: childProcess.exec(command, options, (error, stdout, stderr) => { ... }) will call back with a non-null error object if the command exits with non-zero error code. Regardless of the error, stdout and stderr are also set and valid strings (empty strings by default if no actual output took place). However, command-line-test just records the error but forgets to record stdout and stderr.

The problem is solved by replacing the following lines 130–133:

if (error) {
  this.error = error;
  return resolve(_getter.call(this));
} 

with these lines:

if (error) {
  this.error = error;
  this.stderr = stderr.trim();
  this.stdout = stdout.trim();
  return resolve(_getter.call(this));
}