If you've ever run a script like npm run test
from your package.json
:
{
"scripts": {
"test": "node --test src/**/*.test.js"
}
}
You'll notice we are using a globstar here src/**/*.test.js
.
The thing is, on Linux, npm run
runs scripts with sh
by default.
By default, sh
doesn't support globstar paths like **/*
. So you'll notice that it'll only find files one directory deep, and will treat src/**/*.test.js
as if you only wrote src/*/*.test.js
.
This is a major pitfall that can easily go by undetected. For example, imagine your CI skipping 90% of your tests since it was looking at only some of the directories!
⚠️ NOTE: This was only tested on Linux, and was not tested on Windows or Mac.
To fix this, figure out how to enable globstar in your shell. Or do what I did and just update npm
to use zsh
as the default shell for running scripts.
Unlike sh
, zsh
understands and expands globstar paths by default.
Here's how to do that:
- First run
npm config ls -l | grep shell
to see what config you have. It'll probably say:
script-shell = null
shell = "/bin/bash"
-
Now, run
npm config set script-shell=zsh
to update thescript-shell
option to usezsh
. -
Confirm that the update worked. Run
npm config ls -l | grep shell
. It'll probably say:
; script-shell = null ; overridden by user
shell = "/bin/bash"
script-shell = "zsh"
- Now, try using globstar paths again in your scripts. All the matching files should be discovered now by the shell (even several subdirectories deep).
You're all set! 😌
The problem now is... remembering to do this everywhere you use npm
. 😢
(GitHub Codespaces, other laptop, work computer..................)
By the way, many tools that you would use within
npm run
scripts, likemocha
, support quoting the globstar in the script, like'src/**/*.test.js'
, in which case they will perform the globstar matching for you, not relying on the shell you are using. This is a great solution! Use this wherever possible.Unfortunately, some tools don't support this yet, like the native Node.js v20 test runner
node --test
. When Node.js supports this, likenode --test 'src/**/*.test.js'
, I won't really need this hack anymore!
Interesting! So I ran some tests and
sh
aliases to bash on my Linux system. Bash doesn't support globstars by default but in any modern version you can enable support withshopt -s globstar
which resolves this problem. This may be a better solution since it doesn't introduce any other potential changes that might be experienced moving to another shell.