In my package.json
, I have a scripts block that uses **/*Test.js
to match files. When run via npm
, they do not match sub-directories more than one level. When executed on the command line directly, they work as expected.
Can anyone explain what is happening, and provide a workaround or solution?
package.json
{
"name": "immutable-ts",
"scripts": {
"test": "echo mocha dist/**/*Test.js",
}
}
Execution
% npm run test
> immutable-ts@0.0.0 test:unit .../immutable-ts
> echo mocha dist/**/*Test.js
mocha dist/queue/QueueTest.js dist/stack/StackTest.js
% echo mocha dist/**/*Test.js
mocha dist/queue/QueueTest.js dist/stack/StackTest.js dist/tree/binary/BinaryTreeTest.js
% ls dist/**/*
dist/collections.js dist/queue/QueueTest.js dist/tree/binary/BinaryTree.js dist/immutable.js.map dist/stack/Stack.js.map dist/tree/binary/BinaryTreeTest.js.map
dist/immutable.js dist/stack/Stack.js dist/tree/binary/BinaryTreeTest.js dist/queue/Queue.js.map dist/stack/StackTest.js.map
dist/queue/Queue.js dist/stack/StackTest.js dist/collections.js.map dist/queue/QueueTest.js.map dist/tree/binary/BinaryTree.js.map
Solution
Change your scripts so that what you pass to Mocha is protected from expansion by the shell:
Note the single quotes around the parameter given to
mocha
.Explanation
This issue is fixable without resorting to external tools. The root cause of your problem is that by
npm
usessh
as the shell that will run your script commands.It is overwhelmingly the case that when a *nix process starts a shell it will start
sh
unless there is something telling it to do otherwise. The shell preference you set for logins does not constitute a way to "tell it otherwise". So if you have, say,zsh
as your login shell, it does not entail thatnpm
will usezsh
.Those implementations of
sh
that do not include any extensions beyond whatsh
should provide do not understand the**
glob in the way you want it to. As far as I can tell, it is interpreted as*
. However, Mocha interprets the paths passed to it using its a JavaScript implementation of globs. So you can work around the issue by protecting your globs from being interpreted bysh
. Consider the followingpackage.json
:The
shell
script is just so that we can check what shell is running the script. If you run it, you should seesh
.Now, given the following tree:
With all
a.js
andb.js
files containingit(__filename);
. You get the following results:The glob expansion is actually done by your shell and that's why it works from the command line.
You can do
mocha --recursive
and point at your test directory.You can inline the
find
command with the-name
option in your scripts to replace the extended globbing syntax provided by zsh.In your case, the command would be:
You can realistically omit the
-type f
part if you're confident that you won't ever put "Test.js" in a directory name. (A safe assumption, most likely, but I included it for completeness sake)