cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
46.66k stars 3.16k forks source link

cy.exec fails on windows #789

Open dwelle opened 6 years ago

dwelle commented 6 years ago

Current behavior:

image

From the bug, the path seems mangled:

  1. first part is UNIXy /c/Program
  2. There's a : inserted into the (Program Files) folder name for some reason
  3. 2nd half is in windows format (backslashes)

How to reproduce:

cy.exec('echo 42');

Additional Info (images, stack traces, etc)

On my machine is installed (and in env variables) the git-for-windows bash, which is the bash the cypress is trying to invoke.

bahmutov commented 6 years ago

Hmm, I wonder if the git-for-windows is confusing shell read from Cypress. Will need to install and test it.

keithernet commented 6 years ago

Hello,

I am also having an issue running exec in Windows 10. My git bash install path is C:\dev-tools\Git\usr\bin. When I exec cypress logs: cypress:server shell C:\dev-tools\Git\usr\bin\bash.exe profile undefined +4ms cypress:server cy.exec found shell C:\dev-tools\Git\usr\bin\bash.exe +1ms cypress:server and is running command: echo +1ms

The command fails with Stderr: /usr/bin/bash: /s: No such file or directory

I'm not sure if this is an issue with my git-bash install or the way cypress is calling it. Any help would be greatly appreciated.

GuyBransgrove commented 6 years ago

I haven't got a solution for this (yet) but I do know what the problem is.

image (https://github.com/sindresorhus/execa/blob/master/index.js)

Basically the above section in the dependency "execa" is the problem. If your platform is windows it makes the assumption that your shell is cmd and it structures the resulting command as follows:

C:\\ProgramFiles\\Git\\usr\\bin\\bash.exe /s /c "source undefined > /dev/null 2>&1; echo foo" (Yes, that is ProgramFiles with no spaces. I was trying to work around the original issue.)

As you can see the flags /s /c make sense in cmd, but bash sees them as file paths and we get the error we are all seeing. In line 89 you can see what the args variable should actually be set to when you shell is bash.

jennifer-shehane commented 6 years ago

@GuyBransgrove Thanks for looking into this and opening the issue with execa - hopefully they get a fix in and we can update the package.

jennifer-shehane commented 6 years ago

execa has decided to not offer support for cmd.exe-incompatible shells, so this looks like something we would have to manually support.

Sandy-Garrido commented 5 years ago

execa has decided to not offer support for cmd.exe-incompatible shells, so this looks like something we would have to manually support.

That's great news. Is there a solution as of yet to have this working at all on windows at all? I seem to be getting this error regardless of the shell used being on windows

Vandivier commented 5 years ago

How about using ShellJS?

Saibamen commented 5 years ago

This same issue: #1034

selvex commented 5 years ago

Found a solution that does the trick for now. I'm using cypress.task to start a task which I define in the plugins file. There, I import shell-exec, a npm package that also supports windows. Since I only need a single command for now, this works fine.

Sharing full example for clearness. cypress/plugins/index.js

// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
require('dotenv').config();
const shell = require('shell-exec');
module.exports = (on, config) => {
  // `on` is used to hook into various events Cypress emits
  // `config` is the resolved Cypress config
  on('task', {
    'env': () => {
      return new Promise(resolve => {
        resolve(process.env);
      });
    },
    // relevant part
    'db:clean': () => {
      return shell('npx gulp db:clean');
    }
  })
};

And in a test:

it('can register a new account', () => {
      cy.task('db:clean');

      cy.visit('/register');
});

It returns a promise, so it is then-able. However cypress waits for the completion out-of-the-box.

Hope that helps.

flotwig commented 4 years ago

execa has decided to not offer support for cmd.exe-incompatible shells, so this looks like something we would have to manually support.

The reason this issue occurs is because Git Bash sets the SHELL environment variable, which Cypress then tries to use with execa.

Since the docs don't say anything about what shell should be used in cy.exec, and there's no option to supply a custom shell, I think we should just short-circuit the shell detection code to always use cmd.exe on Windows until people ask for support for other shells.

That would mean moving lines 88-92 of this getShell function to the top:

https://github.com/cypress-io/cypress/blob/029ed01793ba0af0e9b210d818de61d0f6806e9e/packages/server/lib/util/shell.js#L75-L95

Tested and this fixes the issue on Windows 10. Don't believe it would change existing behavior, since the current behavior is "use cmd.exe or fail".

dwelle commented 4 years ago

That would mean we won't be able to use UNIX shell programs, which means that cross-platform tests written for UNIX target would stop working.

Is this issue still outstanding though? It works for me at the moment (I've also tried using execa directly, and it works, too). Though, some things changed, such as my SHELL path not containing spaces as it did in OP --- but weren't the main issue that execa passed cmd.exe switches even to the bash shell? It seems that's no longer an issue.

flotwig commented 4 years ago

That would mean we won't be able to use UNIX shell programs, which means that cross-platform tests written for UNIX target would stop working.

Would it though? I only say that because AFAIK, currently, you cannot launch Cypress from a non-cmd.exe shell and then successfully use cy.exec, at all, in any way. Any command will give you the error from the OP. So tests that would break in the way you're describing are already broken today, and I'd assume that tests that pass today are most likely being launched through cmd.exe.

The change I'm proposing would make cy.exec behave as if Cypress is always launched from cmd.exe on Windows, which will make cy.exec work in non-cmd.exe shells.

Let me know if this is mistaken or you see a breaking change with this.

Is this issue still outstanding though? It works for me at the moment (I've also tried using execa directly, and it works, too). Though, some things changed, such as my SHELL path not containing spaces as it did in OP --- but weren't the main issue that execa passed cmd.exe switches even to the bash shell? It seems that's no longer an issue .

I just experienced the issue in CI using bash.exe, and switching the CI step to use cmd.exe with SHELL empty fixed it:

dwelle commented 4 years ago

Would it though? I only say that because AFAIK, currently, you cannot launch Cypress from a non-cmd.exe shell and then successfully use cy.exec, at all, in any way.

Interesting. You're right, I've just tested. Previously it worked for me because I've run the test from the vscode terminal (which I have configured to use bash.exe, though) --- but running the test directly from cmd.exe or bash.exe results in the error.

Weirdly enough, it seems that I have two bash.exe executables on my system:

  1. C:\Windows\System32\cmd.exe --- this is used by vscode terminal (and since it contains no spaces, it works).
  2. C:\Program Files\Git\usr\bin\bash.exe --- this is the default shell (weirdly, echo $SHELL shows /usr/bin/bash, which isn't a valid absolute path. It seems the path is relative to C:\Program Files\Git\).

That being said, it seems this error comes down to improperly handling the path (not sure whose fault that is, but I believe it's Cypress').

cy.exec seems to use (2), but handles it in such a way that it results in the OP error of /c/Program: Files\Git\usr\bin\bash.exe: No such file or directory. I believe if we solve that, this issue would be resolved (since the upstream issue in execa seems to no longer exist).

flotwig commented 4 years ago

Agreed, that's probably the preferred approach if execa will indeed work with bash.exe.


Weirdly enough, it seems that I have two bash.exe executables on my system:

1. `C:\Windows\System32\cmd.exe` --- this is used by vscode terminal (and since it contains no spaces, it works).

Is this supposed to be a path to a bash.exe executable? :stuck_out_tongue:

dwelle commented 4 years ago

Wha..

It's not, I misread it :). But I'm indeed using bash.exe, it's just configured via settings.json (and isn't reflected in the vscode settings view, from which I blindly copied it). WTBS, the path again points to the Git path:

"terminal.integrated.shell.windows": "C:\\Program Files\\Git\\bin\\bash.exe",

Thus, it still contains the space. Why does Cypress handle it correctly, when invoked from vscode terminal, though?

flotwig commented 4 years ago

What is the value of the SHELL environment variable in each environment?

dwelle commented 4 years ago

Not sure how to figure that out on windows (maybe looking it up in registry?) except echo $SHELL, which feels not very authoritative. But it reports /usr/bin/bash when executed both from vscode terminal, and bash.exe.

dwelle commented 4 years ago

Googling, it seems that echo %SHELL% should work in cmd.exe, but it seems this env variable is only set within the bash.exe process, because echoing it from cmd.exe shows nothing (which suggests it doesn't exist).

flotwig commented 4 years ago

Cool, that sounds right. Strange, in that case I have no idea why it works in VScode but not outside it. There's a lot of logic in the shell.js file that needs to be unpacked...

Codediggar commented 4 years ago

For intelliJ https://www.jetbrains.com/help/idea/settings-tools-terminal.html choose your terminal as cmd for windows .

For VS Code : Check the settings - Terminal › External: Windows Exec Customizes which terminal to run on Windows. C:\windows\System32\cmd.exe

Hope this helps

saulonunesdev commented 4 years ago

I was using git bash to run cypress, when i changed to windows powershell it worked for me

uncleramsay commented 3 years ago

Is there any update to this issue or any workaround? I can't seem to get cy.exec to work on Windows at all, even via VSCode or cmd. Makes it pretty difficult to use Cypress at the moment sadly.

EDIT: @selvex's solution does work for me as well, I did something wrong when I tried it the first time. This is a reasonable workaround for the moment, but obviously it would be great for cy.exec to work on Windows too.

haase1020 commented 3 years ago

I am running into the same situation and was wondering if cy.exec works on Windows....

jennifer-shehane commented 3 years ago

Is this still an issue? Can anyone provide the code and the error they see when running a failing cy.exec() command in our current version?

haase1020 commented 3 years ago

I am not sure because I switched to an Ubuntu operating system.

Tobbe commented 3 years ago

I saw this issue two days ago. execa has solved the issue on their side with this PR: https://github.com/sindresorhus/execa/pull/181

Not sure what version of cypress we're on, will check and report back

Tobbe commented 3 years ago

We're on 5.1.0

image

https://github.com/redwoodjs/redwood/blob/19bb1b5f39dae7d6863096b560bc3549889a7b9a/tasks/e2e/cypress/integration/tutorial/tutorial.js#L40

Tobbe commented 3 years ago

Upgraded to 6.4.0 and I still get the same error

image

(Oops, copied the error from a different line, but the error is the same on all lines that call cy.exec)

MuckT commented 3 years ago

This issue still reproduces. I ran into it while working off a clone of this repo on a windows machine.

sandra-ouadghiri commented 3 years ago

On 6.5.0 I can confirm that

I guess the question is, what do we want.

I think it would be nice to be able to change cy.exec terminal (ex in cypress.json and cypress.env.json) to be able to choose between cmd, powershell, sh and git-bash at least. I think it is fair to have a default value. This value, instead of being based on my computer could be powershell core has it is now a standard on both linux and windows.

So I would propose:

It's a spec proposition, so please feel free to argue with it :).

Josef37 commented 3 years ago

A workaround I currently use. Just utilize Windows' command line to invoke Git Bash, since we get those Windows flags from execa.

// Setup 'bash' and 'comSpec' [environment variables](https://docs.cypress.io/guides/guides/environment-variables)

const command = 'yarn run seed';

if (Cypress.platform !== 'win32') {
  cy.exec(command);
} else {
  // This is a hack!
  const sh = `"${Cypress.env('bash')}" --login -i -c`;
  cy.exec(`${sh} "${command}"`, { env: { SHELL: Cypress.env('comSpec') } });
}

Weirdly it fails on the first run...

jaffrepaul commented 3 years ago

I see that @jennifer-shehane commented in February about capturing errors with the current Cypress version and we have some confirmation (v5.10 - v6.5.0) with varying degrees of workaround effort included.

Just curious, @Tobbe which version you are currently running and if you still have this issue in 7.4.0? I would assume yes given the nature of the issue thus far. The outstanding issue may just be deciding which path to take.

adding @flotwig & @bahmutov for good measure

Tobbe commented 3 years ago

@jaffrepaul Thanks for giving this issue some attention. I gave up on trying to get this to work for a while, but I could never truly let it go, I keep thinking about it :) Thanks to your nudge I'll try to get the project spun up locally again and give it another go. Hopefully I can report back with answers to your questions tomorrow

Tobbe commented 3 years ago

@jaffrepaul Finally got around to try this again.

I can confirm we're still seeing the same issue in 7.4.0

image

image

ivanAndCode commented 3 years ago

I also bumped into this issue with Cypress 8.0.0. Used a workaround provided by @Josef37 here Here's my slightly modified code: cypress.json

...
    "env": {
      "bash": "C:\\Program Files\\Git\\bin\\bash.exe",
      "comSpec": "C:\\Windows\\system32\\cmd.exe",

helper.ts:

export function fetchSecrets() {
  cy.log(`Platform: ${Cypress.platform}`)
  cy.log(`Architecture: ${Cypress.arch}`)

  const command = 'pathToScript/fetch.secrets.sh secretName secretKeyvault';

 if (Cypress.platform !== 'win32') {
    cy.exec(command);
  } else {
    // This is a workaround against cy.exec not working on windows machine
    // https://github.com/cypress-io/cypress/issues/789
    // To make this code work you need to setup 2 cypress env variables
    // - bash (pointing to the bash shell executable on your machine)
    // - comSpec (pointing to cmd.exe on your machine)
    cy.log('Bash path: ' + Cypress.env('bash'))
    cy.log('cmd.exe path: ' + Cypress.env('comSpec'))

    const sh = `"${Cypress.env('bash')}" --login -c`;
    const fullCommand = `${sh} "${command}"`
    //for some reason cypress cannot find shell on the first try so it throws
    //this is a retry hack allowing cypress to gracefully deal with error
    executeCypressCommand(fullCommand, false)
    executeCypressCommand(fullCommand, true)
  }

function executeCypressCommand(command: string, failOnError: boolean = true) {
  cy.exec(command, {env: {SHELL: Cypress.env('comSpec')}, failOnNonZeroExit: failOnError}).then(result => {
    cy.log('Exit code: ' + result.code.toString())
    if (result.stdout.toString().length > 0) {
      cy.log('Stdout: ' + result.stdout.toString())
    }
    if (result.stderr.toString().length > 0) {
      cy.log('Stderr: ' + result.stderr.toString())
    }
  })
}

/support/index.ts

import {fetchSecrets} from './helpers/helper'

before(() => {
  fetchSecrets()
})

I think there might be a room for improvement/optimisation, but I haven't explored it yet (hashtag worksonmymachinenow 🤣 ). Will try to update my comment if I will end up spending more time on it. Hope this will help someone :)

Update: Weirdly it fails on the first run... I can see what you meant now. If you have cypress open and refresh it, everything works. When you try to run it in a cicd fashion, this solution fails:( I have added a retry into the example above to fix this problem.

clazette commented 2 years ago

Switch your default terminal, in VS Code, from Bash to PowerShell and the problem is solved.

amadeogallardo commented 2 years ago

Upgraded to Cypress 9.2.0 and the error is still present.

clazette commented 2 years ago

You switched to PowerShell and you're still having the issue?

amadeogallardo commented 2 years ago

To clarify: the error still happens when running Cypress from a Bash terminal in VS Code. It doesn't happen when using either CMD or PowerShell. But, I would assume that any terminal should work.

clazette commented 2 years ago

There is an issue when using Bash. Yes, it needs to be resolved but switching to CMD or PowerShell solves the issue and you can do what you need to do, yes? I'm not sure why you downvoted my response. It solved the issue and you can proceed, no? Did I not provide helpful information so that someone may avoid hours of screwing with something before they realize that it's something specific to Bash?

amadeogallardo commented 2 years ago

Although you provided a valid workaround (which I was already aware of) the problem is not really "solved". No animosity, just reporting back that this issue still happens on the latest version.

clazette commented 2 years ago

I wasn't attempting to solve the issue for Cypress. I was attempting to provide information that would, hopefully, prevent others from wasting hours of their lives messing with this issue not realizing that it was something specific to Bash. Anyway, whatever, glad you know about the workaround.

jb1mc commented 2 years ago

The issue is present with Cypress v9.4.1 when using Git Bash with VS Code.

image

moishinetzer commented 2 years ago

The issue is STILL present with Cypress v10.3.0 when using Git Bash with VS Code on windows

strowk commented 1 year ago

Had this, fiexed by resinstalling Git Bash in "C:/Git" rather than "C:/Program Files/Git". Took some additional effort to make vscode understand where shell is now installed, but it all worked out in the end.

gustawx commented 1 year ago

@strowk worked for me as well, thanks for tip! Maybe it's about a space character in the path :/

ddfridley commented 1 year ago

This is still a problem with 10.10.0, but some how it has changed from no space a while back, to colon and then space.

Stderr:
/c/Program: Files\Git\usr\bin\bash.exe: No such file or directory

I see all these work arounds, but for open source projects we really need the repo to just install and run. The root of the problem seems to be something inserting a ": " in the path. How do we fix that!

I'm using git bash from vs code.

One other observation, from the bash terminal in vscode the path to bash is:

$ which bash
/usr/bin/bash

So shouldn't cy.exec be using the environment variables from where it is being run from?

DJSdev commented 1 year ago

Just started running into this on Cypress 12.7. The cy.exec() has been working for weeks on this version, but now all of a sudden I'm getting the exact same error that was described years ago. I haven't reinstalled git or anything. Nothing on my system has changed as far as I know. Just all of a sudden can't execute anything residing in program files.

MikeMcC399 commented 1 year ago

I noticed running the example cypress-io/cypress-example-kitchensink on Microsoft Windows 11 with an out-of-the-box configuration, that the test cypress/e2e/2-advanced-examples/misc.cy.js with cy.exec('echo Jane Lane') succeeds in a cmd terminal window and fails in a git bash terminal window.

That should probably be documented somewhere.

nikola-ignjatovic commented 1 year ago

It still doesn't work well. I managed to fix it temporarily by switching to Powershell terminal in Webstorm. It worked for a week or two and after that it started to not work again. My friend has the exact same tests but he is running them on Linux and everything works just fine there.