Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .ddev/.env.playwright
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PLAYWRIGHT_DOCKER_IMAGE="mcr.microsoft.com/playwright:v1.64.1-noble"
15 changes: 15 additions & 0 deletions .ddev/addon-metadata/playwright/manifest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
name: playwright
repository: julienloizelet/ddev-playwright
version: v3.1.0
install_date: "2026-10-25T09:07:45+01:00"
project_files:
- commands/playwright/playwright
- commands/playwright/playwright-install
- commands/playwright/playwright-init
- playwright-build/Dockerfile
- playwright-build/kasmvnc.yaml
- playwright-build/xstartup
- playwright-build/entrypoint.sh
- docker-compose.playwright.yaml
global_files: []
removal_actions: []
24 changes: 24 additions & 0 deletions .ddev/commands/playwright/playwright
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
#ddev-generated
# Remove the line above if you don't want this file to be overwritten when you run
# ddev add-on get julienloizelet/ddev-playwright
#
# This file comes from https://github.com/julienloizelet/ddev-playwright
#
## Description: Run playwright command
## Usage: playwright [options] [command]
## Example: "ddev playwright test"
cd /var/www/html || exit 1
cd "${PLAYWRIGHT_TEST_DIR}" || exit 1

export PLAYWRIGHT_BROWSERS_PATH=0

if [ -f "package-lock.json" ]; then
npx playwright "$@"
elif [ -f "yarn.lock" ]; then
yarn playwright "$@"
else
echo "ERROR: could not find lock file for a supported package manager (npm, yarn) in '${PLAYWRIGHT_TEST_DIR}'"
echo "Please run 'ddev playwright-install' or 'ddev playwright-init' to install playwright."
exit 1
fi
48 changes: 48 additions & 0 deletions .ddev/commands/playwright/playwright-init
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env bash
#ddev-generated
# Remove the line above if you don't want this file to be overwritten when you run
# ddev add-on get julienloizelet/ddev-playwright
#
# This file comes from https://github.com/julienloizelet/ddev-playwright
#
## Description: Init playwright in PLAYWRIGHT_TEST_DIR
## Usage: playwright-init --pm [npm|yarn]
## Example: "ddev playwright-init --pm yarn"

function display_help() {
echo "Usage: $0 --pm [yarn|npm]"
echo "Example: $0 --pm yarn"
exit 1
}

# Default package manager is not set
PACKAGE_MANAGER=""

while [[ "$#" -gt 0 ]]; do
case $1 in
--pm) PACKAGE_MANAGER="$2"; shift ;;
*) echo "Unknown parameter passed: $1"; display_help ;;
esac
shift
done

# Check if package manager is specified and valid
if [[ -z "$PACKAGE_MANAGER" ]] || ! { [[ "$PACKAGE_MANAGER" == "yarn" ]] || [[ "$PACKAGE_MANAGER" == "npm" ]]; }; then
echo "Warning: Package manager should be specified with --pm and be one of 'yarn' or 'npm'."
echo "Defaulting to yarn"
PACKAGE_MANAGER="yarn"
fi

cd /var/www/html || exit 1
cd "${PLAYWRIGHT_TEST_DIR}" || exit 1

export PLAYWRIGHT_BROWSERS_PATH=0

if [[ $PACKAGE_MANAGER == "npm" ]]; then
npm init playwright@latest
elif [[ $PACKAGE_MANAGER == "yarn" ]]; then
yarn create playwright
fi

# Conditionally copy an .env file if an example file exists
[ -f .env.example ] && [ ! -f .env ] && cp -n .env.example .env; exit 0
50 changes: 50 additions & 0 deletions .ddev/commands/playwright/playwright-install
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/usr/bin/env bash
#ddev-generated
# Remove the line above if you don't want this file to be overwritten when you run
# ddev add-on get julienloizelet/ddev-playwright
#
# This file comes from https://github.com/julienloizelet/ddev-playwright
#
## Description: Install playwright in PLAYWRIGHT_TEST_DIR
## Usage: playwright-install --pm [npm|yarn]
## Example: "ddev playwright-install --pm npm"

function display_help() {
echo "Usage: $0 --pm [yarn|npm]"
echo "Example: $0 --pm yarn"
exit 1
}

# Default package manager is not set
PACKAGE_MANAGER=""

while [[ "$#" -gt 0 ]]; do
case $1 in
--pm) PACKAGE_MANAGER="$2"; shift ;;
*) echo "Unknown parameter passed: $1"; display_help ;;
esac
shift
done

# Check if package manager is specified and valid
if [[ -z "$PACKAGE_MANAGER" ]] || ! { [[ "$PACKAGE_MANAGER" == "yarn" ]] || [[ "$PACKAGE_MANAGER" == "npm" ]]; }; then
echo "Warning: Package manager should be specified with --pm and be one of 'yarn' or 'npm'."
echo "Defaulting to yarn"
PACKAGE_MANAGER="yarn"
fi

cd /var/www/html || exit 1
cd "${PLAYWRIGHT_TEST_DIR}" || exit 1

export PLAYWRIGHT_BROWSERS_PATH=0

if [[ $PACKAGE_MANAGER == "npm" ]]; then
npm install
npx playwright install --with-deps
elif [[ $PACKAGE_MANAGER == "yarn" ]]; then
yarn install
yarn playwright install --with-deps
fi

# Conditionally copy an .env file if an example file exists
[ -f .env.example ] && [ ! -f .env ] && cp -n .env.example .env; exit 0
2 changes: 1 addition & 1 deletion .ddev/config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: os2forms-f2
type: drupal11
docroot: Drupal
docroot: web
php_version: "8.4"
webserver_type: nginx-fpm
xdebug_enabled: false
Expand Down
4 changes: 4 additions & 0 deletions .ddev/docker-compose.override.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
services:
playwright:
volumes:
- ../docs/user-manual:/docs/user-manual
44 changes: 44 additions & 0 deletions .ddev/docker-compose.playwright.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#ddev-generated
# Remove the line above if you don't want this file to be overwritten when you run
# ddev add-on get julienloizelet/ddev-playwright
#
# This file comes from https://github.com/julienloizelet/ddev-playwright
#
services:
playwright:
image: ${PLAYWRIGHT_DOCKER_IMAGE:-mcr.microsoft.com/playwright:v1.62.1-noble}-${DDEV_SITENAME}-built
build:
context: playwright-build
args:
PLAYWRIGHT_DOCKER_IMAGE: ${PLAYWRIGHT_DOCKER_IMAGE:-mcr.microsoft.com/playwright:v1.62.1-noble}
KASMVNC_VERSION: ${KASMVNC_VERSION:-1.4.0}
username: ${DDEV_USER}
uid: ${DDEV_UID}
gid: ${DDEV_GID}
container_name: ddev-${DDEV_SITENAME}-playwright
user: "${DDEV_UID}:${DDEV_GID}"
hostname: ${DDEV_SITENAME}-playwright
# These labels ensure this service is discoverable by ddev.
labels:
com.ddev.site-name: ${DDEV_SITENAME}
com.ddev.approot: ${DDEV_APPROOT}
environment:
# Modify the PLAYWRIGHT_TEST_DIR folder path to suit your needs
- PLAYWRIGHT_TEST_DIR=tests/Playwright
- NETWORK_IFACE=eth0
- DISPLAY=:1
- VIRTUAL_HOST=$DDEV_HOSTNAME
- HTTP_EXPOSE=8443:8444,9322:9323
- HTTPS_EXPOSE=8444:8444,9323:9323
expose:
- "8444"
- "9323"
depends_on:
- web
volumes:
- .:/mnt/ddev_config
- ddev-global-cache:/mnt/ddev-global-cache
- ../:/var/www/html:rw
working_dir: /var/www/html
x-ddev:
ssh-shell: bash
96 changes: 96 additions & 0 deletions .ddev/playwright-build/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#ddev-generated
# Remove the line above if you don't want this file to be overwritten when you run
# ddev add-on get julienloizelet/ddev-playwright
#
# This file comes from https://github.com/julienloizelet/ddev-playwright
#
ARG PLAYWRIGHT_DOCKER_IMAGE=mcr.microsoft.com/playwright:v1.62.1-noble
ARG KASMVNC_VERSION=1.4.0
FROM ${PLAYWRIGHT_DOCKER_IMAGE}

ARG PLAYWRIGHT_DOCKER_IMAGE
ARG KASMVNC_VERSION
LABEL PARENT_IMAGE="${PLAYWRIGHT_DOCKER_IMAGE}"

# Debian images by default disable apt caching, so turn it on until we finish
# the build.
RUN mv /etc/apt/apt.conf.d/docker-clean /etc/apt/docker-clean-disabled

# Remove any existing pwuser/ubuntu users to avoid UID conflicts
RUN deluser --remove-home pwuser || true
RUN deluser --remove-home ubuntu || true
# Accept build arguments for user creation
ARG username
ARG uid
ARG gid
# Ensure tty group exists
RUN getent group tty || groupadd tty
# Create group and user, trying multiple methods for compatibility
RUN (groupadd --gid "$gid" "$username" || groupadd "$username" || true) && \
(useradd -G tty -l -m -s "/bin/bash" --gid "$username" --comment '' --uid "$uid" "$username" || \
useradd -G tty -l -m -s "/bin/bash" --gid "$username" --comment '' "$username" || \
useradd -G tty -l -m -s "/bin/bash" --gid "$gid" --comment '' "$username" || \
useradd -G tty -l -m -s "/bin/bash" --comment '' "$username")

# Define CAROOT for mkcert
ENV CAROOT=/mnt/ddev-global-cache/mkcert

RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update \
&& apt-get install -y sudo

# Allow the `$username` user passwordless sudo for `mkcert -install`
RUN mkdir -p /etc/sudoers.d && \
echo "$username ALL=(ALL) NOPASSWD: ALL" > "/etc/sudoers.d/$username" && \
chmod 0440 "/etc/sudoers.d/$username"

# Install mkcert for the correct architecture
ARG TARGETARCH
RUN mkdir -p /usr/local/bin && \
curl --fail -JL -s -o /usr/local/bin/mkcert "https://dl.filippo.io/mkcert/latest?for=linux/${TARGETARCH}" && \
chmod +x /usr/local/bin/mkcert

# Install a window manager.
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt-get update \
&& apt-get install -y icewm xauth

# Enable universe repository for Ubuntu (needed for KasmVNC dependencies for some versions).
RUN apt-get update && apt-get install -y software-properties-common && \
add-apt-repository -y universe && apt-get update


# Install KasmVNC for remote access.
RUN if echo "$PLAYWRIGHT_DOCKER_IMAGE" | grep -q "jammy"; then \
KASMVNC_DIST="jammy"; \
elif echo "$PLAYWRIGHT_DOCKER_IMAGE" | grep -q "noble"; then \
KASMVNC_DIST="noble"; \
else \
KASMVNC_DIST="bullseye"; \
fi && \
wget https://github.com/kasmtech/KasmVNC/releases/download/v${KASMVNC_VERSION}/kasmvncserver_${KASMVNC_DIST}_${KASMVNC_VERSION}_${TARGETARCH}.deb && \
apt-get install -y ./kasmvncserver*.deb && \
rm -f kasmvncserver*.deb

# We're done with apt so disable caching again for the final image.
RUN mv /etc/apt/docker-clean-disabled /etc/apt/apt.conf.d/docker-clean

# Prepare KasmVNC
RUN mkdir -p "/home/$username/.vnc"
COPY kasmvnc.yaml xstartup /home/"$username"/.vnc/
RUN touch "/home/$username/.vnc/.de-was-selected"
# We actually disable auth, but KASM complains without it
RUN sudo -u "$username" /bin/bash -c "echo -e \"secret\nsecret\n\" | kasmvncpasswd -wo -u \"$username\""
RUN chown -R "$uid:$gid" "/home/$username"
RUN usermod -a -G ssl-cert "$username"

# Create the X11 socket directory with the standard permissions.
# The container runs as an unprivileged user. Xvnc would still create this
# directory itself, but it prints a misleading
# "_XSERVTransmkdir: ERROR: euid != 0" message in its log every time it does.
RUN mkdir -p /tmp/.X11-unix && chmod 1777 /tmp/.X11-unix

COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
51 changes: 51 additions & 0 deletions .ddev/playwright-build/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env bash
#ddev-generated
# Remove the line above if you don't want this file to be overwritten when you run
# ddev add-on get julienloizelet/ddev-playwright
#
# This file comes from https://github.com/julienloizelet/ddev-playwright
#

# Install DDEV certificate
mkcert -install

# Set up homeadditions if present
if [ -d /mnt/ddev_config/.homeadditions ]; then
cp -r /mnt/ddev_config/.homeadditions/. $HOME/
fi

# Remove stale X11 lock and socket files.
# When the container was not stopped cleanly (crash, kill, host reboot), DDEV
# restarts the same container and these files survive in /tmp. KasmVNC would
# then consider display :1 taken and start Xvnc on :2, while everything else
# expects DISPLAY=:1, so the window manager would fail and the container would
# exit. Nothing else is running at this point, so removing them is safe.
rm -f /tmp/.X*-lock /tmp/.X11-unix/X*

# Stop Xvnc cleanly when the container is stopped, so that its lock, socket and
# pid files are removed.
stop_vnc() {
sudo -u "$(whoami)" vncserver -kill :1
exit 0
}
trap stop_vnc TERM INT

# Start KasmVNC server on display :1.
# Xvnc and the applications of xstartup are started in the background, then
# vncserver returns. Requesting :1 explicitly makes vncserver fail if that
# display is not available, instead of silently using another one.
# sudo does not change the user here, but it re-initializes the supplementary
# groups (ssl-cert, tty) that Docker drops when the container is started with
# "user: uid:gid". vncserver refuses to start when it cannot read the KasmVNC
# certificate key, which belongs to the ssl-cert group.
sudo -u "$(whoami)" vncserver :1 -disableBasicAuth || exit 1

# Keep the container alive as long as Xvnc runs.
# The lifetime of the container is bound to Xvnc, not to the window manager
# started by xstartup: if the window manager fails, headless tests keep working.
XVNC_PID=$(cat "$HOME/.vnc/$(uname -n):1.pid")
while kill -0 "$XVNC_PID" 2>/dev/null; do
sleep 1
done
echo "Xvnc (PID $XVNC_PID) exited, stopping the container" >&2
exit 1
24 changes: 24 additions & 0 deletions .ddev/playwright-build/kasmvnc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ddev-generated
# Remove the line above if you don't want this file to be overwritten when you run
# ddev add-on get julienloizelet/ddev-playwright
#
# This file comes from https://github.com/julienloizelet/ddev-playwright
#
logging:
log_writer_name: all
log_dest: syslog
level: 100

network:
ssl:
require_ssl: false
udp:
# Skip the public IP lookup that Xvnc performs when it starts.
# Without a fixed value, KasmVNC sends a STUN request to each of seven
# hardcoded internet servers and waits up to 10 seconds for each answer.
# On hosts where outgoing UDP is filtered, Xvnc blocks for about
# 70 seconds, X clients cannot connect in the meantime, and Xvnc then
# exits, which stops the container.
# See https://github.com/julienloizelet/ddev-playwright/issues/38
# The UDP transport is not reachable through the DDEV router anyway.
public_ip: 127.0.0.1
Loading
Loading