Setting Up Cypress in CircleCI

03/08/2019 β€” 2 Min Read β€” In CircleCI, Cypress, Docker, Yarn

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:latest
steps:
- checkout
- restore_cache:
keys:
- application-v1-{{ checksum "yarn.lock" }}
- application-v1-
- run:
name: Install Dependencies
command: yarn install
- save_cache:
paths:
- node_modules
- ~/.cache
key: application-v1-{{ checksum "yarn.lock" }}

2. Build the Application

build_application:
docker:
- image: circleci/node:latest
steps:
- checkout
- attach_workspace:
at: ~/app
- restore_cache:
keys:
- application-v1-{{ checksum "yarn.lock" }}
- application-v1-
- run:
name: Build Application
command: yarn build
- persist_to_workspace:
root: ./
paths:
- build

3. Run Integration Tests

run_integration_test:
docker:
- image: cypress/browsers:latest
working_directory: /home/circleci/app
steps:
- checkout
- attach_workspace:
at: /home/cricleci/app
- restore_cache:
keys:
- application-v1-{{ checksum "yarn.lock" }}
- application-v1-
- run:
name: Link Cypress Binary
command: ln -s /home/circleci/.cache ~/.cache
- run:
name: Run Acceptance Tests
command: 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 Binary
command: 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
  • Syamlink the .cache directory so Cypress can find it
    • ln -s /home/circleci/.cache ~/.cache