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 buildvideo
: by default totrue
. You might not want to record video when running tests in local – otherwise, leave it totrue
(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 sitesnpm-run-all
: a cli tool to run multiple npm-scripts in parallel or sequentialstart-server-and-test
: make sure to start testing only when server is readycross-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:
- generate a production build (using
npm run build
) - serve the
build
folder on http://localhost:5000 - 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 modetest: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 paralleltest:unit
: run your unit tests (if you had some)test:cypress
: run your e2e tests in headless modetest:cypress:dev
: launch your dev server + run your e2e tests in the Cypress GUI