Cypress in Docker with VNC

Lately, I’ve been trying to do as much of my development work as possible inside Docker containers. I wrote a bit about this in a blog post in 2019.

My current project is using Cypress for automated browser testing, and after a little bit of research and experimenting, I’m now able to run everything in containers, using VNC to interact with the Cypress UI.

I intentionally wanted to do this with VNC so that I could easily connect/disconnect/ minimize the entire environment, potentially even having multiple VNC windows connected to different containers (for different projects). I wasn’t able to find much online documentation about specifically getting Cypress tests working in such an environment — but a couple of sources had pretty much what I needed.

Here, I’ll bring that information together and show you how I got Cypress running in a Docker container, viewable with a VNC client. However, this is not a general introduction to Docker or Cypress, so I’m going to assume you’re familiar with writing Dockerfiles, running Docker containers, and running Cypress tests.

Dockerfile

Below are some relevant portions of a Dockerfile that can run Node, X11, VNC, a window manager (Fluxbox in this case), and Google Chrome.

NOTE: It’s quite likely I don’t need to specify all of the UI-related libraries that are being installed here, but this is the list I had when I got things working, and it works. So I’m passing it along as is.

ANOTHER NOTE: Again, you’ll almost certainly need more than just this in your Dockerfile to use it as a development container. I’m only showing things related to getting Cypress running with VNC.


FROM ubuntu:20.0

RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y \
  curl \
  libgtk2.0-0 \
  libgtk-3-0 \
  libgbm-dev \
  libnotify-dev \
  libgconf-2-4 \
  libnss3 \
  libxss1 \
  libasound2 \
  libxtst6 \
  xauth \
  xvfb \
  x11vnc \
  fluxbox

#
# Install Node
#
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash -
RUN apt-get update && apt-get install -y nodejs
RUN npm install -g yarn

# Install Chrome
RUN curl https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -o /tmp/google-chrome.deb
RUN apt-get install -y /tmp/google-chrome.deb

CMD ["bash"]

Running the container

I use Docker Compose to manage my development containers. That makes it easy to run multiple containers that can all talk to each other, as well as manage mounting volumes and ports. For a container like this one, I’ll start the container with docker-compose up -d and then open a couple of bash sessions with:


  > docker-compose up -d
  > docker-compose exec dev bash

The relevant portion of my docker-compose.yml looks something like:


dev:
  build:
      context: .
      dockerfile: ./Dockerfile
  tty: true
  restart: unless-stopped
  ports:
    - "5920:5920"

X11 / VNC / Window Manager

As mentioned above, you first need to connect to the running container:


  docker-compose exec dev bash

I’m somewhat arbitrarily using :20 as the display (based on some other examples I copied). To start the Xvfb server, in the container run:


  Xvfb :20 -screen 0 1920x1080x16 &

UPDATE (2022-05-01): Since first writing this post I updated my Docker base image to be ubuntu:22.04. After doing so,
Xvfb stopped working. I was able to get it to work again by changing the command to:


  Xvfb :20 -extension GLX -screen 0 1920x1080x16 &

Next, start the VNC server:


  x11vnc -display :20 -N -forever -bg -o "/tmp/x11vnc.log"

And finally, a window manager:


  DISPLAY=:20 fluxbox -log /tmp/fluxbox.log &

Here’s the whole thing in a single script:


#!/bin/bash

Xvfb :20 -screen 0 1920x1080x16 &
sleep 1
x11vnc -display :20 -N -forever -bg -o "/tmp/x11vnc.log"
sleep 1
DISPLAY=:20 fluxbox -log /tmp/fluxbox.log &
wait

With this script, you can run start.sh & and it will do all of the steps and put the process in the background.

Cypress

Assuming you have your project checked out in the container (or bind mounted), you just need to install Cypress and start it up:


  > yarn install
  > yarn cypress install
  > DISPLAY=:20 yarn cypress open --browser chrome

VNC Client

And finally, you need to connect to the running VNC server. I like VNC Viewer, but any client should work.

If you’re running Docker locally, then you’ll want to specify the VNC Server as localhost:5900.

Cypress Running in a Docker Container

The more project-related work I can do in containers the better chance I have of being able to run things again down the road, after my laptop’s OS has been upgraded, etc. Being able to run the end-to-end browser tests in a container, and connect/disconnect as needed with a VNC Viewer is a really nice environment to work in — especially if you’re switching between different projects using different versions of things.

If this is something you’ve been interested in trying out, you definitely should.

Caveats

  • I’m running x11vnc without a password. That’s not a problem for my current development environment, but it might be something you’d want to lock down. If you look at the /tmp/x11vnc.log file, it has some instructions on what you might want to try.
  • Up to this point, I’ve just been starting all of the X11-related processes by hand after I start the container. I leave the development container running most of the time, so it’s not a hassle. I did poke around, and it looks like one option some have taken is to add something to your shell startup scripts (e.g. .bashrc) that checks for the processes and starts them if not found.
  • If you’ve been running Cypress on your local machine, you’ve probably set a base URL that’s something like: http://localhost:3000/api. With Cypress and Chrome running in the Docker container, that’s not going to work. If you’re running the containers on macOS, you can replace localhost with host.docker.internal. In my setup, I’m running the containers on a different machine, so I specify the hostname of that machine.
Conversation
  • ryan says:

    This article helped me a lot! Thank you for writing this!

  • Comments are closed.