cypress icon indicating copy to clipboard operation
cypress copied to clipboard

localhost URL not accessible after cy.request on server

Open nicolas-marien opened this issue 3 years ago • 31 comments

Current behavior

Hello 👋

We are trying to integrate Cypress but we run into an issue. Cypress tells us that our frontend is not reachable. The client runs on port 4200 and the server on port 3333. We are working in an monorepo managed by NX. The client is a basic React application, and the server is a NestJS application.

First we make a call to our server using cy.request and then we use cy.visit. The cy.visit fails (see screenshot attached) telling is that the connection is refused. When opening http://localhost:4200 on a browser behaves as intended.

When we change the server URL to point to 127.0.0.1 things work fine (but cookies are broken, and we want cookie 🍪).

Capture d’écran 2023-01-09 à 11 49 55

I put together a bare bone repository where things can be reproduced: https://github.com/nicolas-marien/nx-cypress-localhost-issue

Please find attached the output of DEBUG=cypress:* NODE_DEBUG=request y nx e2e client-e2e --watch

I do not have any corporate proxy.

Thank you for your help.

Desired behavior

The cy.visit(/) call should open my client.

Test code to reproduce

Start client and server using yarn nx run-many --target=serve Run yarn nx e2e client-e2e --watch and select the only spec file.

Cypress Version

12.3.0

Node version

18.10.0

Operating System

MacOS 12.6.1 (also happens on Ventura)

Debug Logs

[out.txt](https://github.com/cypress-io/cypress/files/10373543/out.txt)

Other

No response

nicolas-marien avatar Jan 09 '23 13:01 nicolas-marien

@nicolas-marien thanks for the repo. I cloned it, installed dependencies and ran

yarn nx e2e client-e2e --watch

which launched Cypress, but I didn't see any client or server running on port 4200 or 3333 like you described. So, the test failed when calling cy.login because the server wasn't running.

Am I missing something?

astone123 avatar Jan 11 '23 19:01 astone123

@astone123 Oh sorry! I forgot to add the start command to run everything 🙄 Both client and server can be run using yarn nx run-many --target=serve. I'll update the OP and the repo to add a start:all script.

nicolas-marien avatar Jan 12 '23 07:01 nicolas-marien

@nicolas-marien thanks for clarifying. I was able to run the application but I'm not seeing the same error message. The test passes for me

Image

astone123 avatar Jan 12 '23 16:01 astone123

Thank you @astone123 for your answer. Truth be told that is a bit of a bummer 😅 Since the issue happens on several of our machines (both corporate and personal). Do you have any idea of what could be involved? Does cy.request happens to have some inner-working behavior that might result in our issue? Also, the error states that 127.0.0.1:4200 is unreachable. That shows that localhost has already been resolved. Do you know why that print this and not localhost:4200. Thank you for your help.

nicolas-marien avatar Jan 16 '23 13:01 nicolas-marien

@nicolas-marien I was able to reproduce your issue by using Node18. With Node16, the e2e test works fine. There was a DNS change between Node16 and Node18 (issue) that you might be running into. I'll keep investigating to see where the problem lies and if there is a workaround for you.

ZachJW34 avatar Jan 18 '23 18:01 ZachJW34

Can you try adding "host": "127.0.0.1" to your apps/client/project.json for the serve.options configuration and see if it works? I tried it locally and it worked for me. You can still use localhost for visiting your site locally and telling Cypress how to connect but Webpack needs to be forced to use ipv4 over ipv6 (my understanding of DNS is fuzzy admittedly).

To be explicit, this is the update I made:

"serve": {
  "executor": "@nrwl/webpack:dev-server",
  "defaultConfiguration": "development",
  "options": {
    "buildTarget": "client:build",
    "hmr": true,
    "host": "127.0.0.1" <----
  },

Still investigating if there is an issue on our side. Cypress will warn the user it can't connect to the provided baseUrl, but in this case there is no warning yet the connection fails when using cy.visit.

Edit: After investigating, it looks like the issue is due to Nx's use of localhost for the default value of host used in for their webpack-dev-server executor. This use prohibits use of ipv4. Workaround described above should be enough, you can also use 0.0.0.0 to open both ipv4 and ipv6.

ZachJW34 avatar Jan 18 '23 19:01 ZachJW34

I closed this prematurely, I'm now seeing some buggy behavior based on your reproduction where a request made to your backend before visiting is causing Cypress to lock onto the ipv4 range (hence the 127.0.0.1 connection refused). Shifting the request to be after the visit doesn't display this behavior. I'm working on a very simple reproduction.

ZachJW34 avatar Jan 24 '23 20:01 ZachJW34

I've created a simple reproduction here. The README explains the bug in detail. My understanding of the bug is:

  • Setting host to localhost for the webpack-dev-server (the default value supplied by the nrwl/webpack-dev-server executor) inhibits the use of 127.0.0.1 (ipv4). You can still access the frontend site via localhost or [::1].
  • The backend server is listening on 127.0.0.1
  • When the cy.request is executed before the cy.visit, the subsequent visit is mapped to 127.0.0.1 rather than ::1. This causes the error as the frontend server will not accept requests from this IP as it is not listening to it.

If you move the request to after the visit, everything works fine. Also, if Cypress is allowed to visit before sending the request (by commenting out the request), adding the request back in works fine. There must be some server state being set from the initial request that influences subsequent visit requests.

ZachJW34 avatar Jan 24 '23 22:01 ZachJW34

Thank you @ZachJW34 for your detailed answers. To give some more context, we issue a request before visiting the page to create a test user (possibly not the best practice) and get a cookie for this user.

nicolas-marien avatar Jan 25 '23 15:01 nicolas-marien

@nicolas-marien your workflow is totally valid. I've routed this to the e2e team and they will prioritize accordingly.

ZachJW34 avatar Jan 25 '23 16:01 ZachJW34

@ZachJW34 thanks for the feedback.

nicolas-marien avatar Feb 08 '23 13:02 nicolas-marien

Are there any updates on this issue? Thanks.

gitnubster avatar Mar 01 '23 09:03 gitnubster

Same issue here I was using node 18.10 and cypress 12.9.0, I downgraded the node version to 16.13.2 and that fixed the issue.

cerojasg1 avatar Apr 13 '23 22:04 cerojasg1

We are unable to upgrade to node 18 due to this issue

UgurGumushan avatar May 08 '23 17:05 UgurGumushan

For me instructing the bundle server (in my case vite) to explicitly use host '127.0.0.1' fixed the issue.

lucaslenz avatar Jun 06 '23 13:06 lucaslenz

For me instructing the bundle server (in my case vite) to explicitly use host '127.0.0.1' fixed the issue.

This was solving the issue also on my dev-env. Using v12.9.0

dbeuchler avatar Jun 27 '23 14:06 dbeuchler

I have set default nvm version from 16 to 20 with nvm alias default 20 To make sure apps open outside the console have some latest nvm version (I intended to use Cypress GUI) Upgraded cypress to v12.17.3 And this resolved the problem

UgurGumushan avatar Aug 15 '23 17:08 UgurGumushan

The original issue was reported for Macos but same was happening on Windows for us. Upgrading to latest versions of Node and Cypress didn't help. The only thing which helped was changing the precedence rules for network stack by:

netsh interface ipv6 set prefix ::ffff:0:0/96 60 4

zihotki avatar Sep 05 '23 09:09 zihotki

I get this error after upgrading Node from 16 to 18 or 20. I'm not even using cy.request().

A workaround when using Vite is hinted at here: https://vitejs.dev/config/server-options.html#server-host

// vite.config.js
import { defineConfig } from 'vite'
import dns from 'dns'

dns.setDefaultResultOrder('ipv4first')

export default defineConfig({ ...

or set server.host to true but this will allow access to the server over the network


(Adding the code ECONNREFUSED to this thread to make it easier to find)

MetRonnie avatar Oct 23 '23 15:10 MetRonnie

This issue is painful to me, see my test results below.

Test machines:

  • Linux (RHEL 8): localhost resolves to ::1 first.
  • MacOS (Monterey): localhost resolves to 127.0.0.1 first.
  • Windows 10

Test project:

  • Node 18.18.2
  • Vite 4.4.5 (cannot listen both on ::1 and 127.0.0.1, unless it listens on all interfaces)
  • Cypress 13.4.0
  • Chrome browser

Test cases:

  • Case 1: Vite listens on localhost, Cypress baseUrl set to localhost
    • => Linux: baseUrl check passes, test fails (can't connect to localhost)
    • => Macos: baseUrl check passes, test fails (can't connect to localhost)
    • => Windows: both pass
  • Case 2: Vite listens on 127.0.0.1, Cypress baseUrl set to 127.0.0.1
    • => Linux: both pass
    • => MacOS: baseUrl check passes, test fails.
    • => Windows: both pass
  • Case 3: Vite listens on 127.0.0.1, Cypress baseUrl set to localhost
    • => Linux: baseUrl check fails, test passes
    • => MacOS: baseUrl check fails, test passes.
    • => Windows: both pass
  • Case 4: Vite listens on ::1, Cypress baseUrl set to http://[::1]:5173
    • => Cypress: invalid URL, see https://github.com/cypress-io/cypress/issues/25950
  • Case 5: Vite listens on all interfaces, Cypress baseUrl set to localhost
    • => Linux: both pass
    • => MacOS: both pass
    • => Windows: both pass

Conclusion:

  • Apart from case 5, I found no configuration that is platform independent and works.
  • Listening on all interfaces might be a security issue.

rkrisztian avatar Nov 07 '23 12:11 rkrisztian

@rkrisztian

Are you able to test on Node.js 20? In some circumstances I've noticed that these IPv4 / IPv6 issues are less of a problem on the later version of Node.js.

This is not to invalidate your issue in any way, but it might possibly be a workaround.

  • You've also linked to https://github.com/cypress-io/cypress/issues/25950 which I opened. I'm still waiting for the Cypress team to address this bug. I started to look at it myself and it looked like parse is working correctly, but when Cypress reconstructs a URL it doesn't put the necessary [ ] brackets back in to the literal IPv6 address and it breaks the syntax therefore.

MikeMcC399 avatar Nov 07 '23 12:11 MikeMcC399

Thanks, @MikeMcC399, I did some quick checks on Linux with Node v20.9.0, my test case results did not change, even the IPv6 issue is still the same.

rkrisztian avatar Nov 07 '23 14:11 rkrisztian

News about this? We are using Gatsby v5, and Node 18 is a requirement.

Things I've tried:

  • setting Node v20
  • NODE_OPTIONS: --dns-result-order=ipv4first
  • using 127.0.0.1 as baseURL instead of localhost

Considering this bug is almost a year old, I'd like to know if there is any workaround I'm missing.

cesarvarela avatar Nov 17 '23 22:11 cesarvarela

You just have to start your dev server / app on a host with an ipv4 address. In my case bun astro dev --host 127.0.0.1. No settings / parameters for cypress needed. It looks like cypress cannot resolve localhost to an ipv6 address. Hope that helps.

levino avatar Nov 20 '23 07:11 levino

I just run into this issue (Cypress v12.17.4 with node v18.16.1). Configure the serving webapp (Angular) to use the host "127.0.0.1" instead the default "localhost" fixed the problem on my side.

Before I found this workaroud in this issue-thread here I had another one (Working with proxy and default "localhost"-setting"): I'm working behind a proxy, but this proxy isn't defined globally. Only in the .npmrc the proxy is set. Cypress takes this proxy and says that it is managed by the system.

  • If I unset the proxy-settings in .npmrc cypress works fine.
  • If I let the proxy-settings in .npmrc as they are cypress cannot load localhost
  • If I let the proxy-settings in .npmrc as they are and try to override/unset them via a user-environment-variable before starting cypress it cannot load localhost (even cypress shows the correct overwritten proxysettings). So it points to an underlaying nodeJS-issue with a set proxy.

RobertWagnerPLG avatar Feb 02 '24 10:02 RobertWagnerPLG

My workaround for anyone interested (Using angular, but should work for any, imho)

I had a few personal requirements:

  • I did not want to change the host property. I want the app to run on localhost, not on 127.0.0.1
  • The workaround should not affect performance (total runtime of e2e test) to much (not at all at best)
  • should not cause alot of boilerplate
  • should not require thrid party tools, any extra effort

go to your support file cypress/support/e2e.ts and add this one line of code: fetch(Cypress.env('baseUrl'), { method: 'GET' }) // fire and forget

Edit 2024-08-29: The intend is to have the first http request go the front end. The support file runs before the tests (to eliminate race conditions). Depending on what other code you have in your support file, you should most likely put that line of code at the top of the file.

I figured, since the cause for the issue is a cy.request() (and it was still an issue, after I replaced my login logic with fetch()), we can just do a fetch before all tests run.

Of course you can use a hardcoded url for this fetch('http://localhost:4200', {method: 'GET'}), but I used mine from the cypress.config.ts image

Give me a thumbs up, if it works for you as well. I will report back, If I improve or change anything or if it stop working :C

RobinMeow avatar Apr 01 '24 20:04 RobinMeow

go to your support file cypress/support/e2e.ts and add this one line of code: fetch(Cypress.env('baseUrl'), { method: 'GET' }) // fire and forget

This resolved the issue for me, quick and easy without having to change the host.

rphmee-lo avatar Apr 10 '24 14:04 rphmee-lo

@RobinMeow solution worked like a charm. Thanks!

fre-ben avatar Apr 11 '24 10:04 fre-ben

I was using Node 20.10.0 and had to downgrade to Node 16.13.2. I can confirm that this is a bug.

robbporto avatar Apr 22 '24 22:04 robbporto

Ma solution de contournement pour toute personne intéressée (en utilisant angulaire, mais devrait fonctionner pour tout le monde, à mon humble avis)

J'avais quelques exigences personnelles :

  • Je ne voulais pas changer la propriété hôte. Je veux que l'application s'exécute sur localhost, pas sur 127.0.0.1
  • La solution de contournement ne devrait pas trop affecter les performances (durée d'exécution totale du test e2e) (pas du tout au mieux)
  • ne devrait pas causer beaucoup de passe-partout
  • ne devrait pas nécessiter d'outils tiers, aucun effort supplémentaire

allez dans votre fichier de support cypress/support/e2e.ts et ajoutez cette ligne de code : fetch(Cypress.env('baseUrl'), { method: 'GET' }) // fire and forget

J'ai pensé que, puisque la cause du problème est un cy.request() (et c'était toujours un problème, après avoir remplacé ma logique de connexion par fetch()) , nous pouvons simplement effectuer une récupération avant l'exécution de tous les tests.

Bien sûr, vous pouvez utiliser une URL codée en dur pour cela fetch('http://localhost:4200', {method: 'GET'}), mais j'ai utilisé la mienne ducypress.config.ts image

Donnez-moi un coup de pouce, si cela fonctionne aussi pour vous. Je ferai un rapport si j'améliore ou change quelque chose ou si cela cesse de fonctionner :C

what node version ? what angular version ? Because on my case dont work :( edit: a solution for me is set host to 0.0.0.0 and that work, url in cypress is localhost

ph1823 avatar Apr 25 '24 12:04 ph1823