Complete Guide: Setting Up Playwright E2E Testing with Local WordPress
Introduction
End-to-end (E2E) testing is crucial for ensuring your WordPress site works correctly from a user’s perspective. In this comprehensive guide, we’ll walk through setting up Playwright, a powerful modern testing framework, with Local (by Flywheel) WordPress development environment. Whether you’re testing a simple blog or a complex BuddyPress community, this guide will get you up and running.
Table of Contents
- Prerequisites
- Why Playwright for WordPress Testing?
- Setting Up Your Environment
- Installing Playwright
- Configuring Playwright for Local WordPress
- Writing Your First Tests
- Advanced Testing Scenarios
- Debugging and Troubleshooting
- Best Practices
- Common Issues and Solutions
Prerequisites {#prerequisites}
Before we begin, ensure you have:
- Local (by Flywheel) installed with at least one WordPress site
- Node.js (version 16 or higher) and npm installed
- Basic knowledge of JavaScript
- A code editor (VS Code recommended)
To check your Node.js version:
node --version # Should output v16.x.x or higher
npm --version # Should output 6.x.x or higher
Why Playwright for WordPress Testing? {#why-playwright}
Playwright offers several advantages for WordPress testing:
- Cross-browser Support: Test on Chromium, Firefox, and WebKit with a single API
- Auto-wait: Automatically waits for elements to be ready before acting
- Powerful Selectors: Multiple ways to locate elements reliably
- Visual Testing: Built-in screenshot and video recording capabilities
- Fast Execution: Runs tests in parallel for quick feedback
- Great Developer Experience: Excellent debugging tools and UI mode
Setting Up Your Environment {#environment-setup}
Step 1: Locate Your Local WordPress Site
Local typically stores sites in these locations:
macOS:
~/Local Sites/your-site-name
Windows:
C:\Users\YourName\Local Sites\your-site-name
Step 2: Find Your Site’s URL
In the Local app, find your site’s URL. It’s usually:
http://yoursite.localhttps://yoursite.local(if SSL is enabled)
Step 3: Navigate to Your Site Directory
Open terminal/command prompt and navigate to your site:
# macOS
cd ~/Local\ Sites/your-site-name/app/public
# Windows
cd "C:\Users\YourName\Local Sites\your-site-name\app\public"
Installing Playwright {#installing-playwright}
Step 1: Create a Testing Directory
mkdir playwright-tests
cd playwright-tests
Step 2: Initialize npm Project
npm init -y
Step 3: Install Playwright
npm install --save-dev @playwright/test
Step 4: Install Playwright Browsers
npx playwright install
This downloads browser binaries for Chromium, Firefox, and WebKit.
Step 5: Verify Installation
Create a package.json with test scripts:
{
"name": "playwright-tests",
"version": "1.0.0",
"scripts": {
"test": "playwright test",
"test:ui": "playwright test --ui",
"test:headed": "playwright test --headed",
"report": "playwright show-report"
},
"devDependencies": {
"@playwright/test": "^1.41.0"
}
}
Configuring Playwright for Local WordPress {#configuration}
Create playwright.config.js in your playwright-tests directory:
const { devices } = require('@playwright/test');
module.exports = {
// Test timeout
timeout: 30000,
// Test retries on failure
retries: 1,
// Reporter configuration
reporter: [
['html'],
['list']
],
use: {
// Your Local WordPress URL
baseURL: 'http://yoursite.local',
// Ignore HTTPS errors for self-signed certificates
ignoreHTTPSErrors: true,
// Collect trace on failure
trace: 'on-first-retry',
// Take screenshot on failure
screenshot: 'only-on-failure',
// Video recording
video: 'retain-on-failure',
},
// Configure projects for different browsers
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
],
};
Handling Local’s SSL Certificates
If your Local site uses HTTPS with self-signed certificates, the ignoreHTTPSErrors: true setting handles this automatically.
Writing Your First Tests {#first-tests}
Basic WordPress Test
Create wordpress-basic.spec.js:
const { test, expect } = require('@playwright/test');
test.describe('WordPress Basic Tests', () => {
test('homepage loads correctly', async ({ page }) => {
// Navigate to homepage
await page.goto('/');
// Check if site title exists
const siteTitle = page.locator('.site-title');
await expect(siteTitle).toBeVisible();
// Take a screenshot
await page.screenshot({ path: 'screenshots/homepage.png' });
});
test('admin login works', async ({ page }) => {
// Go to login page
await page.goto('/wp-login.php');
// Fill in credentials
await page.fill('#user_login', 'your-username');
await page.fill('#user_pass', 'your-password');
// Submit form
await page.click('#wp-submit');
// Verify login successful
await expect(page).toHaveURL(/.*wp-admin.*/);
await expect(page.locator('#wpadminbar')).toBeVisible();
});
test('create a new post', async ({ page }) => {
// Login first
await page.goto('/wp-login.php');
await page.fill('#user_login', 'your-username');
await page.fill('#user_pass', 'your-password');
await page.click('#wp-submit');
// Navigate to new post
await page.goto('/wp-admin/post-new.php');
// Fill in post details
await page.fill('.editor-post-title__input', 'Test Post from Playwright');
// Click into the editor and add content
await page.click('.block-editor-default-block-appender__content');
await page.keyboard.type('This is automated test content.');
// Publish post
await page.click('.editor-post-publish-button__button');
// Confirm publish
const publishButton = page.locator('.editor-post-publish-button');
await publishButton.click();
// Verify post published
await expect(page.locator('.components-snackbar')).toBeVisible();
});
});
Running Your Tests
# Run all tests
npm test
# Run with UI mode (recommended for development)
npm run test:ui
# Run in headed mode (see the browser)
npm run test:headed
# Run specific test file
npm test wordpress-basic.spec.js
Advanced Testing Scenarios {#advanced-testing}
Testing with Page Objects Pattern
Create page-objects/LoginPage.js:
class LoginPage {
constructor(page) {
this.page = page;
this.usernameInput = page.locator('#user_login');
this.passwordInput = page.locator('#user_pass');
this.submitButton = page.locator('#wp-submit');
this.rememberMe = page.locator('#rememberme');
}
async goto() {
await this.page.goto('/wp-login.php');
}
async login(username, password, remember = false) {
await this.usernameInput.fill(username);
await this.passwordInput.fill(password);
if (remember) {
await this.rememberMe.check();
}
await this.submitButton.click();
await this.page.waitForURL('**/wp-admin/**');
}
}
module.exports = { LoginPage };
Using the Page Object:
const { test, expect } = require('@playwright/test');
const { LoginPage } = require('./page-objects/LoginPage');
test('login using page object', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.goto();
await loginPage.login('your-username', 'your-password');
await expect(page.locator('#wpadminbar')).toBeVisible();
});
Testing BuddyPress Features
const { test, expect } = require('@playwright/test');
test.describe('BuddyPress Tests', () => {
test.beforeEach(async ({ page }) => {
// Login before each test
await page.goto('/wp-login.php');
await page.fill('#user_login', 'your-username');
await page.fill('#user_pass', 'your-password');
await page.click('#wp-submit');
});
test('post activity update', async ({ page }) => {
await page.goto('/activity/');
// Post new activity
const activityInput = page.locator('#whats-new');
await activityInput.fill('Testing BuddyPress with Playwright!');
// Submit activity
await page.click('#aw-whats-new-submit');
// Verify activity posted
await expect(page.locator('.activity-content').first()).toContainText('Testing BuddyPress');
});
test('view member profile', async ({ page }) => {
await page.goto('/members/');
// Click first member
await page.click('.members-list li:first-child .list-title a');
// Verify profile page loaded
await expect(page.locator('#item-header')).toBeVisible();
});
});
Testing WooCommerce
test('add product to cart', async ({ page }) => {
await page.goto('/shop/');
// Click first product
await page.click('.products .product:first-child a');
// Add to cart
await page.click('.single_add_to_cart_button');
// Verify added to cart
await expect(page.locator('.woocommerce-message')).toContainText('has been added to your cart');
// Go to cart
await page.click('.cart-contents');
// Verify product in cart
await expect(page.locator('.cart_item')).toBeVisible();
});
Debugging and Troubleshooting {#debugging}
Using Playwright Inspector
# Run with inspector
npx playwright test --debug
# Debug specific test
npx playwright test wordpress-basic.spec.js --debug
Debugging Tips
- Use page.pause() to pause execution:
await page.pause(); // Opens Playwright Inspector
- Take screenshots during tests:
await page.screenshot({ path: 'debug.png', fullPage: true });
- Use console.log for debugging:
const title = await page.title();
console.log('Page title:', title);
- Enable verbose logging:
DEBUG=pw:api npm test
Using Trace Viewer
When a test fails, Playwright creates a trace file:
# View trace
npx playwright show-trace test-results/*/trace.zip
Best Practices {#best-practices}
1. Use Data Attributes for Reliable Selectors
Add data attributes to your WordPress theme:
<button data-test="submit-comment" type="submit">Submit</button>
Then in tests:
await page.click('[data-test="submit-comment"]');
2. Create Reusable Helper Functions
Create helpers/wordpress.js:
async function loginToWordPress(page, username, password) {
await page.goto('/wp-login.php');
await page.fill('#user_login', username);
await page.fill('#user_pass', password);
await page.click('#wp-submit');
await page.waitForURL('**/wp-admin/**');
}
async function createPost(page, title, content) {
await page.goto('/wp-admin/post-new.php');
await page.fill('.editor-post-title__input', title);
await page.click('.block-editor-default-block-appender__content');
await page.keyboard.type(content);
await page.click('.editor-post-publish-button__button');
await page.click('.editor-post-publish-button');
}
module.exports = { loginToWordPress, createPost };
3. Use Environment Variables
Create .env file:
WP_USERNAME=your-username
WP_PASSWORD=your-password
WP_BASE_URL=http://yoursite.local
Install dotenv:
npm install --save-dev dotenv
Use in tests:
require('dotenv').config();
const username = process.env.WP_USERNAME;
const password = process.env.WP_PASSWORD;
4. Organize Tests by Feature
playwright-tests/
├── tests/
│ ├── auth/
│ │ └── login.spec.js
│ ├── content/
│ │ ├── posts.spec.js
│ │ └── pages.spec.js
│ └── buddypress/
│ ├── activity.spec.js
│ └── members.spec.js
├── page-objects/
├── helpers/
└── playwright.config.js
5. Use Fixtures for Common Setup
Create custom fixtures:
const base = require('@playwright/test');
exports.test = base.test.extend({
authenticatedPage: async ({ page }, use) => {
// Login before test
await page.goto('/wp-login.php');
await page.fill('#user_login', 'username');
await page.fill('#user_pass', 'password');
await page.click('#wp-submit');
// Use the authenticated page
await use(page);
// Cleanup after test
await page.goto('/wp-login.php?action=logout');
},
});
Common Issues and Solutions {#common-issues}
Issue 1: Cannot Connect to Local Site
Solution: Add to hosts file if needed:
# macOS/Linux: /etc/hosts
# Windows: C:\Windows\System32\drivers\etc\hosts
127.0.0.1 yoursite.local
::1 yoursite.local
Issue 2: SSL Certificate Errors
Solution: Already handled by ignoreHTTPSErrors: true in config.
Issue 3: Tests Timeout
Solution: Increase timeout in config or specific test:
test('slow test', async ({ page }) => {
test.setTimeout(60000); // 60 seconds
// ... test code
});
Issue 4: Module Not Found Errors
Solution: Clean install:
rm -rf node_modules package-lock.json
npm install
Issue 5: Elements Not Found
Solution: Use better waiting strategies:
// Wait for element to be visible
await page.waitForSelector('.my-element', { state: 'visible' });
// Wait for network to be idle
await page.waitForLoadState('networkidle');
Continuous Integration
GitHub Actions Example
Create .github/workflows/playwright.yml:
name: Playwright Tests
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm ci
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: npm test
- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
Conclusion
You now have a complete Playwright testing setup for your Local WordPress site! This foundation allows you to:
- Test critical user flows automatically
- Catch bugs before they reach production
- Have confidence when making changes
- Save time on manual testing
Start with simple tests and gradually build your test suite. Remember, the goal is not 100% coverage but testing the most important user journeys.
Additional Resources
- Playwright Documentation
- WordPress Testing Best Practices
- Local by Flywheel Documentation
- BuddyPress Developer Documentation
Next Steps
- Write tests for your most critical user flows
- Set up CI/CD pipeline
- Add visual regression testing
- Integrate with your deployment process
- Share this guide with your team!
Happy testing! 🚀
We specialize in web design & development, search engine optimization and web marketing, eCommerce, multimedia solutions, content writing, graphic and logo design. We build web solutions, which evolve with the changing needs of your business.