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.
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.
- Yarn
- npm
- pnpm
Run the following command in the root of your project to generate all the necessary Docker and Grid files
yarn gwen init --docker
Run the following command in the root of your project to generate all the necessary Docker and Grid files
npm run gwen init --docker
Run the following command in the root of your project to generate all the necessary Docker and Grid files
pnpm 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).
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).
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
}
..
}
}
gwen-video.timeoutSecs
- Time to wait for asyncronous video writes to complete (override only if default does not suffice)
Videos will not be recorded when headless browser or interactive (non --repl) modes are enabled.