Need to understand best way to configure react and cypress

Viewed 796

I just have a question around best method to start my react app when I run cypress test. Right now the way its setup for me I need to start my server then run cypress test. I would like a single command to start react app -> run Cypress test.

I am new to both react and cypress

My package.json looks like this

  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "cypress run",
    "eject": "react-scripts eject"
  },

Currently I need to run npm start then in another window npm test

I tried to start and run test in a single line but I could not get it to work. It just started react app and did nothing else.

2 Answers

I wrote this up recently as part of a series on TDD in JS, you can read the full article on my blog.


First, install some useful helper dependencies:

$ npm install concurrently cross-env wait-on

Then add some extra scripts to the package.json:

"e2e:ci": "concurrently -k -s first \"npm:e2e:ci:*\"",
"e2e:ci:app": "cross-env BROWSER=none PORT=4321 npm start",
"pree2e:ci:run": "wait-on -t 30000 http-get://localhost:4321",
"e2e:ci:run": "cross-env CYPRESS_BASE_URL=http://localhost:4321 npm run e2e",

So what does that do? When we run npm run e2e:ci, the concurrently script is going to run two things in parallel for us:

  • e2e:ci:app: Run the app using npm start, with some environment variables set via cross-env (this allows it to work on *nix and Windows):
    • BROWSER=none stops the browser from popping up and taking over the screen [this is the default behaviour of a React app created by CRA, which the article was using]; and
    • PORT=4321 runs the app on the specified port (so we can still have a version running on port 3000 without causing any conflicts).
  • e2e:ci:run: Run the E2E tests in a two-step process:
    • The pre script runs first, and uses wait-on to wait for up to 30,000ms for the app to be running on the specified port; then
    • If that works (i.e. the app starts in less than 30s) run the actual tests, with the baseUrl configuration overridden to point to the right place.

The other configuration options passed to concurrently itself are:

  • -k, meaning stop all of the other processes when one exits (in this case we expect our tests to exit at some point and want to stop the app when they do); and
  • -s first, meaning that the output of the overall command is the output of the first one to exit (i.e. output from the e2e:ci command should be the output from the tests).

Building on the answer by jonrsharpe, I also needed to launch my (golang, though the implementation language doesn't really matter) api server, and I'm running tests via wdio. It uses the same toolset as his answer but with an extra step:

    "e2e:ci": "concurrently -k -s first \"npm:e2e:ci:*\"",
    "e2e:ci:server": "cross-env SERVER_PORT=40001 ./launchServer.sh",
    "pree2e:ci:app": "wait-on -t30000 http-get://localhost:40001/state",
    "e2e:ci:app": "cross-env BROWSER=none PORT=40002 npm start",
    "pree2e:ci:run": "wait-on -t 30000 http-get://localhost:40002",
    "e2e:ci:run": "npx wdio run ./wdio.conf.js --baseUrl http://localhost:40002"

The two extra scripts are:

  • e2e:ci:server which runs a script to launch the server
  • pree2e:ci:app just waits until the server is running. Note that it's not just waiting on "/" -- my api server 404s on root requests, and wait-on needs to get a 2xx response, so the http-get url needs to be a valid api endpoint ("/state").

It's also worth noting that wdio just uses an extra command line argument to set the base url instead of the env var in the original cypress solution.

Related