If you find this add-on useful, please star it on GitHub — stars show appreciation and help maintainers know their work matters.
Example test validating phpinfo(), slowed down for the demo.
This repository contains an addon for integrating Playwright tests into your ddev project.
Highlights include:
The full setup workflow is:
package.json, config, etc.).ddev install-playwright to 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:9324
The 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:
~/.pki/nssdb; the script imports every mkcert
root via certutil.PLAYWRIGHT_FIREFOX_POLICIES_JSON. The script
writes that file; config.playwright.yml sets the env var.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-msg
If 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:
drush or other CLI tools to set up tests.julienloizelet/ddev-playwright) includes KasmVNC to run tests in headed mode or to generate code.If you find this add-on useful, please star it on GitHub — stars show appreciation and help maintainers know their work matters.