Example test validating phpinfo(), slowed down for the demo.
- What is ddev-playwright?
- Getting started
- SQLite tmpfs mount
- What the browser install sees
- Contributing
This repository contains an addon for integrating Playwright tests into your ddev project.
Highlights include:
- Support for both npm and yarn.
- Support for running headless tests.
- Support for running headed tests with remote access to the UI through your web browser.
- Only installs the heavy Playwright dependencies if a given local opts in to them.
- Does not require running Playwright in ddev, in case developers prefer to run on the host on locals.
- Optimizations to reduce build time, especially on locals when ddev versions are upgraded.
The full setup workflow is:
- Install the addon and commit the generated configuration.
- Initialize Playwright inside the container (creates
package.json, config, etc.). - Run
ddev install-playwrightto rebuild the web service with browser dependencies.
Tip: Re-run
ddev restartany time you update the Playwright version intest/playwright/package.jsonso the matching browser binaries are installed.
Tip: Tests live in
test/playwrightby default. To use a different path (e.g.tests/playwright), add it to.ddev/.env:PLAYWRIGHT_TEST_DIR=tests/playwrightthen
ddev restartbefore initializing Playwright. Substitute your chosen path fortest/playwrightin the commands below.
# 1. Install the addon.
ddev add-on get Lullabot/ddev-playwright
git add .
git add -f .ddev/config.playwright.yml
# 2. Initialize Playwright (choose npm or yarn).
mkdir -p test/playwright
ddev exec -d /var/www/html/test/playwright npm init playwright@latest
# Or yarn:
# ddev exec -d /var/www/html/test/playwright yarn create playwright
# 3. Install Playwright browser dependencies and cache them.
ddev install-playwright
# To run playwright's test command.
ddev playwright test
# To run with the UI.
ddev playwright test --headed
# To generate playwright code by browsing.
ddev playwright codegen
# To view the HTML test report.
# Bind to the loopback interface inside the container, which is sufficient for
# DDEV routing and keeps the report server more constrained.
ddev playwright show-report --host=127.0.0.1
# The report is then accessible at https://<PROJECT>.ddev.site:9324The following services are exposed with this addon:
| Service | URL | Notes |
|---|---|---|
| KasmVNC | https://<PROJECT>.ddev.site:8444 | Username is your local username. Password is secret. |
| Playwright Test Reports | https://<PROJECT>.ddev.site:9324 | This port is changed from the default to not conflict with running Playwright on the host. |
This addon mounts /tmp/sqlite as a tmpfs (in-memory) volume. The
@lullabot/playwright-drupal
package uses this path for per-test SQLite database copies, and keeping
the I/O in memory significantly improves parallel test performance. Feel free to use it for your own database driven tests.
Because tmpfs is volatile, ddev restart will clear the volume.
DDEV signs every *.ddev.site certificate with a per-host
mkcert root CA. On container
start this addon makes Chromium, Firefox, and WebKit all trust that CA,
so *.ddev.site loads cleanly without ignoreHTTPSErrors: true in any
Playwright project. The setup lives in
.ddev/web-entrypoint.d/mkcert-nssdb.sh:
- Chromium reads
~/.pki/nssdb; the script imports every mkcert root viacertutil. - Firefox (the Playwright build) reads an enterprise policy JSON
whose path is given by
PLAYWRIGHT_FIREFOX_POLICIES_JSON. The script writes that file;config.playwright.ymlsets the env var. - WebKit reads the system CA bundle directly, which DDEV already seeds, so it needs no extra handling.
Browsers are installed in a Docker layer, and that layer needs to know which
version of Playwright your project has locked. A pre-start hook stages the
files a package manager reads to answer that question into
.ddev/web-build/playwright:
package.json, package-lock.json, npm-shrinkwrap.json, yarn.lock,
.yarnrc.yml, .npmrc, and any *.tgz in your Playwright directory (for
local tarball dependencies).
Yarn Berry projects also get .yarn/releases, .yarn/patches,
.yarn/plugins and .yarn/cache. Those are install inputs — .yarn/cache
holds the packages themselves, so a zero-install project still installs.
.yarn/install-state.gz, .yarn/unplugged/ and .yarn/build-state.yml are
regenerated by yarn install and are left out. Note that .yarn/cache is
sized by your dependency tree, so a Berry project stages more than an npm one
— it changes only when your dependencies do, which is a rebuild you want.
Your specs, fixtures, and snapshot baselines are deliberately left out. The staged directory is bind-mounted into the build, so everything in it becomes part of that layer's cache key — staging a snapshot baseline would rebuild the web image, and every layer after it, each time you updated a screenshot. None of those files survive into the image anyway; the layer deletes its copy once the browsers are cached.
The practical consequence: a dependency in your package.json must be
resolvable from the Playwright directory alone. A file: dependency pointing
outside it (file:../../some-package.tgz) will fail to install during the
build. Move the target inside the Playwright directory and reference it
relatively.
This project uses conventional commits for all commit messages. A pre-commit hook is included to validate commit messages locally before pushing.
To install pre-commit:
pip install pre-commit
pre-commit install
pre-commit install --hook-type commit-msgIf you use Claude Code or GitHub Copilot, pre-commit is installed automatically when a session starts.
julienloizelet/ddev-playwright was a great inspiration for this work. It uses Playwright containers built by Microsoft for tests. A few questions on the implementation has some notes on the differences in the implementations. The main differences are:
- This addon stacks Playwright and KasmVNC into the web container. This makes accessing the system being tested (like Drupal) much easier. For example, with a Drupal site Playwright can easily call
drushor other CLI tools to set up tests. - The official Playwright containers do not ship with any sort of remote access to the Playwright UI. This repository (as well as
julienloizelet/ddev-playwright) includes KasmVNC to run tests in headed mode or to generate code. - By stacking Playwright into the web container, it simplifies permissions for writing Playwright's test reports back out.