I have what I think is a better solution here: I added an exceedingly simple bash script called nofail.sh
to the root of my project, which is nothing but the following:
"$@" || true
Then, I added ./nofail.sh
at the beginning of my npm test
command like so:
"scripts": {
"pretest": "echo pretest",
"test": "./nofail.sh mocha",
"posttest": "echo posttest"
}
If you don't like adding a bash script to the mix, or need something cross-platform, suppress-exit-code
is a node package that seems to fit the bill, just install that and use suppress-exit-code
instead of ./nofail.sh
.
But why?
For one, I think it's clearer about what is happening - we are ignoring the failure code from the test command. But more importantly, this allows you to pass arguments to your test command as normal, so that this still works:
npm test -- test/to/run.js
Both other solutions break this case: in the || :
the arguments are passed to the :
command† instead, where they do nothing, and in the all-in-one they get passed to npm-run-all
.
This was particularly troublesome in our project, because our base test script has a couple configuration parameters, and then we have several "suites" defined as individual scripts that specified a given set of test files as arguments. Because we weren't able to run npm test -- --spec "tests/some-suite/*.spec.js"
, we had to repeat the configuration and setup for the base test runner in each suite, in addition to the strange-looking || :
at the end of each script, which made things much more verbose and messier than necessary.
With this solution, the base test configuration can be given once in npm test
, and then used by all the suites, and everything is much clearer and easier to maintain.
But how?
$@
is a special variable that is set to whatever arguments are passed into the script. If the npm scripts were actual bash scripts, we could simply run mocha "$@" || true
and be done with it, but they are not, so they don't have access to that variable.
So instead, we use this very simple bash script and pass our original command as arguments to it, which includes any arguments passed with --
. It then runs those arguments as a command and ignores the result, which is what we want. Quoting $@
here ensures that any quoted arguments are handled correctly.
† While it is sometimes used similarly, :
is not actually a "comment" in any meaningful sense, it is a builtin command like any other and is documented as such in Bash's manpage:
: [arguments]
No effect; the command does nothing beyond expanding arguments and performing any specified redirections. A zero exit code is returned.
These days :
is just a confusing holdover from the early days when true
was not widely available. I recommend using true
these days, which fulfills the same function and makes it somewhat clearer what is going on.