Drupal & DDEV Procedure
When to Use
Use this guide when running VR against a Drupal site under DDEV.
Decision
| Question | Answer |
|---|---|
| Clear Drupal cache between tests? | Almost never — clears take 5–30 s and torpedo suite runtime |
| When to clear cache? | Once in global.setup.ts before the whole suite (after drush updb); or when the test exercises a cache-rebuild path specifically |
| When to clear before re-running? | After Twig/CSS changes: ddev drush cr once, then re-run — not between tests |
Pattern
Storage-state authentication:
auth.setup.tslogs in via/user/loginand writesplaywright/.auth/admin.jsonviacontext.storageState()- Authenticated projects declare
use: { storageState: 'playwright/.auth/admin.json' } - Anonymous projects omit
storageState .auth/is gitignored — files contain session cookies
DDEV URL + self-signed certs:
// playwright.config.ts
use: {
baseURL: process.env.DDEV_PRIMARY_URL ?? 'https://my-site.ddev.site',
ignoreHTTPSErrors: true,
}
Run inside the DDEV web container:
ddev exec npx playwright test
Common Drupal elements to mask:
const dynamic = [
page.locator('time[datetime]'),
page.locator('.views-row .submitted'),
page.locator('.user--name'),
page.locator('.toolbar-tray .messages'),
page.locator('[data-contextual-id]'),
];
await expect(page).toHaveScreenshot({ mask: dynamic });
Olivero/Claro peculiarities:
- Admin toolbar — wait for '.toolbar-loading' to disappear or hide via stylePath
- CKEditor 5 iframe — mask doesn't pierce iframes; stylePath does (iframe { visibility: hidden; })
- Big Pipe placeholders — always await page.waitForLoadState('networkidle') after goto
Directory layout:
<repo>/
├── composer.json
├── web/
└── tests/playwright/
├── playwright.config.ts
├── screenshot.css
├── auth.setup.ts
├── .auth/ # gitignored
├── e2e/
│ ├── homepage.spec.ts
│ └── homepage.spec.ts-snapshots/ # committed baselines
└── playwright-report/ # gitignored
Common Mistakes
- Wrong: capturing on the host → Right: works locally, fails in CI; capture inside the Docker image always
- Wrong: running
drush crbetween every test → Right: kills suite time - Wrong: forgetting
ignoreHTTPSErrors→ Right: every navigation fails on DDEV TLS - Wrong: committing
.auth/files → Right: leaks session cookies