Cypress.io advanced setup

In my last projects, I’ve been using Cypress.io as an end to end testing solution (npm-registry-browser / react-fiber-experiments). It makes it easy to write, debug and record e2e tests.

If you want your team to write e2e tests, the dev experience must be straightforward:

  • You shouldn’t have to run more than one command line to launch your tests
  • You should have feedback
  • You should be able to debug your tests
  • You should be able to run your unit and e2e tests in parallel
  • You should be able to run your tests on a CI at some point

I will explain my setup. I won’t talk about how to write tests but how to run them against your code base / server (so there will be NO framework-specific code).

1) Cypress init

Install cypress then init your project. It will create a cypress directory containing default tests.

npm install --save-dev cypress
npx cypress open

Update the cypress.json file that was created and set the following:

{
  "baseUrl": "http://localhost:5000",
  "video": false
}
  • baseUrl: the url of the local server from where we will serve the production build
  • video: by default to true. You might not want to record video when running tests in local – otherwise, leave it to true (I will show on a future post how to setup Cypress on CI to record videos)

You will be ready to write your own tests and run them, but you will quickly feel that it misses some kind of automation …

2) Basics

You will need to install the following packages:

  • serve: use any other package that serves static sites
  • npm-run-all: a cli tool to run multiple npm-scripts in parallel or sequential
  • start-server-and-test: make sure to start testing only when server is ready
  • cross-env: set and use env vars across platforms

Install them:

npm install --save-dev serve npm-run-all start-server-and-test cross-env

3) Run your tests against a development server

You should be able to run your e2e tests while you are coding your project (a little like when you run your unit tests in watch mode). This will let you debug your tests.

We all have some kind of development toolchain, whether you rely on webpack, browserify or any other, I assume that:

  • npm start: starts your development server
  • your development server runs on http://localhost:3000

Here are the npm scripts we will use (change the start task to your own usage – I’m using a create-react-app based project as example):

scripts: {
  "start": "react-scripts start",
  "test:cypress:dev": "npm-run-all --parallel --race start 'cy:open -- --config baseUrl=http://localhost:3000'",
  "cy:open": "cypress open"
}

Running npm run test:cypress:dev will:

  • start your dev server (using npm start)
  • start the Cypress GUI (ready to test on your dev server at http://localhost:3000)

That way, you could choose to develop inside chrome or run your tests in the cypress GUI.

4) Run your tests against a production build

End to end tests should run in an environment that is the closest to production, to avoid the “it works on my machine” problem. So we will run them against a production build.

Here are the npm scripts we will use:

scripts: {
  "build": "react-scripts build",
  "test:cypress": "npm run build && npm run cy:start-server-and-test",
  "cy:start-server-and-test": "npx start-server-and-test serve :5000 cy:run",
  "serve": "npx serve --no-clipboard --single --listen 5000 build"
}

I will assume that you have some npm run build task that generates a production version of your project in the build folder (we all have that kind of task).

Running npm run test:cypress will:

  1. generate a production build (using npm run build)
  2. serve the build folder on http://localhost:5000
  3. finally, run the tests in headless mode

5) Run both your unit and e2e tests

Whatever the test framework you use, I will assume that you have setup your npm tasks to run your unit tests as:

  • test:unit: runs your unit tests in single run mode
  • test:unit:watch: runs your unit tests in watch mode

We will reuse a few tasks from the previous example, adding test, test:unit, test:unit:watch:

scripts: {
  "build": "react-scripts build",
  "test": "npm-run-all --parallel --silent test:unit test:cypress",
  "test:unit": "cross-env CI=true npm run test:unit:watch",
  "test:unit:watch": "react-scripts test --env=jsdom",
  "test:cypress": "npm run build && npm run cy:start-server-and-test",
  "cy:start-server-and-test": "npx start-server-and-test serve :5000 cy:run",
  "serve": "npx serve --no-clipboard --single --listen 5000 build"
}

Running npm test will launch in parallel test:unit and test:cypress, which means that while:

  • a production build is created and then served on http://localhost:5000 to be e2e tested
  • the unit tests will run

That way, you only have to run one command: npm test to run all your tests (unit AND e2e) – without even bothering about generating a production build / launching a test server – everything is included / run as soon as possible.

6) Conclusion

My testing workflow is based on the one I exposed in the following projects:

Check them out to learn more about react and testing.

If you followed all the steps, you should have the following tasks setup:

  • test: run both unit and e2e tests in parallel
  • test:unit: run your unit tests (if you had some)
  • test:cypress: run your e2e tests in headless mode
  • test:cypress:dev: launch your dev server + run your e2e tests in the Cypress GUI

 

Leave a Reply

Your email address will not be published. Required fields are marked *