Setting Up Cypress in CircleCI
The Problem
Congratulations, you have just setup Cypress to run your integration and end-to-end tests for your single page app π. All the tests run locally using cypress open
and you have even setup a yarn script to run your tests in a continuous integration environment with cypress run
. After setting up your initial .circleci/config.yaml
file, you run into a few walls and hit a few dead ends π£.
This was certainly the case for me, and unfortunately, there are a host of variables that might contribute to these issues. This is because Cypress relies on some system requirements that you likely already had installed on your local machine, but may not be installed on the CI server. Luckily, Cypress knew this could be an issue so they maintain a few different Docker images to be used for this purpose. There are also different assumptions made by each Docker image involved regarding the root working directory and where the .cache
directory lives. The following setup will help eliminate those variables to allow you to have a working Cypress/CircleCI test setup.
The Solution
Here are the jobs required to build and test a single page app in CircleCI. They are broken out into separate jobs because there would typically be other steps, like unit testing, that can be run in parallel.
1. Download Application Dependencies
detect_changes:docker:- image: circleci/node:lateststeps:- checkout- restore_cache:keys:- application-v1-{{ checksum "yarn.lock" }}- application-v1-- run:name: Install Dependenciescommand: yarn install- save_cache:paths:- node_modules- ~/.cachekey: application-v1-{{ checksum "yarn.lock" }}
2. Build the Application
build_application:docker:- image: circleci/node:lateststeps:- checkout- attach_workspace:at: ~/app- restore_cache:keys:- application-v1-{{ checksum "yarn.lock" }}- application-v1-- run:name: Build Applicationcommand: yarn build- persist_to_workspace:root: ./paths:- build
3. Run Integration Tests
run_integration_test:docker:- image: cypress/browsers:latestworking_directory: /home/circleci/appsteps:- checkout- attach_workspace:at: /home/cricleci/app- restore_cache:keys:- application-v1-{{ checksum "yarn.lock" }}- application-v1-- run:name: Link Cypress Binarycommand: ln -s /home/circleci/.cache ~/.cache- run:name: Run Acceptance Testscommand: yarn test:integration
It is important to list the images used in each step, because this is where a lot of assumptions between different images start to cause problems. You'll definitely want to use the Cypress Docker Image (cypress/browsers:latest
) to ensure Cypress has everything it needs to be able to run on its own.
The Setup
Image Working Directories
As previously mentioned, the root working directories for both images needed to build the application (circleci/node:latest
) and to run the integration tests (cypress/browsers:latest
are different.
circleci/node:latest
Default Working Directory: /home/circleci/
cypress/browsers:latest
Default Working Directory: /root/
This will cause issues when trying to access your cached node_modules
from the first build job (detect_changes
) and when trying to access the build
directory persisted in the second step (build_application
). To fix this, we must change the working directory of the Cypress image to be the same as the other circleci/node:latest
images.
working_directory: /home/circleci/app{...}- attach_workspace:at: /home/circleci/app
Cached Cypress
At this point, the integration tests should almost run. We have the /build
and /node_modules
directories successfully copied over to our Cypress image, but the tests will fail because they can't find the .cache
directory.
Cypress executable not found at: /root/.cache/Cypress/3.0.1/Cypress/Cypress
Once again the differing assumptions made by the two images causes this problem. The circleci/node:latest
image puts the cache in /home/circleci/.cache
, but the cypress/browsers:latest
image expects the folder to be in /root/.cache
. To fix this, we simply set a syamlink to point Cypress to the correct directory:
- run:name: Link Cypress Binarycommand: ln -s /home/circleci/.cache ~/.cache
Success!
Now Cypress should be running in CircleCI - hopefully all your tests pass π! Since there are so many things that need to be lined up in order for these images to work together, it is worth a recap:
- Use the Cypress Docker image
- Cypress needs a lot of system dependencies (taken care with the Docker image)
- Resolve the differences in root working directories
- Change the working directory of the Cypress image to
/home/circleci/app
- Change the working directory of the Cypress image to
- Syamlink the
.cache
directory so Cypress can find itln -s /home/circleci/.cache ~/.cache