Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception raised: Process failed: spawn node_modules\.bin\jest.cmd ENOENT #98

Closed
bnwan opened this issue Apr 24, 2017 · 28 comments · Fixed by #248
Closed

Exception raised: Process failed: spawn node_modules\.bin\jest.cmd ENOENT #98

bnwan opened this issue Apr 24, 2017 · 28 comments · Fixed by #248

Comments

@bnwan
Copy link

bnwan commented Apr 24, 2017

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

@orta
Copy link
Member

orta commented Apr 24, 2017

Can you provide a demo project?

@carlosflorencio
Copy link

Getting this too.

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

@3KniGHtcZ
Copy link

I have same problem on macOS

@Aklesk
Copy link

Aklesk commented Oct 23, 2017

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.

@akaztp
Copy link

akaztp commented Dec 6, 2017

Or you can install jest globally and set the config:

"jest.pathToJest": "jest"

@seanpoulter
Copy link
Member

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

@Aklesk
Copy link

Aklesk commented Dec 23, 2017

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.

@seanpoulter
Copy link
Member

seanpoulter commented Jan 2, 2018

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.

@stephtr
Copy link
Member

stephtr commented Jan 5, 2018

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?

@seanpoulter
Copy link
Member

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)

@Aklesk
Copy link

Aklesk commented Jan 7, 2018

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.

@stephtr
Copy link
Member

stephtr commented Jan 7, 2018

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.

@seanpoulter
Copy link
Member

seanpoulter commented Jan 7, 2018

@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. 😖 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.

@stephtr
Copy link
Member

stephtr commented Jan 7, 2018

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.

@seanpoulter
Copy link
Member

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

@seanpoulter
Copy link
Member

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

@stephtr
Copy link
Member

stephtr commented Feb 3, 2018

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.

@seanpoulter
Copy link
Member

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.

@stephtr
Copy link
Member

stephtr commented Feb 4, 2018

@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".

@seanpoulter
Copy link
Member

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.

@Aklesk
Copy link

Aklesk commented Feb 4, 2018

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'.

@orta orta closed this as completed in #248 Feb 21, 2018
@Aklesk
Copy link

Aklesk commented Feb 27, 2018

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!

@stephtr
Copy link
Member

stephtr commented Mar 1, 2018

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

@demeralde
Copy link

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

@stephtr
Copy link
Member

stephtr commented Nov 4, 2018

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

@demeralde
Copy link

@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

@crstamps2
Copy link

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

@SpencerKaiser
Copy link

SpencerKaiser commented Aug 19, 2019

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.