If you are a Node.js developer, installing Cypress as a dev dependency in your package.json
file or even via direct download seems simple enough. Yet for developers working in other languages like Python or Go, using npm can be an obstacle. We often hear this question from developers:
Why don’t you have a Docker image with Cypress pre-installed?
Having an image with both OS dependencies and the Cypress test runner ready to go seems to be very convenient. We have listened and created a Docker image with Cypress installed. It is called cypress/included
and is tagged with the version of Cypress installed in the image. For now, we'll use the image for the current Cypress version as of this writing - the cypress/included:3.2.0
image. We create new images for every Cypress version released. The image is built on top of the cypress/base:12.1.0
image with Node 12.1.0 included. You can find our official Docker images in the cypress-docker-images repository and on Docker hub.
You can find the examples below in the repo demo-docker-cypress-included.
Running headless tests
If you have Cypress end-to-end tests, you can run them using the complete image. For example, if your project structure looks like this:
cypress/
integration/
spec.js
cypress.json
Then you can execute your Cypress tests using the following shell command:
$ docker run -it -v $PWD:/e2e -w /e2e cypress/included:3.2.0
==============================================================================
(Run Starting)
┌──────────────────────────────────────────────────────────────────────────┐
│ Cypress: 3.2.0 │
│ Browser: Electron 59 (headless) │
│ Specs: 1 found (spec.js) │
└──────────────────────────────────────────────────────────────────────────┘
──────────────────────────────────────────────────────────────────────────────
Running: spec.js... (1 of 1)
Cypress TodoMVC test
✓ adds 2 todos (1351ms)
...
Explanation of the "docker run" command line arguments
-it = interactive terminal
-v $PWD:/e2e = map current folder to /e2e inside the container
-w /e2e = set working directy to /e2e
Nothing to install, just write your spec files using your favorite editor and run them.
Commands and options
The image cypress/included:3.2.0
has the entrypoint set to cypress run
, so you don’t need to type it when running our Docker image. If you want a different command, you can change the entrypoint and then pass any additional arguments after the image name.
$ docker run -it -v $PWD:/e2e -w /e2e --entrypoint=cypress cypress/included:3.2.0 help
Usage: cypress [options] [command]
Options:
-v, --version prints Cypress version
-h, --help output usage information
Commands:
help Shows CLI help and exits
version prints Cypress version
run [options] Runs Cypress tests from the CLI without the GUI
open [options] Opens Cypress in the interactive GUI.
install [options] Installs the Cypress executable matching this package's version
verify Verifies that Cypress is installed correctly and executable
cache [options] Manages the Cypress binary cache
You can also pass environment variables into the container to control Cypress behavior. For example, the boolean config option video
controls if the video of the run is recorded. It is true
by default, but you can disable it via an environment variable.
$ CYPRESS_VIDEO=false
$ docker run -it -v $PWD:/e2e -w /e2e -e CYPRESS_VIDEO cypress/included:3.2.0
If you want to record the test run on the Cypress Dashboard to review later, you need to pass the record key and the --record
CLI flag.
$ docker run -it -v $PWD:/e2e -w /e2e \
-e CYPRESS_RECORD_KEY cypress/included:3.2.0 --record
Container info
To show the information about the operating system and pre-installed browsers, you can execute cypress info command:
$ docker run -it -v $PWD:/e2e -w /e2e --entrypoint=cypress cypress/included:6.2.1 info
Displaying Cypress info...
Detected 2 browsers installed:
1. Chrome
- Name: chrome
- Channel: stable
- Version: 87.0.4280.66
- Executable: google-chrome
2. Firefox
- Name: firefox
- Channel: stable
- Version: 82.0
- Executable: firefox
Note: to run these browsers, pass <name>:<channel> to the '--browser' field
Examples:
- cypress run --browser firefox
- cypress run --browser chrome
Learn More: https://on.cypress.io/launching-browsers
Proxy Settings: none detected
Environment Variables:
CYPRESS_CACHE_FOLDER: /root/.cache/Cypress
Application Data: /root/.config/cypress/cy/development
Browser Profiles: /root/.config/cypress/cy/development/browsers
Binary Caches: /root/.cache/Cypress
Cypress Version: 6.2.1
System Platform: linux (Debian - 10.5)
System Memory: 2.09 GB free 534 MB
We can see both Chrome and Firefox browsers pre-installed in the cypress/included:6.2.1
image. Let's run our tests using Firefox browser for example:
$ docker run -it -v $PWD:/e2e -w /e2e cypress/included:6.2.1 --browser firefox
========================================================================
(Run Starting)
┌──────────────────────────────────────────────────────────────────────┐
│ Cypress: 6.2.1 │
│ Browser: Firefox 82 │
│ Specs: 1 found (spec.js) │
└──────────────────────────────────────────────────────────────────────┘
...
Interactive mode
Running the tests inside a Docker container is nice, but it is missing my favorite Cypress feature: its interactive Test Runner with the Command Log, time-traveling debugger and live view of what is going on during the test! Typically, you would execute cypress open
to open the Test Runner in interactive mode, but how do we see it if Cypress opens inside a Docker container?
If you want to see Cypress in interactive mode, you need to forward the XVFB messages from Cypress out of the Docker container into an X11 server running on the host machine. I have done this on my Mac; other operating systems might require different commands.
I have installed an XQuartz X11 server following the instructions at Running GUI applications using Docker for Mac.
Then I grabbed the IP of the host machine and added it to the allowed X11 hosts.
$ IP=$(ipconfig getifaddr en0)
$ /usr/X11/bin/xhost + $IP
10.0.0.124 being added to access control list
Now you can execute a cypress open
command passing DISPLAY
and the X11 socket file to the container:
DISPLAY=$IP:0
docker run -it \
-v $PWD:/e2e \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-w /e2e \
-e DISPLAY \
--entrypoint cypress \
cypress/included:3.2.0 open --project .
Explanation of the "docker run" command line arguments:
-it = interactive terminal
-v $PWD:/e2e = map current folder to /e2e inside the container
-v /tmp/.X11-unix:/tmp/.X11-unix = map X11 socket file to communicate
-w /e2e = set working directy to /e2e
-e DISPLAY = pass environment variable DISPLAY to the container
--entrypoint cypress = run "cypress" command
with arguments AFTER Docker image name
in our case they are "--project ." to point globally installed Cypress
at the current working directory /e2e inside the container
The Docker container starts and you can see the full interactive Cypress Test Runner open. You can watch the test run, interact with the Command Log, open DevTools, etc. Even spec file watching is working - if you edit and save the cypress/integration/spec.js
file, the Test Runner picks up the change and reruns the tests.
Debugging tip: if Cypress shows an error Gtk-WARNING **: cannot open display:...
make sure X11 server allows connections over the network from the Docker container. Run xhost
command in the terminal to see if it has the IP address you have added previous with xhost + $IP
.
Docker compose
Using docker-compose to spawn services and run end-to-end tests is very convenient. We have coded several examples that show how to run a web application and Cypress tests in two Docker containers:
- cypress-example-docker-compose
- cypress-open-from-docker-compose which is a fork of mtlynch/hello-world-cypress
To support both cypress run
and cypress open
settings we recommend:
- placing the default settings for
cypress run
intodocker-compose.yml
file, for example, like this
# e2e/docker-compose.yml from repo
# https://github.com/bahmutov/cypress-open-from-docker-compose
version: '3.2'
services:
# this is the web application we are going to test
sentimentalyzer:
build: ../
environment:
- PORT=8123
# Cypress container
cypress:
# the Docker image to use from https://github.com/cypress-io/cypress-docker-images
image: "cypress/included:3.2.0"
depends_on:
- sentimentalyzer
environment:
# pass base url to test pointing at the web application
- CYPRESS_baseUrl=http://sentimentalyzer:8123
# share the current folder as volume to avoid copying
working_dir: /e2e
volumes:
- ./:/e2e
You can start the application, run the headless tests and close the services with command:
docker-compose up --exit-code-from cypress
- place the X11 configuration that enables
cypress open
Test Runner to show on the host machine in a separate YAML file that extends the above file. The second file only has additional environment variables and volumes
version: '3.2'
# e2e/cy-open.yml from repo
# https://github.com/bahmutov/cypress-open-from-docker-compose
services:
cypress:
# pass custom command to start Cypress otherwise it will use the entrypoint
# specified in the Cypress Docker image.
# also pass "--project <folder>" so that when Cypress opens
# it can find file "cypress.json" and show integration specs
# https://on.cypress.io/command-line#cypress-open
entrypoint: cypress open --project /e2e
environment:
# get the IP address of the host machine and allow X11 to accept
# incoming connections from that IP address
# IP=$(ipconfig getifaddr en0)
# /usr/X11/bin/xhost + $IP
# then pass the environment variable DISPLAY to show Cypress GUI on the host system
# DISPLAY=$IP:0
- DISPLAY
volumes:
# for Cypress to communicate with the X11 server pass this socket file
# in addition to any other mapped volumes
- /tmp/.X11-unix:/tmp/.X11-unix
To start in the interactive mode we need to pass both filenames to the docker
docker-compose -f docker-compose.yml -f cy-open.yml up --exit-code-from cypress
You should see the Test Runner and be able to run tests
Testing site on host
Let's consider another common situation: running the Test Runner inside a Docker container, while running the website on the host outside the container. First, start the website on the host machine
$ npm start
# website is running at http://localhost:2222
Now start the Test Runner but instead of localhost
use a special Docker domain that points back at the host machine:
DISPLAY=$IP:0
docker run -it \
-v $PWD:/e2e \
-w /e2e \
-e DISPLAY \
--entrypoint cypress \
cypress/included:3.2.0 open --project . \
--config baseUrl=http://host.docker.internal:2222
Explanation of the "docker run" command line arguments:
-it = interactive terminal
-v $PWD:/e2e = map current folder to /e2e inside the container
-w /e2e = set working directy to /e2e
-e DISPLAY = pass environment variable DISPLAY to the container
--entrypoint cypress = run "cypress" command
with arguments AFTER Docker image name
in our case they are "--project ." to point globally installed Cypress
at the current working directory /e2e inside the container
--config baseUrl=... = replace the default "baseUrl" with
special domain pointing to the website running on the host machine
Running the Test Runner in a Docker container allows us to debug font and encoding issues. For example the problem of missing Chinese characters in the cypress-documentation
translation is only visible on CI or inside a Docker container.
Start testing
That should give you all you need to start using Cypress in Docker for all your testing needs. If you were on the fence before due to compatibility concerns, worry no more, and download the Cypress app here.
More information
- Cypress Docker documentation page
- Official cypress-docker-images
- demo-docker-cypress-included
- cypress-open-from-docker-compose example
If you have any feedback for this approach or suggestions on how to make running Cypress even simpler for your team, please let us know. Open an issue in the cypress-io/cypress-docker-images repo or in the main cypress-io/cypress repo (and do not forget to give it a ⭐️!)
Bonus
If you want to run Cypress Test Runner inside a Docker container, while the web application is running on the host machine, read how to do this in "Run Cypress included from Docker container"
Bonus 2
You can use cypress/included
Docker image to run tests without installing any dependencies on GH Actions CI. See repository cypress-gh-action-included and its workflow file:
name: included
on: [push]
jobs:
cypress-run:
runs-on: ubuntu-latest
# Docker image with Cypress pre-installed
# https://github.com/cypress-io/cypress-docker-images/tree/master/included
container: cypress/included:3.8.3
steps:
- uses: actions/checkout@v1
- run: cypress run