Using Cypress from Docker container


Cypress docker image

Cypress docker image (Javascript version)

Of course, you can run Cypress without any docker images and install it as a node somewhere on your system and run from there Cypress tests. But if you decide to use Cypress like this, you might end up developing and testing your Cypress scripts in an environment that might be quite different than the environment where you plan to run your Cypress tests, which will be quite likely in a CI/CD pipeline.
By using the Cypress docker images provided by the Cypress community, you can make sure that the environment where you develop and test your Cypress scripts is exactly the same as the environment where your Cypress scripts will be used for e2e tests.

Cypress official docker images can be found here:

https://github.com/cypress-io/cypress-docker-images

Here is an example of how we could create a new docker image based on one of the official Cypress docker images, one of the images which already has browsers and node installed. A docker image suited for developing scripts locally on your computer, a docker image that would allow you to run Cypress with its normal GUI but started from within the container, for which we need the x11-apps package:

# Base image taken from:https://github.com/cypress-io/cypress-docker-images
FROM cypress/browsers:node16.14.0-chrome99-ff97 

# Create the folder where our project will be stored
RUN mkdir /testing

# We make it our workdirectory
WORKDIR /testing 

# Let's copy the essential folders and files that we MUST use to run our scripts
COPY ./cypress ./cypress
COPY ./cypress.env.json .
COPY ./cypress.config.js .
COPY ./package-lock.json .
COPY ./package.json .

# Install the cypress dependencies in the work directory
RUN npm install
RUN apt install -y x11-apps 

# Executable commands the container will use [Exec Form]
ENTRYPOINT ["npx", "cypress", "open"]

# With CMD in this case, we can specify more parameters to the last entrypoint
CMD [""]

Let’s save this docker file as dockerfile-cypress-headed.

During the build of the image, we copy our cypress files and scripts from the local repository on our host computer into the testing folder inside the container.

Let’s say our host OS is Windows. In this case, we could install the tool VcXsrv Windows X Server (https://sourceforge.net/projects/vcxsrv/) which allows us to access the Cypress GUI running inside the container.

Download and install Windows X Server (VcXsrv).

Once it is installed, you can run it by the XLaunch command in the Windows Start Menu.

Chose the following settings:

Now our host is ready to access the Cypress GUI inside the container. Next, we have to build our docker image based on the docker file we prepared above.

On a Windows system it is a good choice to use Windows WSL for running docker containers are more widespread and supported in the Linux world. To allow that you have to activate the [Use the WSL 2 based engine] option in docker:

To build our cypress image based on the dockerfile we prepared above we have to open a WSL command prompt and execute the following command:

docker build -f dockerfile-cypress-headed -t cypress/cypress-image-headed:1.0 .

Then you can run the docker on a Linux system (or from within the WSL environment in case of a Windows system) with the following docker command:

docker run -i –mount type=bind,source=path-to-cypress-root-path-on-host-system\cypress,target=/testing/cypress -w /testing -t –rm –e DISPLAY=”ip-address-of-the-host-system:0.0″ cypress/cypress-image-headed open

This command mounts the inner cypress folder, which is the folder one level below cypress.config.js which we already have copied (see docker image file above) in the docker image, to the cypress folder inside the testing folder inside the docker container.

The part with the DISPLAY parameter ensures that the cypress GUI will be accessible from the host.

Cypress docker image (TypeScript version)

Here we describe how we can prepare a package.json for Cypress with typescript support which we can then copy to the Cypress official image with OS, browser, and node but without Cypress itself. Then we can install cypress with typescript support with the package.json which we have prepared for this and which we will copy into the image.

The following article describes how to use TypeScript with Cypress:

https://docs.cypress.io/guides/tooling/typescript-support#Install-TypeScript

You can create a Cypress docker image based on one of the official Cypress docker images.

We have chosen the official Cypress image with OS, browsers, and node but without Cypress, because we want to install Cypress ourselves:

Dockerfile:

# Base image taken from:https://github.com/cypress-io/cypress-docker-images
FROM cypress/browsers:node16.14.0-chrome99-ff97 

# Create the folder where our project will be stored
RUN mkdir /testing

# We make it our workdirectory
WORKDIR /testing

# Let's copy the essential folders and files that we MUST use to run our scripts
COPY ./cypress ./cypress
COPY ./cypress.config.ts .
COPY ./package-cypress.json ./package.json
COPY ./tsconfig-cypress.json ./tsconfig.json

# Install the cypress dependencies in the work directory
RUN npm install
RUN apt install -y x11-apps

# Executable commands the container will use [Exec Form]
ENTRYPOINT ["npx", "cypress", "open"]

# With CMD in this case, we can specify more parameters to the last entrypoint
CMD [""]

For TypeScript support we need a tsconfig.json file:

tsconfig.json:

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["es5", "dom"],
    "types": ["cypress", "node"]
  },
  "include": ["**/*.ts"]
}

package.json:

{
    "name": "projectx",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "devDependencies": {
        "@babel/preset-typescript": "^7.12.7",
        "cypress": "^10.1.0",
        "typescript": "^4.1.2"
    },
    "author": "",
    "license": "ISC"
}

Create the image with the following command:

sudo docker build -f Dockerfile -t cypress/cypress-image-headed:1.0 .

Make sure that Xlaunch or a similar tool is installed on your Windows host (see “Cypress docker image (Javascript version)” section before) and ready. You need that for the Cypress GUI which will run inside the container and is accessible from the Windows Host system:

docker run -i --mount type=bind,source=absolute-path-to-cypress-root-folder/cypress,target=/testing/cypress -w /testing -t --rm -e DISPLAY="ip-address-of-the-host-system:0.0" cypress/cypress-image-headed:1.0 open

Now you can run your TypeScript Cypress scripts from the Cypress GUI

Changing the Chrome browser language inside the container

Sometimes have to run a Cypress test with Chrome set to a specific language. The following example shows one or many ways this can be achieved.

Let’s assume we have to make sure that Chrome is set to the Japanese language. To achieve this we have to make sure that before Cypress starts, the following environment variable is set as follows:

export LANG=ja_JP.UTF-8

We can set the environment directly in the docker file, but then we would have to create a new image if we wanted to change the language again. An alternative way would be to change and use a docker file that can execute some commands in an external bash script that is mounted (during the execution of the docker run command) into the docker container. This would allow us to change the language by changing the external script instead of rebuilding the docker file. The following example shows such a solution:

Dockerfile:

# Base image taken from:https://github.com/cypress-io/cypress-docker-images
FROM cypress/browsers:node16.14.0-chrome99-ff97 

# Create the folder where our project will be stored
RUN mkdir /testing

# We make it our workdirectory
WORKDIR /testing 

# Let's copy the essential folders and files that we MUST use to run our scripts
COPY ./cypress ./cypress
COPY ./cypress.env.json .
COPY ./cypress.config.js .
COPY ./package-lock.json .
COPY ./package.json .

# Install the cypress dependencies in the work directory
RUN npm install
RUN apt install -y x11-apps 

# Executable commands the container will use [Exec Form]
ENTRYPOINT ["/testing/cypress/preparation.sh"]

# With CMD in this case, we can specify more parameters to the last entrypoint
CMD [""]


preparation.sh:

#!/bin/sh
#/etc/init.d/dbus start

export LANG=ja_JP.UTF-8
npx cypress open

Cypress then can be executed as follows and the preparation.sh script, which should be under path-to-cypress-root-path-on-host-system\cypress folder, is mounted into the /testing/cypress path inside the container:

docker run -i –mount type=bind,source=path-to-cypress-root-path-on-host-system\cypress,target=/testing/cypress -w /testing -t –rm -e DISPLAY=”ip-address-of-the-host-system:0.0″ cypress/cypress-image-headed

Passing environment variables to Cypress running in a container

You can also pass environment variables to Cypress from outside to the shell script ( preparation.sh in our example) referred by the entry point using the -e option.

docker run -i –mount type=bind,source=path-to-cypress-root-path-on-host-system\cypress,target=/testing/cypress -w /testing -t –rm -e CYPRESS_SERVER_ADDRESS=’https://tested-application-url/’ -e CYPRESS_PARAM_X=’xyz’ cypress/cypress-image-headed

Note: The order of parameters in the “docker run” command does matter. Make sure that environment variables appear before the docker image

You can retrieve the passed environment variable in the entry point script and pass it to Cypress like this:

preparation.sh:

#!/bin/sh
#/etc/init.d/dbus start

export LANG=ja_JP.UTF-8
echo "Test server address: $CYPRESS_SERVER_ADDRESS"
echo "Parameter X: $CYPRESS_PARAM_X"

npx cypress open --env CYPRESS_SERVER_ADDRESS=$CYPRESS_SERVER_ADDRESS,CYPRESS_PARAM_X=$CYPRESS_PARAM_X

Troubleshooting

Error: no matching manifest for windows/amd64 10.0.xxxxx in the manifest list entries

Problem

We have the following docker command in an Azure DevOps pipeline:

DOCKER_BUILDKIT=0 docker build -f dockerfile-t cypress/cypress-test-image .

During the Run the command above would lead to the following error:

...
Step 1/13 : FROM cypress/browsers:node16.16.0-chrome107-ff107-edge 
node16.16.0-chrome107-ff107-edge: Pulling from cypress/browsers 
no matching manifest for windows/amd64 10.0.xxxxx in the manifest list entries 
...

Potential Resolution

Change the pipeline agent to Linux instead of Windows:


pool:
vmImage: windows-latest

pool:
vmImage: “ubuntu-latest”