Npm glob pattern не совпадает с подкаталогами

В моем package.json у меня есть блок сценариев, который использует **/*Test.js для соответствия файлам. При запуске через npm они не соответствуют подкаталогам более одного уровня. Когда они выполняются в командной строке напрямую, они работают как ожидалось.

Может ли кто-нибудь объяснить, что происходит, и обеспечить обходное решение или решение?

package.json

{
  "name": "immutable-ts",
  "scripts": {
    "test": "echo mocha dist/**/*Test.js",
  }
}

Выполнение

% npm run test

> [email protected] 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

Ответ 1

Решение

Измените свои сценарии так, чтобы то, что вы передали Mocha, защищено от расширения оболочкой:

"scripts": {
    "test": "mocha 'dist/**/*Test.js'",
 }

Обратите внимание на одинарные кавычки вокруг параметра, заданного на mocha.

Объяснение

Эта проблема исправляется без использования внешних инструментов. Основная причина вашей проблемы заключается в том, что npm использует sh как оболочку, которая будет запускать ваши команды script.

В подавляющем большинстве случаев, когда процесс * nix запускает оболочку, он запускает sh, если нет чего-то, говорящего об этом иначе. Предпочтение оболочки, которое вы устанавливаете для входа в систему, не является способом "сказать об этом иначе". Поэтому, если у вас есть, скажем, zsh как ваша оболочка входа, это не означает, что npm будет использовать zsh.

Те реализации sh, которые не содержат никаких расширений, помимо того, что должен предоставить sh, не понимают glob-функции ** так, как вы этого хотите. Насколько я могу судить, это интерпретируется как *. Однако Mocha интерпретирует пути, переданные ему, используя реализацию JavaScript globs. Таким образом, вы можете обойти проблему, защищая свои глобы от интерпретации sh. Рассмотрим следующий package.json:

{
  "name": "immutable-ts",
  "scripts": {
    "bad": "mocha test/**/*a.js",
    "good": "mocha 'test/**/*a.js'",
    "shell": "echo $0"
  }
}

shell script - это просто, чтобы мы могли проверить, в какой оболочке работает script. Если вы запустите его, вы должны увидеть sh.

Теперь, учитывая следующее дерево:

test/
├── a.js
├── b.js
├── x
│   ├── a
│   │   ├── a.js
│   │   └── b.js
│   ├── a.js
│   └── b
│       └── a.js
└── y
    ├── a.js
    └── q

Со всеми a.js и b.js файлами, содержащими it(__filename);. Вы получаете следующие результаты:

$ npm run bad

> [email protected] bad /tmp/t2
> mocha test/**/*a.js

  - /tmp/t2/test/x/a.js
  - /tmp/t2/test/y/a.js

  0 passing (6ms)
  2 pending

$ npm run good

> [email protected] good /tmp/t2
> mocha 'test/**/*a.js'

  - /tmp/t2/test/a.js
  - /tmp/t2/test/x/a.js
  - /tmp/t2/test/x/a/a.js
  - /tmp/t2/test/x/b/a.js
  - /tmp/t2/test/y/a.js

  0 passing (5ms)
  5 pending

Ответ 2

Вы можете встроить команду find с параметром -name в своих сценариях, чтобы заменить расширенный синтаксис globbing, предоставленный zsh.

В вашем случае команда будет:

mocha `find dist -type f -name '*Test.js'`

Вы можете реально проигнорировать часть -type f, если вы уверены, что никогда не ставите "Test.js" в имя каталога. (Безопасное предположение, скорее всего, но я включил его для полноты)

Ответ 3

Расширение glob фактически выполняется вашей оболочкой и поэтому работает из командной строки.

Вы можете сделать mocha --recursive и указать свой тестовый каталог.