Skip to main content

Running Gwen in Docker

Sometimes it may be useful to run Gwen in Docker. For example, if you want to run Gwen in a Jenkins pipeline on a build server or node agent. Setting up Gwen to run in a Selenoid container in Docker is describe here.

Docker Setup

Since v3.16.0, the init --docker command was introduced to generate Docker and Selenoid files in your project. You will need to create the files manually if you are using an older version.

Run the following command in the root of your project to generate all the necessary Docker and Selenoid files

yarn gwen init --docker

Dockerfile

./project                    # Your project root
└── /gwen
└──Dockerfile # Docker image file

The init --docker commad will create a gwen/DockerFile with the following content to build an Alpine Linux node and Yarn based image with bash and Open JDK 8 JRE installed.

# base alpine image with node
FROM node:17-alpine

# install bash and java
RUN apk update \
&& apk add bash \
&& apk add openjdk8-jre

# Run as a non root user
RUN addgroup -S gwen && adduser -S gwen -G gwen -u 4936
USER gwen

Should you prefer a Red Hat Linux and Open JDK 8 based image with node and Yarn installed instead, you can change the content to this:

# base Red Hat image with open JDK 8
FROM adoptopenjdk/openjdk8:ubi

# install node & yarn
RUN dnf module install nodejs:16 -y
RUN npm install --global yarn

# Run as a non root user
RUN useradd -u 4936 gwen
USER gwen

Docker compose file

./project                        # Your project root
└── /gwen
├── Dockerfile # Docker image file
└── docker-compose.yml # Docker compose YAML file

The init --docker commad will create a gwen/docker-compose.yml file with the following content to create containers for Gwen, Chrome, Firefox, and Edge web browsers, a video recorder, and a Selenoid hub that Gwen will connect to.

version: '3.5'
services:
chrome:
image: selenoid/chrome:latest
networks:
- gwen-net
edge:
image: browsers/edge:latest
networks:
- gwen-net
firefox:
image: selenoid/firefox:latest
networks:
- gwen-net
video-recorder:
image: selenoid/video-recorder:latest-release
networks:
- gwen-net
selenoid:
image: aerokube/selenoid:latest-release
networks:
- gwen-net
ports:
- "4444:4444"
volumes:
- "$PWD/gwen/browsers:/etc/selenoid/:ro"
- "/var/run/docker.sock:/var/run/docker.sock"
- "$PWD/gwen/output/.video:/opt/selenoid/video"
environment:
- OVERRIDE_VIDEO_OUTPUT_DIR=$PWD/gwen/output/.video
command: ["-container-network", "gwen-net", "-video-output-dir", "/opt/selenoid/video"]
selenoid-ui:
depends_on:
- selenoid
- $GWEN_BROWSER
image: aerokube/selenoid-ui:latest
environment:
- GWEN_BROWSER
networks:
- gwen-net
ports:
- "8999:8999"
command: ["--selenoid-uri", "http://selenoid:4444", "--listen", ":8999"]
gwen:
depends_on:
- selenoid
- video-recorder
- $GWEN_BROWSER
build:
context: .
dockerfile: Dockerfile
environment:
- SELENIUM_HUB=selenoid
- NO_COLOR=1
- GWEN_ENV
- GWEN_BROWSER
- GWEN_DRY_RUN
- GWEN_PARALLEL
- GWEN_THREADS
- GWEN_HEADLESS
- GWEN_VIDEO
volumes:
- "$PWD:/project"
working_dir: /project
command: bash -c "yarn install && yarn gwen:selenoid -b"
networks:
- gwen-net
networks:
gwen-net:
name: gwen-net

Selenoid browsers file

./project                    # Your project root
└── /gwen
└── /browsers
└──browsers.json # Selenoid browsers file

The init --docker commad will create a gwen/browsers/browsers.json file with the following content that will be used by Selenoid to stand up the browsers in Docker.

{
"chrome": {
"default": "latest",
"versions": {
"latest": {
"image": "selenoid/chrome:latest",
"port": "4444",
"path": "/"
}
}
},
"MicrosoftEdge": {
"default": "latest",
"versions": {
"latest": {
"image": "browsers/edge:latest",
"port": "4444",
"path": "/"
}
}
},
"firefox": {
"default": "latest",
"versions": {
"latest": {
"image": "selenoid/firefox:latest",
"port": "4444",
"path": "/wd/hub"
}
}
}
}

Gwen settings file

./project                    # Your project root
└── /gwen
└── /browsers
├──browsers.json # Selenoid browsers file
└──selenoid.conf # Selenoid Gwen settings

The init --docker commad will create a gwen/browsers/selenoid.conf file with the following content that will be used by Gwen to connect to Selenoid.

gwen {
web {
capabilities {
"selenoid:options" {
enableVNC = true
enableVideo = true
}
}
remote {
url = "http://${env.SELENIUM_HUB}:4444/wd/hub"
}
}
}

Package JSON script

Add the following gwen:selenoid script to the scripts section of the package.json file in your project.

./project             # Your project root
└── package.json # Package json file

This script will be called by the gwen container in the docker-compose file generated above.

"scripts": {
"gwen:selenoid": "gwen -c gwen/browsers/selenoid.conf gwen/features"
}

Or to run the samples bundled in Gwen:

"scripts": {
"gwen:selenoid": "gwen -c gwen/browsers/selenoid.conf gwen/samples"
}

Run Gwen in docker

Start your docker desktop engine (see getting started with Docker for more info).

Create the Gwen output directory if it does not already exist.

mkdir -p gwen/output

Run the following command to build your docker image

docker-compose -f gwen/docker-compose.yml build

Run the following command in your project directory to launch Gwen on chrome in docker

GWEN_BROWSER=chrome docker-compose -f gwen/docker-compose.yml run gwen

To execute features in parallel (you can pass any number of environment varaibles in this manner)

GWEN_BROWSER=chrome GWEN_PARALLEL=true docker-compose -f gwen/docker-compose.yml run gwen

Tear it all down when done

GWEN_BROWSER=chrome docker-compose -f gwen/docker-compose.yml down

Run Gwen locally with Selenoid UI

Make sure enableVNC = true in your selenoid settings. Then run the following command to launch the Selenoid UI service in Docker

GWEN_BROWSER=chrome docker-compose -f gwen/docker-compose.yml run -d --service-ports selenoid-ui

Open http://localhost:8999 in a browser to check that the Selenoid UI is running and avaialable

Run the following command to launch Gwen against your Selenoid instance in Docker. You will see browser session(s) appear in the Selenoid UI.

SELENIUM_HUB=localhost yarn gwen:selenoid

Tear it all down when done

GWEN_BROWSER=chrome docker-compose -f gwen/docker-compose.yml down

Video capture

See also: Video recordings

If you set the GWEN_VIDEO environment variable or the selenoid:options.enableVideo capability setting to true in your selenoid.conf file, MP4 video recordings of each session will be attached to the feature level HTML reports. Set this to false if you do not wish to capture video.

File: gwen/browsers/selenoid.conf

gwen {
web {
capabilities {
"selenoid:options" {
enableVNC = true
enableVideo = true
}
}
..
}
}
video settings
  • gwen-video.dir
    • Should match host directory mounted to /opt/selenoid/video in Selenoid video-recorder
  • gwen-video.timeoutSecs
    • Time to wait for asyncronous video writes to complete (override only if default does not suffice)
Limitation

Videos will not be recorded when parallel execution, headless browser, or interactive (non --batch/-b) modes are enabled.

Mac M1 notes

Chrome or Edge crashes

If you're running Chrome or Edge in a Selenoid docker container on a Mac M1 and encounter the following error

(unknown error: DevToolsActivePort file doesn't exist)

Make the following changes to the following files to use the experimanal Seleniarm images instead and try again.

File: gwen/docker-compose.yml

version: '3.5'
services:
chrome:
image: seleniarm/standalone-chromium:latest
networks:
- gwen-net
edge:
image: seleniarm/standalone-chromium:latest
networks:
- gwen-net

File: gwen/browsers/browsers.json

  {
"chrome": {
"default": "latest",
"versions": {
"latest": {
"image": "seleniarm/standalone-chromium:latest",
"port": "4444",
"path": "/"
}
}
},
"MicrosoftEdge": {
"default": "latest",
"versions": {
"latest": {
"image": "seleniarm/standalone-chromium:latest",
"port": "4444",
"path": "/"
}
}
}
}

The Selenoid video recorder won't work with the experimental Seleniarm images, so you should disable video

File: gwen/browsers/selenoid.conf

gwen {
web {
capabilities {
"selenoid:options" {
enableVNC = true
enableVideo = false
}
}
remote {
url = "http://${env.SELENIUM_HUB}:4444/wd/hub"
}
}
}