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 dynamic Selenium Grid in Docker is described here.

info

Since v4.2.0, Gwen will generate docker files targetting the Selenium Grid instead of Selenoid.

Get started

First, start a new Gwen project or use an existing one.

Docker Setup

Since v3.16.0, the init --docker command was introduced to generate Docker and Grid 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 Grid files

yarn gwen init --docker

This will create the following files in your project:

./project                         # Your project root
└── /gwen
├── .env # Docker env file
├── Dockerfile # Docker image file
├── docker-compose.yml # Se Grid docker compose file
├── docker-compose-arm.yml # Se Grid docker compose file for ARMs
└── conf
└── /browsers
├──grid.conf # Se Grid remote driver settings
├──grid.toml # Se Grid docker config
└──grid-arm.toml # Se Grid docker config for ARMs

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 17 JRE installed.

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

# install tools
RUN apk update \
&& apk add bash \
&& apk add jq \
&& apk add curl \
&& apk add tzdata \
&& apk add openjdk17-jre

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

RUN mkdir /tmp/assets

Docker compose file

./project                         # Your project root
└── /gwen
├── docker-compose.yml # Se Grid docker compose file
└── docker-compose-arm.yml # Se Grid docker compose file for ARMs

The init --docker commad will create a gwen/docker-compose.yml file with the following content to create a Selenium Grid in Docker that Gwen will connect to.

services:

node-docker:
image: selenium/node-docker:4
volumes:
- $PWD/gwen/output/assets:/opt/selenium/assets
- $PWD/gwen/conf/browsers/grid.toml:/opt/selenium/docker.toml
- /var/run/docker.sock:/var/run/docker.sock
depends_on:
- selenium-hub
environment:
- SE_EVENT_BUS_HOST=selenium-hub
- SE_EVENT_BUS_PUBLISH_PORT=4442
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
- SE_NODE_DOCKER_CONFIG_FILENAME=docker.toml
- SE_START_VNC=true
- TZ
shm_size: 2gb

selenium-hub:
image: selenium/hub:4
container_name: selenium-hub
ports:
- "4442:4442"
- "4443:4443"
- "4444:4444"

gwen:
depends_on:
- node-docker
build:
context: .
dockerfile: Dockerfile
environment:
- GWEN_ENV
- GWEN_PROFILE
- GWEN_BROWSER
- GWEN_DRY_RUN
- GWEN_PARALLEL
- GWEN_THREADS
- GWEN_HEADLESS
- GWEN_VIDEO
- GWEN_WEB_VERSION
- SELENIUM_HUB
- NO_COLOR
- TZ
volumes:
- $PWD:/project
- $PWD/gwen/output/assets:/tmp/assets
working_dir: /project
command: bash -c "yarn install && yarn gwen -b -c gwen/conf/browsers/grid.conf gwen/features"

gwen-dry-run:
build:
context: .
dockerfile: Dockerfile
environment:
- GWEN_ENV
- GWEN_WEB_VERSION
- NO_COLOR
- TZ
volumes:
- "$PWD:/project"
working_dir: /project
command: bash -c "yarn install && yarn gwen -bn --parallel gwen/features"

It will also create a gwen/docker-compose-arm.toml file for ARMs, with the only difference being the toml file mapping.

- $PWD/gwen/conf/browsers/grid-arm.toml:/opt/selenium/docker.toml

Docker env file

Since v3.35.0

./project                         # Your project root
└── /gwen
└── .env # Docker env file

A gwen/.env file containing the following environment variable defaults will also be generated by init --docker.

SELENIUM_HUB=selenium-hub
NO_COLOR=1
TZ=Australia/Melbourne

Grid config file

./project                         # Your project root
└── /gwen
└── /conf
└── /browsers
├──grid.toml # Se Grid docker config
└──grid-arm.toml # Se Grid docker config for ARMs

The init --docker command will create a gwen/conf/browsers/grid.toml file with the following content that will be used to configure the node-docker service and spin up browser containers as specified.

[docker]
# Configs have a mapping between the Docker image to use and the capabilities that need to be matched to
# start a container with the given image.
configs = [
"selenium/standalone-chrome:4", '{"browserName": "chrome"}',
"selenium/standalone-edge:4", '{"browserName": "edge"}',
"selenium/standalone-firefox:4", '{"browserName": "firefox"}'
]

host-config-keys = ["Dns", "DnsOptions", "DnsSearch", "ExtraHosts", "Binds", "Mounts"]

# URL for connecting to the docker daemon
# Most simple approach, leave it as http://127.0.0.1:2375, and mount /var/run/docker.sock.
# 127.0.0.1 is used because internally the container uses socat when /var/run/docker.sock is mounted
# If var/run/docker.sock is not mounted:
# Windows: make sure Docker Desktop exposes the daemon via tcp, and use http://host.docker.internal:2375.
# macOS: install socat and run the following command, socat -4 TCP-LISTEN:2375,fork UNIX-CONNECT:/var/run/docker.sock,
# then use http://host.docker.internal:2375.
# Linux: varies from machine to machine, please mount /var/run/docker.sock. If this does not work, please create an issue.
url = "http://127.0.0.1:2375"

# Docker image used for video recording
video-image = "selenium/video:ffmpeg-7.1-20250101"

# Uncomment the following section if you are running the node on a separate VM
# Fill out the placeholders with appropriate values
#[server]
#host = <ip-from-node-machine>
#port = <port-from-node-machine>

It will also create a gwen/conf/browsers/grid-arm.toml file for ARMs, with the only difference being the browser list (namely chrome mapped to chromium and no edge).

configs = [
"selenium/standalone-chromium:4", '{"browserName": "chrome"}',
"selenium/standalone-firefox:4", '{"browserName": "firefox"}'
]

Remote driver settings file

./project                         # Your project root
└── /gwen
└── /conf
└── /browsers
└──grid.conf # Se Grid remote driver settings

The init --docker commad will create a gwen/conf/browsers/grid.conf file with the following content that will be used by Gwen to connect to the Grid with remote web driver.

gwen {
web {
capabilities {
"se:recordVideo" = false
"se:recordVideo" = ${?GWEN_VIDEO}
"se:screenResolution" = "1920x1080"
"se:timeZone" = "${env.TZ}"
}
remote {
url = "http://${env.SELENIUM_HUB}:4444/wd/hub"
localFileDetector = auto # auto|true|false
sessionRetries = auto # auto|true|false
connectTimeout {
seconds = 60
}
}
}
video {
dir = "${gwen.outDir}/assets/$<gwen.web.sessionId>"
timeoutSecs = 10
}
}

Run Gwen in docker

Start your docker desktop engine app if not already done so (see getting started with Docker for more info).

note

If you're on a Mac or ARM, replace gwen/docker-compose.yml with gwen/docker-compose-arm.yml

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 in docker and run your features

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

To execute features in parallel

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

To record video

GWEN_VIDEO=true docker-compose -f gwen/docker-compose.yml run gwen

To target a specific browser

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

To execute dry run instead (Since v3.35.0)

docker-compose -f gwen/docker-compose.yml run gwen-dry-run

Tear it all down when done

docker-compose -f gwen/docker-compose.yml down --remove-orphans

Run Gwen against Grid in your local Docker

Start your docker desktop engine app if not already done so (see getting started with Docker for more info).

note

If you're on a Mac or ARM, replace gwen/docker-compose.yml with gwen/docker-compose-arm.yml

If you wish to view active sessions in the Grid console, ensure that SE_START_VNC is set to true in your gwen/docker-compose.yml file.

services:

node-docker:
image: selenium/node-docker:4
volumes:
- $PWD/gwen/output/assets:/opt/selenium/assets
- $PWD/gwen/conf/browsers/grid.toml:/opt/selenium/docker.toml
- /var/run/docker.sock:/var/run/docker.sock
depends_on:
- selenium-hub
environment:
- SE_EVENT_BUS_HOST=selenium-hub
- SE_EVENT_BUS_PUBLISH_PORT=4442
- SE_EVENT_BUS_SUBSCRIBE_PORT=4443
- SE_NODE_DOCKER_CONFIG_FILENAME=docker.toml
- SE_START_VNC=true
- TZ
..

Run the following command to launch the Grid in Docker

docker-compose -f gwen/docker-compose.yml run -d --service-ports node-docker

Open http://localhost:4444/ui/ to access the Grid console and verify that it is running and available. It may take a few seconds.

Run the following command to launch Gwen against your Grid, specifying SELENIUM_HUB as localhost

SELENIUM_HUB=localhost yarn gwen -b -c gwen/conf/browsers/grid.conf gwen/features

If you have VNC enabled, you can click the active browser session in the Grid console to see it in action.

Tear it all down when done

docker-compose -f gwen/docker-compose.yml down --remove-orphans

Video capture

See also: Video recordings

If you set the GWEN_VIDEO environment variable or the se:recordVideo capability setting to true in your grid.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/conf/browsers/grid.conf

gwen {
web {
capabilities {
"se:recordVideo" = true
}
..
}
}
video settings
  • 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 headless browser or interactive (non --repl) modes are enabled.