Vscode-jest: Exception raised: Process failed: spawn node_modules\.bin\jest.cmd ENOENT

Created on 24 Apr 2017  Â·  28Comments  Â·  Source: jest-community/vscode-jest

Enable to get this working. Using create-react-app with TypeScript. Any help appreciated

enhancement needs information

Most helpful comment

I have same problem on macOS

All 28 comments

Can you provide a demo project?

Getting this too.

Windows 10, clean create-react-app project:
image

I have same problem on macOS

I'm not using create-react-app, but I am using Windows 10 and struggled with that precise error message with my project for some time and have finally managed to find a functional workaround.

The basic issue seems to be with the path finding code on Windows. As a result of the fix to #10, when VSCode is running in a Windows environment this extension naively assumes that everything must end in .cmd, and actually adds .cmd to the end of jest.pathToJest if it doesn't already have it. This may be reasonable functionality in some specific use cases, but sadly is completely wrong in my case - I may be developing on Windows 10, but literally nothing in my project folder ends in .cmd.

In the end the only way I could find to satisfy the requirements was to create a text file called jest.cmd in my project root, and make use of the %* syntax:

node node_modules\jest-cli\bin\jest.js %*

The %* passes any arguments provided to the .cmd file to the inner script so the suffixes and arguments all work, and because the script is inside a file that ends in .cmd I can actually point the path at it, so everything works!

I hope it works for others too.

Or you can install jest globally and set the config:

"jest.pathToJest": "jest"

Is this one still a problem? Could anyone experiencing the issue provide more info to reproduce the steps or create a sample repo?

I haven't had time to dig into this deeply, but yes, it's still an issue. Skimming the source code, it looks like the issue is lines 22-24 of vscode-jest/src/helpers.ts still naively sticking .cmd on the end of jest.pathToJest in Windows environments.

Steps to reproduce are basically to install Vagrant and Virtualbox, spin up an Ubuntu (or Linux kernel of your choice) VM, set up a NodeJS project using Jest inside the VM, then point VSCode at the (shared) project folder on the host machine (running Windows). NodeJS was installed inside the (linux) VM so nothing was given the .cmd extension, but vscode-jest just looks at the host machine environment and makes assumptions about the project based on that.

Installing Jest globally on the host machine could possibly work? I haven't tested that - the point of using a virtual machine to develop is to keep the environment as much inside the VM (and as close to your production environment) as possible, so running the tests outside the virtual environment is not a desirable workflow for me.

Ah, yes! Packages installed from a VM would surely cause problems @Fendrian.

If we can't make assumptions about the OS being OK, we may be wise to run things like npm run which adds node_modules/.bin/ to the PATH environment variable then calls npm <path>. It may also work out for monorepos / multiple workspace roots.

Wouldn't it be a little more useful to add the .cmd only if the command starts with npm and maybe if the command contains node_modules/.bin/… (and stick it directly to the executable, not just the end, in case there are additional arguments)?

If packages have been restored in a Linux VM is there even a way to to run Jest from command line?

Wouldn't it be a little more useful to add the .cmd only if the command starts with npm ...

It's a start, but it misses other package managers like yarn or any other scripts folks can run without the extension (e.g. .bat, .cmd). Since it seems to be a Windows-specific problem, we can delegate the optional .com, .cmd, or .bat file extension handling to cmd.exe that stops when done (/c).

If packages have been restored in a Linux VM is there even a way to to run Jest from command line?

Great leading question! After playing around with npm and yarn from the CLI, no. When you delete node_modules\.bin\jest.cmd or never had it installed then jest isn't recognized from the npm test script -- it's not found in node_modules\.bin when added to the PATH.

With this information, it makes me think @Fendrian's needs something beyond what we'll offer in the extension. I'd suggest one of these options:

  • restore a working node_modules\.bin\jest.cmd from a deployment script on the VM
  • change pathToJest to call node like jest.cmd
  • create all the node_modules\.bin\*.cmd files based on the installed Bash scripts from a deployment script
  • re-install the packages to get the .cmd files (if possible, there may be challenges with symlinks)

I'm a bit confused why there's code adding .cmd at all. :) generally I expect that when I specify a path, I specify a path. Code that helps the user if they mis-type something or use strange syntax is great as long as it doesn't get in the way, but in this instance it very much is.

Personally I'd be inclined to leave code adding .cmd to the default path if there is no pathToJest specified, but if the user specifies a path, trust the user to know what they're doing and use what they specify. That would not only solve all my current problems, it would mean that I never would have had a problem to begin with.

As I said in an earlier post, I found a workaround for my issue that allows me to use this plugin with my setup, and it's a wonderful and helpful plugin to use and I definitely appreciate the time and effort that went into it. But the workaround I found is very non-standard and a bit confusing, and it feels a bit needless to me.

As a reminder, there are more terminal options available to Windows users than just the base Windows Command Prompt, and there are more methods of ending up with completely functional and legitimate Node and Jest installations that don't have any files that end with .cmd than just using virtual machines. One of the workarounds I tried for a while was running Jest using Windows 10's integrated Bash terminal, which would be nice to have as an option. Though if I'm recalling correctly that wouldn't have worked in this case even without the .cmd issue due to a hard-coded path elsewhere - but that's another issue.

My primary thought was that the configuration (file) should be shareable between Linux and Windows, which wouldn't be the case if on Windows one has to add '.cmd', which, by the way, is less intuitive, at least in my opinion.

It makes me wonder why we even need the '.cmd' extension; I took a short look at vscode-npm-scripts and it seems like they don't use it: vscode-npm-scripts/main.ts.

@Fendrian: trust the user to know what they're doing and use what they specify

Based on the dev environment that you described it sounds like you're an advanced user and can handle yourself. Folks who are new to Node, batch scripts, or are trying to have settings work across platforms may not be familiar with the magic abstracted behavior of the command prompt. The command prompt, in whatever (Windows) flavor, adds .cmd when it's not provided but matches a file. It's a big jump from ENOENT to .cmd missing in pathToJest.

@Fendrian: Personally I'd be inclined to leave code adding .cmd to the default path if there is no pathToJest specified

We don't have to add anything, ever. We can trust the user and run pathToJest. If it fails with an ENOENT error, we can try spawning pathToJest in a command prompt to delegate adding the .cmd extension like it was run manually.

@Fendrian: As a reminder, there are more terminal options available to Windows users than just the base Windows Command Prompt ...

Bash on Win 10 sure does complicate things. :confounded: How'd you find it?

Could you please share your pathToJest that will start running Jest? It'd be a handy reference in the README.

@stephtr: I took a short look at vscode-npm-scripts and it seems like they don't use it

Following the calls from your code pointer leads to the npm.bin setting that defaults to npm. Windows users would still need to specify npm.cmd. It's a good idea, but doesn't help with any other node modules like jest.

--

The root cause of this problem is spawning npm (or another node module like jest) in pathToJest. npm is not an executable on Windows. If you search your PATH environment variable, the two files that match npm are both scripts. npm is a Bash script.

>where npm
C:\Program Files\nodejs\npm
C:\Program Files\nodejs\npm.cmd 

To simplify our problem to this minimal JS, spawning npm on Windows causes an ENOENT error:

const {spawn} = require('child_process');
const proc = spawn('npm', ['--version']);
//const proc = spawn('cmd', ['/c', 'npm', '--version']);

proc.stdout.on('data', (chunk) => console.log(chunk.toString()));
proc.on('error', (err) => console.log('error', err));
proc.on('close', () => console.log('close'))
> node example.js
error { Error: spawn npm ENOENT
    at _errnoException (util.js:1024:11)
    at Process.ChildProcess._handle.onexit (internal/child_process.js:190:19)
    at onErrorNT (internal/child_process.js:372:16)
    at _combinedTickCallback (internal/process/next_tick.js:138:11)
    at process._tickCallback (internal/process/next_tick.js:180:9)
    at Function.Module.runMain (module.js:678:11)
    at startup (bootstrap_node.js:187:16)
    at bootstrap_node.js:608:3
  code: 'ENOENT',
  errno: 'ENOENT',
  syscall: 'spawn npm',
  path: 'npm',
  spawnargs: [ '--version' ] }
close

Swap the commented lines to call cmd /c npm --version and you're likely working. If you've installed the node_modules/ on a POSIX system and the .cmd files are not installed, you'll have to delegate to whatever dash-like terminal is installed to run the .bin/ scripts.

A first step would be to catch the ENOENT error and print an unseful hint instead.

Following the calls from your code pointer leads to the npm.bin setting that defaults to npm. Windows users would still need to specify npm.cmd. It's a good idea, but doesn't help with any other node modules like jest.

I tried it on my Windows machine, even there the (working) default setting is just npm (independent of npm.runInTerminal). For testing only I set npm.bin to node_modules\\.bin\\jest --coverage (without the .cmd extension) and it executed fine.

Gotcha. vscode-npm-scripts is a calls child_process.exec which runs the command in a shell.
The Node child_process docs have a great section on Spawning .bat and .cmd files on Windows

We can make spawn use a shell in jest-editor-support by passing the shell option here. Just need to decide the clean way to get the opts into _createProcess in the Runner

The PR to use the shell option has been merged into jest-editor-support. PRs to use it on Windows are welcome. :wink: There's good documentation in the README about linking to the package for local development.

My PR (#248 ) basically includes:

const useShell = platform() === 'win32'
this.jestProcess = new Runner(this.workspace, { shell: useShell })

Is there a reason not to run in a shell on all other OS? I don't know large the difference is, but my thought would be to keep the behavior across different OS as similar as possible in order to reduce the possibility for introducing new bugs.

Hey @Fendrian, when you're running in your VM what does path.sep and os.platform say? It'll help a lot with @stepht's PR.

@Fendrian's problem should be fixed since vscode-jest doesn't (have to) stick .cmd to jest.pathToJest anymore.
I just tried to verify it by restoring within Linux subsystem on Windows. Running jest results in some lstat errors, but after removing all file links (.bin folders), the extension with my PR works when using "jest.pathToJest": "node node_modules/jest/bin/jest".

My question for @Fendrian is to figure out if path.sep suggests a different OS than `os.platform in his use case. I'm curious if there's different in the VM he's using.

Inside the VM and all terminal operations I run, path.sep is '/' and os.platform() is 'linux'.

I'm not familiar with the shell option though, so I don't know if that's the info you need. For reference, if I log the environment inside tests and look at the output from vscode-jest, the separator is '\' and os.platform is 'win32'.

As a quick followup, running the latest version with #248 merged, my setting is "jest.pathToJest": "node node_modules\\.bin\\jest" and it's working flawlessly with no issues or anything special beyond that. This is absolutely fantastic!

I think even node_modules/.bin/jest (without node) should work.

I've been messing around with this for a fair while and I can't get it to work. my pathToJest is:

${workspaceFolder}/client/node_modules/.bin/jest

I've also tried:

${workspaceFolder}/client/node_modules/jest/bin/jest.js

I've validated these files exists, neither work. The error is:

Exception raised: Process failed: spawn ${workspaceFolder}/client/node_modules/.bin/jest ENOENT

The same spawn error occurs if I use:

yarn test

${workspaceFolder} doesn't get substituted. Did you try client/node_modules/.bin/jest instead?

@stephtr sorry for the late response. Yep I did, it's still throwing errors:

Exception raised: Process failed: spawn client/node_modules/.bin/jest ENOENT

@dspacejs did you ever figure out what the right path to jest should be for a multi-root workspace?

For those who are still getting this error (I _just_ switched to VSCode from Atom), try installing Jest globally without modifying the extension's settings (remove ts-jest if you aren't using TypeScript:
npm i jest ts-jest -g

Try that and then restart the VSCode!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dgoemans picture dgoemans  Â·  63Comments

connectdotz picture connectdotz  Â·  24Comments

Drakota picture Drakota  Â·  16Comments

kartheektrilochan picture kartheektrilochan  Â·  28Comments

karb0f0s picture karb0f0s  Â·  37Comments