WordPress Testing: A Practical Tutorial
Learn how to test WordPress plugins and themes with PHPUnit, Playground, browser checks, and realistic content—and how to cover supported PHP and WordPress versions.
Test each behavior in the layer where it can fail: use isolated PHPUnit tests for PHP logic, WordPress-backed tests for interactions with core, browser end-to-end (E2E) tests for user workflows, and realistic content plus manual review for theme rendering. You can run PHPUnit against a clean WordPress installation with the official Playground CLI, without setting up a local database. Then add browser checks for the workflows that matter and repeat the suite against the WordPress and PHP versions your project supports.
This tutorial covers plugins and themes. For the current official commands and options, see Running PHPUnit with the Playground CLI (last updated September 30, 2026) and the Playwright and Playground E2E guide.
1. Choose what to test and where
A useful test gives feedback at the layer that owns the behavior. A PHP unit test does not prove a browser workflow works; a manual visual pass does not reliably guard against regressions. Combine layers based on the failures your code can have.
| Test layer | What it checks | Typical setup | What it cannot establish alone |
|---|---|---|---|
| Isolated unit test | A small function or class, without WordPress loaded | PHPUnit and test doubles where needed | Whether the code interacts correctly with WordPress APIs |
| WordPress integration test | Plugin or theme behavior while WordPress is running | A WordPress test environment; Playground can provide a clean one | Whether users can complete a browser workflow |
| Browser E2E test | Visible user journeys: clicks, form entry, navigation, and outcomes | Node.js, Playwright, a browser, and a test site | Every PHP edge case or every visual state |
| Manual theme and content review | Rendering and behavior with varied content, browsers, and devices | A populated WordPress site and a review checklist | Repeatable regression coverage by itself |
The WP-CLI handbook distinguishes tests of isolated code from integration tests that load WordPress to check a plugin’s interaction with core. WordPress’s E2E guide describes checking behavior in the browser. These scopes complement one another; you do not need to write every kind of test for every feature. See Plugin Integration Tests for the distinction.
How do I test a WordPress plugin?
- Identify the behavior and its failure boundary. For a pure formatter or validation rule, start with a unit test. For hooks, options, queries, or other WordPress APIs, add a WordPress-backed test.
- Run the PHP suite against a clean WordPress environment, locally or in CI.
- Add browser E2E coverage for high-value user flows, such as saving settings or submitting a front-end form.
- Test the supported WordPress and PHP versions, plus relevant multisite, permissions, and empty-data cases where the plugin supports them.
How do I test a WordPress theme?
Check PHP behavior where the theme has logic, then exercise templates with varied content and inspect the rendered result. A theme can pass PHP checks and still mishandle long titles, nested comments, unusual image sizes, or mixed HTML. Import the official Theme Unit Test data with the WordPress Importer and walk through the templates. Treat this data as one part of testing, not as proof that every site’s content renders correctly.
2. Run PHPUnit for a plugin or theme with Playground CLI
The Playground CLI starts a clean WordPress installation for each run and mounts your project into it. This route avoids local database setup. The documented workflow assumes PHPUnit is installed with Composer.
Prerequisites
- PHP and Composer available for your project.
- A plugin or theme directory with PHPUnit configuration and tests.
- Node.js and npm/npx available to invoke the Playground CLI.
Install PHPUnit
From the plugin or theme directory, add PHPUnit as a development dependency:
composer require --dev phpunit/phpunit
Commit the resulting Composer manifest and lock file so local and CI installs use the project’s resolved dependency versions. Ensure phpunit.xml.dist points to the test files and bootstraps any project-specific test setup.
Run plugin tests
Replace MY_PLUGIN with the plugin directory name. Run this from the project directory:
npx @wp-playground/cli@latest php --auto-mount -- /wordpress/wp-content/plugins/MY_PLUGIN/vendor/bin/phpunit -c /wordpress/wp-content/plugins/MY_PLUGIN/phpunit.xml.dist
--auto-mount detects a plugin, theme, or current WordPress directory and mounts it under /wordpress/wp-content/. To specify the mapping explicitly, use --mount as documented in the official PHPUnit guide. If your Composer setup places PHPUnit elsewhere, change the executable path to match the project.
Run theme tests
For a theme named MY_THEME, substitute its mount path and PHPUnit executable/config paths:
npx @wp-playground/cli@latest php --auto-mount -- /wordpress/wp-content/themes/MY_THEME/vendor/bin/phpunit -c /wordpress/wp-content/themes/MY_THEME/phpunit.xml.dist
Confirm the paths inside the Playground environment match the mounted project and the files it contains. If auto-detection does not select the intended directory, configure an explicit mount using the CLI’s documented syntax.
Select WordPress and PHP versions
The guide documents --php and --wp flags for selecting runtime versions. For example, append the options before --, which separates Playground CLI arguments from PHPUnit arguments:
npx @wp-playground/cli@latest php --php=8.3 --wp=6.8 --auto-mount -- /wordpress/wp-content/plugins/MY_PLUGIN/vendor/bin/phpunit -c /wordpress/wp-content/plugins/MY_PLUGIN/phpunit.xml.dist
Use version values appropriate to your project’s support policy. As of the guide’s September 30, 2026 update, it reports PHP 7.4 through 8.5 and accepts a WordPress version, latest, nightly, or beta. These ranges and available releases can change; check the current guide before relying on a particular version.
Make the test run repeatable
- Keep tests and PHPUnit configuration in version control.
- Run the same command from a clean checkout to catch hidden local dependencies.
- Use the same PHP dependency lock file in local and CI workflows.
- Pin the CLI package version in a stable automation workflow if you need repeatable tool resolution; update it deliberately and review the official guide for command changes.
- When testing a version matrix, record each PHP and WordPress pair so a failure is attributable to a specific environment.
3. Add browser end-to-end checks with Playwright
E2E tests exercise the site from a user’s perspective: open a page, click a control, enter data, navigate, and assert the visible result. They are useful for workflows where the interaction among PHP, WordPress, JavaScript, and rendered markup matters. They complement PHP tests rather than replacing them.
The official WordPress guide combines Playwright with Playground CLI. It lists Node.js 20 or later and a plugin, theme, or site to test as prerequisites, and demonstrates installing Playwright, the CLI, and Chromium:
npm install --save-dev @playwright/test @wp-playground/cli
npx playwright install chromium
Follow the official E2E guide for its current project setup and runnable test examples. The commands and configuration depend on how the site and browser test are started; do not assume a PHPUnit command launches the E2E server or browser for you.
Choose a small set of valuable journeys
- Plugin admin: change a setting, save it, reload, and verify the stored value appears.
- Front end: submit valid data and verify the success state; submit invalid data and verify useful feedback.
- Theme: navigate between representative templates and verify important content and controls are visible.
- Accessibility-sensitive controls: verify keyboard navigation and visible focus as part of the relevant journey.
Keep browser tests focused on visible outcomes. Use PHP tests for exhaustive input permutations that do not require a browser; reserve E2E coverage for critical paths and regressions at the user interface boundary.
4. Test theme rendering with realistic content
Start with imported Theme Unit Test data, then add cases that match the site and theme’s intended use. The WordPress Theme Handbook calls out long titles, varied image dimensions, nested comments, and mixed HTML among the cases to inspect.
Manual theme checklist
- Enable
WP_DEBUGin a development environment and inspect warnings and notices. - Check the templates used by the theme and walk through the imported test content.
- Review long and short titles, empty content, lists, quotes, nested comments, and differently sized media.
- Validate HTML and CSS, and inspect the browser console for JavaScript errors.
- Check the browsers and devices the project intends to support. The Theme Testing handbook gives Safari, Chrome, Opera, Firefox, and Microsoft Edge as browser examples.
- Remove temporary debug settings and TODO material before release.
WordPress lists Theme Check for checks against Theme Review Guidelines. It also names Debug Bar and Query Monitor for debugging and inspection, Log Deprecated Notices for finding deprecated usage, and Monster Widget for classic-theme widget testing. These are optional aids with different purposes, not mandatory parts of every theme workflow. See the Theme Testing handbook and Testing guidance.
5. Test safely and across supported versions
Use a disposable environment for experiments that may change data or configuration. WordPress Playground runs locally in the browser; its quick-start guide says a site is not uploaded unless you choose an action such as exporting to GitHub. Playground also supports browser storage and ZIP export/import for keeping a test environment. See Start using WordPress Playground in 5 minutes.
For automated compatibility checks, select versions that match the project’s declared support policy. A single passing run only gives evidence for that tested combination. Playground’s test overview describes selecting WordPress and PHP versions, including beta or nightly WordPress releases: Test with WordPress Playground.
| Project support promise | Practical coverage |
|---|---|
| A defined PHP and WordPress range | Test the lowest supported combination and a current supported combination; add intermediate pairs when compatibility changes make them relevant. |
| Early compatibility with upcoming WordPress | Add beta or nightly runs as an early signal, then verify release behavior when the supported version is available. |
| Browser-dependent interface | Run high-value E2E journeys in the browsers the project supports and manually inspect theme rendering on representative devices. |
The specific matrix is a project decision: official tooling makes version selection possible, but it does not decide which versions your project promises to support.
6. Troubleshooting common failures
| Symptom | Likely cause | What to check or fix |
|---|---|---|
| Playground cannot find the PHPUnit executable | The mounted path or Composer vendor path does not match the command. | Check the plugin/theme directory name, mount location, and whether Composer dependencies were installed. Update the path after -- and the config path to the actual mounted files. |
| PHPUnit reports that no tests were found | The test directory or filename pattern is not included in the PHPUnit configuration. | Review phpunit.xml.dist, suite paths, bootstrap, and test naming. Confirm the config file is the one passed with -c. |
| A test passes locally but fails in Playground | It depends on local state, an undeclared file, a service, or a PHP extension/version difference. | Reproduce from a clean checkout, make dependencies explicit, inspect the selected runtime, and avoid relying on local database contents. |
| A test passes in one WordPress release but fails in another | The code may use an API or behavior that differs across the supported range. | Keep the failing version pair in the matrix, inspect the relevant core behavior, and adjust compatibility code or the project’s support declaration. |
| E2E test cannot launch Chromium | The browser installation step was skipped or the environment lacks required browser dependencies. | Run the Playwright browser install command from the official guide and check its environment-specific setup notes. |
| E2E test times out or is flaky | The test waits on a transient delay, an unstable selector, or an external service. | Wait for a meaningful visible state, use stable selectors, isolate external dependencies where practical, and keep each test’s setup deterministic. |
| Theme looks wrong only with imported content | A template or style assumes short text, one image size, shallow comments, or a narrow content shape. | Reproduce with the relevant imported post, inspect the template and responsive styles, and retain that case in the manual review set. |
| Debug output appears in a release build | Temporary debug configuration or TODO work was left enabled. | Remove development-only settings and unfinished markers before release, as the Theme Testing checklist advises. |
7. Performance, reliability, and cost
Isolated unit tests generally give the fastest feedback because they do not boot WordPress or a browser. WordPress-backed tests add environment startup and integration coverage; E2E tests add browser startup and user-journey coverage. Keep the fast checks easy to run during development, and run the broader version and browser coverage in automation at a cadence appropriate to the project.
Playground’s clean run helps avoid stale local database state, while a compatibility matrix catches failures a single runtime cannot reveal. For reliable results, control dependencies and test data, avoid assumptions about test order, and keep external network services out of tests unless the integration itself is what you are checking. These are practical recommendations based on the different environments and scopes described in the official guides.
The documented test stack uses open-source tools and local execution; the reviewed WordPress sources do not establish a service price or a benchmark for test runtime. Your costs are primarily the development and CI resources required to run the chosen layers and matrix. Use the smallest matrix that represents the support promise, then expand it where actual compatibility risks justify the extra runs.
8. Capture screenshots of WordPress pages
For visual review, a screenshot can make a page state easier to inspect or share. You can capture a page yourself with a browser, then inspect the image. For an automated screenshot API, ScreenshotNeo is a website screenshot API and MCP server from ScreenshotNeo; its capture endpoint accepts a URL and returns an image or PDF. It is separate from PHPUnit and E2E testing: a screenshot is useful for visual inspection, while interaction and application behavior still need their appropriate tests.
For screenshots of a public or staging URL, you can call the API with cURL, Python, or Node.js. See the ScreenshotNeo API documentation for request details. Replace the example target URL with the page you want to capture.
cURL
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
Python
import requests
r = requests.get(
"https://api.screenshotneo.com/v1/shot",
params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
Node.js
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(await res.arrayBuffer())));
Or skip the browser setup
ScreenshotNeo accepts cookie banners like a visitor and removes more than 60 known consent platforms, newsletter popups, and chat widgets before the capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers say the page verdict and whether the request was billed. Its MCP server gives AI agents tools to take screenshots, get page information, and capture PDFs.
The free plan includes 1,000 screenshots a month with no card. Paid plans start at $5 for 3,000 screenshots; every feature is on every plan. Sign up for ScreenshotNeo’s free plan.
9. Frequently asked questions
Do I need a local MySQL database to run the Playground PHPUnit command?
No. The documented Playground CLI flow starts a clean WordPress environment for the run and is designed to avoid local database setup.
Can a passing PHPUnit suite prove my theme looks right?
No. PHP tests do not cover every rendered state. Use varied content, browser checks, and a manual visual review for presentation issues.
Should every test run against beta or nightly WordPress?
Only if early compatibility feedback is useful for the project. Treat those runs as signals about upcoming changes; test the versions your project actually supports as well.
Where can I find the current Playground CLI version options?
Check the official PHPUnit guide before using a version range or command copied from an older tutorial; the available versions and details can change.


