Skip to content

Migrate dev, e2e, and PHPUnit from wp-env to wp-playground-cli#91

Merged
pento merged 12 commits intomainfrom
migrate-to-wp-playground
Apr 17, 2026
Merged

Migrate dev, e2e, and PHPUnit from wp-env to wp-playground-cli#91
pento merged 12 commits intomainfrom
migrate-to-wp-playground

Conversation

@pento
Copy link
Copy Markdown
Owner

@pento pento commented Apr 17, 2026

Summary

  • Drops the Docker dependency end-to-end. npm run dev:wp boots WordPress via @wp-playground/cli, Playwright's globalSetup spawns a Playground instance for e2e, and PHPUnit runs against Playground's SQLite DB.
  • The WordPress PHPUnit test library is fetched on demand into wordpress-plugin/.wp-tests-lib/ (gitignored) by wordpress-plugin/bin/fetch-wp-tests-lib.sh.
  • Removes @wordpress/env devDep, .wp-env.json / .wp-env.test.json, and bin/after-start-*.sh.

Why

The agent sandbox can't run Docker, so wp-env was unusable there. Playground's PHP-WASM + SQLite path works everywhere Node does, and halves e2e wall time in CI.

Notable non-obvious bits

  • PHPUnit skips the test library's install path (WP_TESTS_SKIP_INSTALL=1). Playground provides a fresh DB per boot, and mounts declared with --mount don't propagate to child PHP workers that system() spawns anyway — so the test library's system(install.php) fork couldn't find its mounted tests dir.
  • $table_prefix = 'wp_' (matching Playground's default) so is_blog_installed() passes without a reinstall. Using wptests_ triggered wp_not_installed()wp_redirect() + die().
  • Plugin activation happens through playground/phpunit.blueprint.json, so WP loads the plugin on the normal plugins_loaded path.
  • Coverage driver requires xdebug.mode=coverage, but Playground's --xdebug flag writes its own xdebug.ini with xdebug.mode=debug,develop that wins over php.ini. A blueprint runPHP step rewrites the generated xdebug.ini so PHPUnit produces clover.xml.
  • vendor/ holds tarballs from WordPress/wordpress-playground#3494, referenced via a direct dependency and an overrides entry. The released @wp-playground/cli@3.1.20 returns a pool worker to the free list before its streamed response finishes, so concurrent e2e requests land on a mid-response worker and WordPress returns 500. Revisit once the upstream PR lands.

Test plan

  • npm run typecheck
  • npm run lint
  • npm test — 41 files, 1211 tests
  • npm run test:plugin-php — 131 tests, 279 assertions (≈3.4s)
  • npm run test:e2e — 19 tests pass locally, 3.1m with 4 Playwright workers
  • CI green on push

Drops the Docker dependency end-to-end. `npm run dev:wp` boots WordPress via
@wp-playground/cli, Playwright's globalSetup spawns a Playground instance for
e2e, and PHPUnit runs against Playground's SQLite DB with the WP test library
cloned into `wordpress-plugin/.wp-tests-lib/` on demand.

Why: the agent sandbox can't run Docker, so wp-env was unusable. Playground's
PHP-WASM + SQLite path works everywhere Node does.

Notes:
- PHPUnit skips the test library's install.php fork (`WP_TESTS_SKIP_INSTALL=1`)
  — Playground provides a fresh DB per boot, and mounts declared with --mount
  don't propagate to child PHP workers that system() spawns anyway.
- `$table_prefix` matches Playground's default (`wp_`) so is_blog_installed()
  passes without reinstalling.
- Plugin activation happens through `playground/phpunit.blueprint.json` so WP
  loads it on the normal muplugins_loaded path.
Copilot AI review requested due to automatic review settings April 17, 2026 07:28
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 17, 2026

✅ Coverage Report — plugin-php

Metric Value
Current coverage 99.03% (717/724)
Baseline coverage 99.03% (717/724)
Result PASS

✅ Coverage Report — plugin-typescript

Metric Value
Current coverage 99.89% (919/920)
Baseline coverage 99.89% (896/897)
Result PASS

✅ Coverage Report — typescript

Metric Value
Current coverage 96.06% (2563/2668)
Baseline coverage 96.06% (2563/2668)
Result PASS

The file mirrors wordpress-develop's wp-tests-config-sample.php — the WP-standard
constants (ABSPATH, DB_NAME, etc.) and the `$table_prefix` global override are
intentional. Also silence two warnings whose root cause isn't visible to the
sniffer: putenv(WP_TESTS_SKIP_INSTALL=1) in tests/bootstrap.php, and
$table_prefix being read from wp-tests-config.php via PHPUnit's FileLoader
scope hoisting.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates the repo’s WordPress dev environment, Playwright e2e tests, and plugin PHPUnit tests away from wp-env/Docker to @wp-playground/cli (PHP-WASM + SQLite), enabling Docker-free development and CI.

Changes:

  • Add Playground blueprints + scripts to run dev:wp, e2e global setup, and PHPUnit inside Playground.
  • Replace wp-env-based e2e helpers with Playground-aware helpers (server lifecycle + REST auth via app passwords).
  • Remove @wordpress/env, wp-env configs, and after-start-* scripts; update docs/ignores/CI accordingly.

Reviewed changes

Copilot reviewed 32 out of 38 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
wordpress-plugin/tests/wp-tests-config.php Adds a dedicated wp-tests config for Playground/SQLite runs.
wordpress-plugin/tests/bootstrap.php Skips WP test lib install and relies on Playground blueprint activation.
wordpress-plugin/phpcs.xml.dist Excludes the cloned WP test library directory from PHPCS.
wordpress-plugin/package.json Delegates PHPUnit scripts to repo-root Playground scripts.
wordpress-plugin/bin/fetch-wp-tests-lib.sh Adds on-demand fetch of WP PHPUnit test library into .wp-tests-lib/.
wordpress-plugin/README.md Updates prerequisites/test instructions for Playground (no Docker).
wordpress-plugin/.wp-env.test.json Removes plugin-level wp-env test config.
wordpress-plugin/.distignore Removes wp-env ignores; excludes .wp-tests-lib from distributions.
tests/e2e/test.ts Switches fixtures/utilities to use new Playground helper module.
tests/e2e/pre-publish-panel.spec.ts Updates imports and removes unused editor fixture usage.
tests/e2e/mu-plugins/enable-app-passwords.php Adds MU plugin to force-enable app passwords under Playground/HTTP.
tests/e2e/helpers/wp-env.ts Removes wp-env-based server lifecycle + REST helpers.
tests/e2e/helpers/playground.ts Adds Playground server lifecycle, auth bootstrap, REST helpers, and retries.
tests/e2e/helpers/mcp.ts Switches command listing helper to Playground implementation.
tests/e2e/helpers/editor.ts Simplifies editor navigation helper to no longer depend on WP editor fixture.
tests/e2e/global-teardown.ts Stops Playground instead of tearing down wp-env state.
tests/e2e/global-setup.ts Ensures Playground is running before Playwright auth setup.
tests/e2e/deleted-post.spec.ts Switches REST helpers import to Playground implementation.
tests/e2e/block-sync.spec.ts Updates openEditor usage after helper signature change.
tests/e2e/ai-actions-sidebar.spec.ts Switches REST helpers import and openEditor usage.
playwright.config.ts Updates default base URL to 127.0.0.1.
playground/phpunit.blueprint.json Blueprint to activate the plugin for PHPUnit runs.
playground/e2e.blueprint.json Blueprint for e2e: installs Gutenberg, activates plugin, sets options.
playground/dev.blueprint.json Blueprint for local dev: installs/activates and sets local-only const.
package.json Adds dev:wp and switches plugin PHP test scripts to Playground CLI.
package-lock.json Removes @wordpress/env and adds @wp-playground/cli dependency tree.
eslint.config.mjs Ignores generated coverage + .wp-tests-lib directories.
bin/after-start-e2e.sh Removes wp-env lifecycle script for e2e.
bin/after-start-dev.sh Removes wp-env lifecycle script for dev.
README.md Documents npm run dev:wp in root README.
CLAUDE.md Updates build/test docs to reflect Playground-based workflows.
.wp-env.test.json Removes root wp-env test config.
.wp-env.json Removes root wp-env dev config.
.prettierignore Ignores plugin coverage + .wp-tests-lib.
.markdownlint-cli2.jsonc Ignores plugin coverage + .wp-tests-lib.
.gitignore Ignores .wp-tests-lib/ and .claude/.
.github/workflows/ci.yml Updates PHPUnit job to run Playground-based coverage; tightens e2e timeout.

Comment thread tests/e2e/helpers/playground.ts Outdated
Comment thread tests/e2e/helpers/playground.ts Outdated
Comment thread tests/e2e/helpers/editor.ts Outdated
Comment thread .github/workflows/ci.yml Outdated
Comment thread wordpress-plugin/tests/bootstrap.php Outdated
pento added 2 commits April 17, 2026 17:46
Review feedback:
- tests/e2e/helpers/playground.ts: close the stdio log fd in the parent after
  spawn so it isn't leaked for the lifetime of the test run.
- tests/e2e/helpers/playground.ts: reconcile the multi-worker count comment
  with the actual flag (13, not 8).
- tests/e2e/helpers/editor.ts: drop the stale "disable welcome guide and
  fullscreen mode" claim from openEditor()'s docblock.
- .github/workflows/ci.yml: the e2e job's pretest:e2e runs `composer install`,
  so provision PHP + Composer explicitly like the plugin-php jobs do.
- wordpress-plugin/tests/bootstrap.php: the blueprint-activated plugin loads on
  the regular plugins_loaded sequence, not muplugins_loaded — correct the
  comment.

Coverage:
- Playground's --xdebug flag writes xdebug.ini with xdebug.mode=debug,develop,
  which takes precedence over any php.ini append. Patch the generated
  xdebug.ini to xdebug.mode=coverage via a blueprint runPHP step so PHPUnit's
  coverage driver actually runs and clover.xml gets written. Without this, the
  andstor/clover2lcov-action step fails with "Source file does not exist".
Vendors tarballs of WordPress/wordpress-playground#3494 under vendor/ and
references them via a direct dependency (@wp-playground/cli) and an npm
override (@php-wasm/universal). Without this patch the object-pool proxy
returns a worker to the free list before its streamed response finishes;
concurrent e2e requests then land on a mid-response worker and WordPress
returns 500. Released builds (3.1.20) still have the bug.

Verified: all 19 e2e tests pass locally with 4 Playwright workers (3.1m).

Revisit once the upstream PR lands — drop vendor/ and bump to the next
released version.
Copilot AI review requested due to automatic review settings April 17, 2026 08:21
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 32 out of 40 changed files in this pull request and generated 2 comments.

Comment thread tests/e2e/helpers/playground.ts Outdated
Comment thread tests/e2e/helpers/playground.ts Outdated
pento added 2 commits April 17, 2026 18:28
The flag is a no-op in released @wp-playground/cli builds (the worker count is
hard-coded to 6 in the bundle), so passing it was misleading. Inheriting stdio
instead of redirecting to a temp log file surfaces Playground output directly
in the Playwright console, which is easier to debug than tailing a file after
a failure.
apiFetch: the 5xx retry existed to mask @wp-playground/cli's pool-proxy bug
which is now patched in vendor/. Without that bug, 5xx responses are real
failures and retrying just hides them. Reverted to a single fetch.

stopPlayground: previously deleted the state file unconditionally after
SIGTERM, even if the process was still alive. If termination failed, the
next run saw Playground responding but had no PID to clean it up, leaving
an orphan. Now waits up to 2s for the process to exit and keeps the state
file around if it doesn't, so the next run retries the kill.
Copilot AI review requested due to automatic review settings April 17, 2026 08:33
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 32 out of 40 changed files in this pull request and generated 2 comments.

Comment thread tests/e2e/helpers/playground.ts Outdated
Comment thread tests/e2e/helpers/playground.ts
pento added 2 commits April 17, 2026 18:53
CI is consistently 3-4× slower than local on the browser↔MCP handshake
(browser joins command room → MCP broadcasts awareness → browser emits
open-post signal → MCP opens the post). 30s for waitForMCPReady and 120s
per test were fine locally but 15/19 MCP-dependent tests timed out on
GitHub runners. Bumped to 90s and 180s respectively.
Addresses two PR review points:
- writeState now writes with mode 0o600. The state file holds the shared
  admin application password; restricting perms keeps it out of reach of
  other users on shared CI boxes / dev machines.
- startPlaygroundSubprocess picks wp-playground-cli.cmd on Windows and
  wp-playground-cli elsewhere, and resolves via path.join(REPO_ROOT, …)
  rather than a hard-coded ./node_modules/.bin prefix.
Copilot AI review requested due to automatic review settings April 17, 2026 08:54
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 32 out of 40 changed files in this pull request and generated 2 comments.

Comment thread wordpress-plugin/README.md
Comment thread package.json Outdated
pento added 2 commits April 17, 2026 19:02
- Remove --php / --wp from dev:wp, test:plugin-php[:coverage], and the e2e
  helper. The matching preferredVersions in each blueprint is now the sole
  source of truth; the flags were duplicated configuration that could drift.
- Move WP_TESTS_CONFIG_FILE_PATH from a CLI --define into the phpunit
  blueprint's defineWpConfigConsts step. Kept as the last step so it wins
  the known upstream consts.json write-order race.
- README: note that `npm run test:php` and `npm run test:plugin-php` both
  shell out to wp-playground-cli from the repo root, so contributors need
  to run `npm install` there first.

Only @mount, @mount-before-install, @xdebug, @blueprint, @PORT, and the
positional script still live on the CLI — none of those have a blueprint
equivalent.
Copilot AI review requested due to automatic review settings April 17, 2026 09:31
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 32 out of 40 changed files in this pull request and generated 6 comments.

Comment thread tests/e2e/helpers/editor.ts Outdated
Comment thread playground/phpunit.blueprint.json
Comment thread playground/e2e.blueprint.json
Comment thread playground/dev.blueprint.json
Comment thread tests/e2e/helpers/playground.ts Outdated
Comment thread wordpress-plugin/tests/wp-tests-config.php
pento added 2 commits April 17, 2026 19:40
- ensurePlaygroundRunning now only reuses state.appPassword when we're
  reusing an existing Playground instance. A fresh Playground has a fresh
  SQLite DB, so any cached credential is orphaned and would 401 — the
  bootstrap is cheap enough to just redo.
- editor.ts header: drop the Editor-fixture mention; these helpers take a
  Playwright Page directly now.
- wp-tests-config.php header: the VFS mount layout is defined by the
  repo-root test:plugin-php script (the plugin-local test:php is now a
  delegator), so point readers there.
Splits playwright test runs into 3 deterministic shards via --shard=N/3.
Wall-clock per shard drops from ~18m to ~8.5m; combined with
workers: 1 in CI the deleted-post spec's two slow tests land in separate
shards, so the single-longest-test bound doesn't block the others.
Timeout dropped from 20m to 15m per shard.
Copilot AI review requested due to automatic review settings April 17, 2026 09:49
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 32 out of 40 changed files in this pull request and generated 2 comments.

Comment thread wordpress-plugin/tests/wp-tests-config.php
Comment thread package.json
@pento pento merged commit 87f2f9b into main Apr 17, 2026
11 of 12 checks passed
@pento pento deleted the migrate-to-wp-playground branch April 17, 2026 10:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants