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 shellto see what config you have. It'll probably say:
script-shell = null
shell = "/bin/bash"
-
Now, run
npm config set script-shell=zshto update thescript-shelloption 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 runscripts, 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
shaliases to bash on my Linux system. Bash doesn't support globstars by default but in any modern version you can enable support withshopt -s globstarwhich 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.