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

localhost:45456/start CORS error #39

Closed
mvasin opened this issue Jun 18, 2020 · 14 comments
Closed

localhost:45456/start CORS error #39

mvasin opened this issue Jun 18, 2020 · 14 comments

Comments

@mvasin
Copy link

mvasin commented Jun 18, 2020

Recently I created a repo to showcase how Mockttp can be controlled from within Cypress tests: https://github.com/mvasin/cypress-mockttp

The tests pass in GitHub Actions, but locally I bumped into an interesting problem.

The example repo fails with a CORS error, but only on one of my Macs. The other Mac does not have CORS issues. All I do on both Macs is

git clone https://github.com/mvasin/cypress-mockttp
cd cypress-mockttp
yarn && yarn cy

Here's the screenshot from the first Mac:

Screenshot 2020-06-18 at 19 39 29

And here's the screenshot from the second Mac:

Screenshot 2020-06-18 at 19 50 26

You can see on the screenshots that the /start pre-flight request on the first Mac does contain access-control-allow-origin: *, while the second doesn't, hence the CORS error on the second screenshot.

How can that happen given the same MacOS (10.5.5), same node version (12.13.0), the same Chrome version (83) that comes with the same Cypress version... I'm puzzled.

Given that I can't reproduce the issue myself 😅 (on the second computer) I'm fine with closing it if no one has a hint on what could it be.

@pimterry
Copy link
Member

Hmm, that's very very strange!

That's the start request to the standalone server, which just uses the standard Express cors module. It can do funky things if you pass cors options to it, but I can see that you're not doing that.

Is this failing consistently on that machine, or was this a once-off? I've tested your demo locally on my machine and it seems to work fine & very reliably.

If you can reproduce this, can you sprinkle some logging into Mockttp's dist/standalone/mockttp-standalone.js and Cors's lib/index.js to get some more details?

Mockttp should set up CORS here (options.corsOptions is undefined be default, that's fine). Cors should then be called with no options here, then receive the /start OPTIONS request here and add the Origin header here. Something in that process isn't happening for some reason.

@pimterry
Copy link
Member

Ah, one way I can think of that you might hit this is if you run your tests with the HTTP Toolkit server running. HTTP Toolkit starts a standalone server, and does configure it with CORS options, as part of blocking other origins from making XSRF requests to reconfigure the application.

I've tested and this shouldn't be possible (your example refuses to start if the standalone server can't startup because the 45456 port is already taken).

If you somehow managed to get past that though and then run the tests without realizing that you're using the locked-down standalone server then you'd see something like the issue you're describing.

@mvasin
Copy link
Author

mvasin commented Jun 19, 2020

Woo-hoo, I was able to make it reproducible: just start HTTP toolkit before starting the Cypress test!

It works the other way around: start the Cypress test, you can wait until it passes or not - doesn't matter, but don't close the Chrome window started by Cypress, then start HTTP toolkit fails to start.

@pimterry
Copy link
Member

Ah great, glad we've pinned that down. Does your test not fail to startup, complaining the port's already in use?

In the short term, that's what should happen, really - Mockttp should loudly fail to start the standalone server straight away.

I'd like to avoid making the HTTP Toolkit port configurable, since it makes a bunch of stuff more complicated, but the Mockttp port is already configurable so you can use that to fix this:

  • Pass a port to the standalone like getStandalone().start(port)
  • Specify an explicit URL when connecting to the standalone server like getLocal({ standaloneServerUrl: "http://localhost:" + port })

That should let you avoid any conflicts in future.

@mvasin
Copy link
Author

mvasin commented Jun 19, 2020

Does your test not fail to startup, complaining the port's already in use?

If that would happen, that would make it way more obvious. But I only see the CORS error, as in the screenshot.

I will change the Mockttp proxy factory "control port" to something else, but if the HTTP toolkit would also run on a non-default port (not 45456), that would reduce the chance of conflicts for other users. It doesn't have to be configurable in the HTTP toolkit UI, just a hardcoded different port.

But... even then, a chance that those "control ports" will collide still exist. Maybe an optional "proxy factory id" can be supplied on instantiation of the proxy factory and of the remote control, then most of Mockttp users will just not set it, but HTTP toolkit will have it set, and when an unexpected "remote control" knocks to the wrong "proxy factory", we would respond with an informative error.

@mvasin
Copy link
Author

mvasin commented Jun 19, 2020

When the mock servers collide on a port, the error message is beautifully informative. If mock server factory collisions (the "remote control" port collisions) would produce something similar, that would be great.
Screenshot 2020-06-19 at 18 25 31

@pimterry
Copy link
Member

Does your test not fail to startup, complaining the port's already in use?

If that would happen, that would make it way more obvious. But I only see the CORS error, as in the screenshot.

This is quite surprising. On my machine, this happens:

➜ yarn cy                                            
yarn run v1.3.2
$ start-server-and-test start:mock-server http-get://localhost:9999 cy:open
1: starting server using command "npm run start:mock-server"
and when url "http-get://localhost:9999" is responding with HTTP status code 200
running tests using command "npm run cy:open"


> [email protected] start:mock-server /tmp/tmp.yy3Hf3YyDw/cypress-mockttp
> ts-node server.ts

Error: listen EADDRINUSE: address already in use :::45456
    at Server.setupListenHandle [as _listen2] (net.js:1270:14)
    at listenInCluster (net.js:1318:12)
    at Server.listen (net.js:1405:7)
    at Function.listen (/tmp/tmp.yy3Hf3YyDw/cypress-mockttp/node_modules/express/lib/application.js:618:24)
    at Promise (/tmp/tmp.yy3Hf3YyDw/cypress-mockttp/node_modules/mockttp/src/standalone/mockttp-standalone.ts:125:48)
    at new Promise (<anonymous>)
    at MockttpStandalone.<anonymous> (/tmp/tmp.yy3Hf3YyDw/cypress-mockttp/node_modules/mockttp/src/standalone/mockttp-standalone.ts:124:15)
    at Generator.next (<anonymous>)
    at /tmp/tmp.yy3Hf3YyDw/cypress-mockttp/node_modules/mockttp/dist/standalone/mockttp-standalone.js:11:71
    at new Promise (<anonymous>)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] start:mock-server: `ts-node server.ts`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the [email protected] start:mock-server script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/tim/.npm/_logs/2020-06-23T13_42_20_816Z-debug.log
Error: server closed unexpectedly
    at ChildProcess.onClose (/tmp/tmp.yy3Hf3YyDw/cypress-mockttp/node_modules/start-server-and-test/src/index.js:69:14)
    at ChildProcess.emit (events.js:189:13)
    at maybeClose (internal/child_process.js:970:16)
    at Process.ChildProcess._handle.onexit (internal/child_process.js:259:5)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Running start:mock-server crashes and exits immediately, because the port is in use, and Cypress never starts up at all.

Can you share the console output you're seeing?

What version of node are you using as well? That could be relevant.

This is where port conflicts should be failing I think - trying to start a standalone server should fail very loudly & clearly at the moment of conflict, just like trying to start a mock server does in the browser code. The error could be improved and explained better here of course, but either way there should already be a big loud error!

@mvasin
Copy link
Author

mvasin commented Jun 27, 2020

Hi Tim! I've got node v12.13.0. I don't have these errors.

We can compare the output of yarn cy:headless. Here's mine (given that HTTP toolkit was started before):

yarn cy:headless
yarn run v1.22.4
$ start-server-and-test start:mock-server http-get://localhost:9999 cy:run
1: starting server using command "npm run start:mock-server"
and when url "[ 'http-get://localhost:9999' ]" is responding with HTTP status code 200
running tests using command "npm run cy:run"

npm WARN lifecycle The node binary used for scripts is /var/folders/ns/85cnwvcx5ysb7jzr8hh_k4r80000gn/T/yarn--1593272964655-0.4019770125636768/node but npm is using /Users/mvasin/.nvm/versions/node/v12.13.0/bin/node itself. Use the `--scripts-prepend-node-path` option to include the path for the node binary npm was executed with.

> [email protected] start:mock-server /Users/mvasin/playground/cypress-mockttp
> ts-node server.ts

Mock server manager is started
npm WARN lifecycle The node binary used for scripts is /var/folders/ns/85cnwvcx5ysb7jzr8hh_k4r80000gn/T/yarn--1593272964655-0.4019770125636768/node but npm is using /Users/mvasin/.nvm/versions/node/v12.13.0/bin/node itself. Use the `--scripts-prepend-node-path` option to include the path for the node binary npm was executed with.

> [email protected] cy:run /Users/mvasin/playground/cypress-mockttp
> cypress run


====================================================================================================

  (Run Starting)

  ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
  │ Cypress:    4.5.0                                                                              │
  │ Browser:    Electron 80 (headless)                                                             │
  │ Specs:      1 found (dummy.spec.ts)                                                            │
  └────────────────────────────────────────────────────────────────────────────────────────────────┘


────────────────────────────────────────────────────────────────────────────────────────────────────
                                                                                                    
  Running:  dummy.spec.ts                                                                   (1 of 1)


  1) "before all" hook for "to cy.request"

  0 passing (390ms)
  1 failing

  1) Mockttp serves mocked responses
       "before all" hook for "to cy.request":
     TypeError: Network request failed

Because this error occurred during a `before all` hook we are skipping all of the remaining tests.
      at XMLHttpRequest.xhr.onerror (http://localhost:54358/__cypress/tests?p=dummy.spec.ts-644:21619:22)




  (Results)

  ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
  │ Tests:        1                                                                                │
  │ Passing:      0                                                                                │
  │ Failing:      1                                                                                │
  │ Pending:      0                                                                                │
  │ Skipped:      0                                                                                │
  │ Screenshots:  1                                                                                │
  │ Video:        true                                                                             │
  │ Duration:     0 seconds                                                                        │
  │ Spec Ran:     dummy.spec.ts                                                                    │
  └────────────────────────────────────────────────────────────────────────────────────────────────┘


  (Screenshots)

  -  /Users/mvasin/playground/cypress-mockttp/screenshots/dummy.spec.ts/to cy.request     (1280x720)
      -- before all hook (failed).png                                                               


  (Video)

  -  Started processing:  Compressing to 32 CRF                                                     
  -  Finished processing: /Users/mvasin/playground/cypress-mockttp/videos/dummy.spec.    (0 seconds)
                          ts.mp4                                                                    


====================================================================================================

  (Run Finished)


       Spec                                              Tests  Passing  Failing  Pending  Skipped  
  ┌────────────────────────────────────────────────────────────────────────────────────────────────┐
  │ ✖  dummy.spec.ts                            377ms        1        -        1        -        - │
  └────────────────────────────────────────────────────────────────────────────────────────────────┘
    ✖  1 of 1 failed (100%)                     377ms        1        -        1        -        -  

npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] cy:run: `cypress run`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the [email protected] cy:run script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/mvasin/.npm/_logs/2020-06-27T15_49_40_148Z-debug.log
Error: Command failed with exit code 1: npm run cy:run
    at makeError (/Users/mvasin/playground/cypress-mockttp/node_modules/start-server-and-test/node_modules/execa/lib/error.js:56:11)
    at handlePromise (/Users/mvasin/playground/cypress-mockttp/node_modules/start-server-and-test/node_modules/execa/index.js:114:26)
    at processTicksAndRejections (internal/process/task_queues.js:93:5) {
  command: 'npm run cy:run',
  exitCode: 1,
  signal: undefined,
  signalDescription: undefined,
  stdout: undefined,
  stderr: undefined,
  failed: true,
  timedOut: false,
  isCanceled: false,
  killed: false
}
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

@mvasin
Copy link
Author

mvasin commented Jun 27, 2020

Anyway, I guess using a port other than 45456 for HTTP toolkit (so it will less likely collide with the default Mockttp port) would be good enough.

@mvasin
Copy link
Author

mvasin commented Aug 15, 2020

Hi Tim!

I want to use mockttp -c CLI utility, but I'm afraid the port clash will happen again if I will use HTTP toolkit at the same time... What would make more sense - to tweak the HTTP toolkit standard port, or add a CLI utility param that would allow specifying a control port?

@pimterry
Copy link
Member

Hi @mvasin! Thanks for chasing this up, good catch.

I've now changed the Mockttp default to 45454 which won't conflict with HTTP Toolkit (which uses 45456 & 45457), and I've also added a -p [port] option to Mockttp's command line runner, so you can easily override that there too, if required.

That's all on master, but not quite released yet, watch this space.

Would that work for you?

@mvasin
Copy link
Author

mvasin commented Aug 17, 2020

Sounds spectacular! :D

@pimterry
Copy link
Member

This is now released, as part of Mockttp 1.0.0 🎉

Give it a go, let me know if you have any other trouble at all.

@mvasin
Copy link
Author

mvasin commented Aug 21, 2020

Thank you, and - congratulations with v.1.0, Tim!

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

No branches or pull requests

2 participants