@gravitywiz/playwright-plugin-gravity-wiz
v0.1.1
Published
Playwright plugin for testing WordPress and Gravity Wiz plugins
Readme
Playwright Plugin for Gravity Wiz
A Playwright plugin that provides WordPress and Gravity Forms specific testing utilities for Gravity Wiz plugins. The plugin offers focused fixtures for different testing concerns, making tests more modular and maintainable.
Installation
npm install @gravitywiz/playwright-plugin-gravity-wiz
# or
yarn add @gravitywiz/playwright-plugin-gravity-wizQuick Start
1. Create Test Setup
First, create the required setup files in your project root:
global-setup.ts:
import { globalSetup } from '@gravitywiz/playwright-plugin-gravity-wiz';
export default async function () {
return globalSetup();
}global-teardown.ts:
import { globalTeardown } from '@gravitywiz/playwright-plugin-gravity-wiz';
export default async function () {
return globalTeardown();
}2. Configure Playwright
playwright.config.ts:
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
reporter: 'html',
// Global setup and teardown
globalSetup: require.resolve('./global-setup'),
globalTeardown: require.resolve('./global-teardown'),
use: {
baseURL: 'http://localhost',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
});3. Write Your First Test
import { test as base, expect } from '@playwright/test';
import { createTest } from '@gravitywiz/playwright-plugin-gravity-wiz';
const test = createTest(base);
test.describe('My Plugin Tests', () => {
// The createTest function automatically runs wpCli.bootstrap() and gfCli.resetGF() before each test
test('should login to WordPress', async ({ page, wpAuth, pageHelpers }) => {
await wpAuth.login();
await pageHelpers.see('Dashboard');
await expect(page.locator('#wpadminbar')).toBeVisible();
});
});Available Fixtures
The plugin provides focused fixtures for different testing concerns:
wpCli - WordPress CLI Operations
WordPress command-line operations that don't require a browser page.
test('CLI operations', async ({ wpCli }) => {
await wpCli.bootstrap();
await wpCli.evalPhp('echo "Hello World";');
const blogname = await wpCli.getOption('blogname');
await wpCli.setOption('blogname', 'Test Site');
});gfCli - Gravity Forms CLI Operations
Gravity Forms specific command-line operations.
test('GF operations', async ({ gfCli }) => {
await gfCli.resetGF();
const version = await gfCli.getGFVersion();
const isModern = await gfCli.isGF25OrNewer();
await gfCli.importForm('contact-form.json');
const formId = await gfCli.getFormID('Contact Form');
});wpAuth - WordPress Authentication
Handle WordPress login and logout operations.
test('Authentication', async ({ wpAuth }) => {
await wpAuth.login(); // Default: admin/admin
await wpAuth.login({ username: 'editor', password: 'password' });
await wpAuth.logout();
});pageHelpers - Page Interaction Utilities
Browser-based page interaction helpers.
test('Page interactions', async ({ pageHelpers, gfCli }) => {
await pageHelpers.see('Dashboard');
await pageHelpers.see('Welcome', '.welcome-panel');
await pageHelpers.goToChoicesSettings(); // GF-specific navigation
const result = await pageHelpers.retryUntil({
cmd: async () => await someAsyncOperation(),
until: (result) => result.success === true,
delay: 500,
timeout: 10000
});
});formHelpers - Form Import/Export
Handle Gravity Forms import and export operations.
test('Form operations', async ({ formHelpers }) => {
await formHelpers.importForm('contact-form.json');
await formHelpers.importForm('survey.json', 'Customer Survey');
await formHelpers.importEntries(1, 'sample-entries.json');
});elementUtils - Element Comparison Utilities
Extract and compare element values and labels.
test('Element utilities', async ({ page, elementUtils }) => {
await page.goto('/wp-admin/admin.php?page=gf_edit_forms');
const values = await elementUtils.toValuesAndLabels('select option');
const matches = await elementUtils.matchesOtherInputs('.source', '.target');
const differs = await elementUtils.doesNotMatchOtherInputs('.source', '.target');
});Complete Example Test Suite
import { test as base, expect } from '@playwright/test';
import { createTest } from '@gravitywiz/playwright-plugin-gravity-wiz';
const test = createTest(base);
test.describe('Gravity Wiz Plugin Example', () => {
// Automatic setup: wpCli.bootstrap() and gfCli.resetGF() run before each test
test('should login to WordPress admin', async ({ page, wpAuth, pageHelpers }) => {
await wpAuth.login();
await pageHelpers.see('Dashboard');
await pageHelpers.see('Howdy,');
await expect(page.locator('#wpadminbar')).toBeVisible();
});
test('should import and work with forms', async ({ page, gfCli, formHelpers, wpAuth }) => {
await wpAuth.login();
// Import a form
await formHelpers.importForm('contact-form.json');
const formId = await gfCli.getFormID('Contact Form');
// Navigate to the form page
await page.goto('/contact-form');
// Test form functionality
await page.locator('#input_1_1').fill('John Doe');
await page.locator('#input_1_2').fill('[email protected]');
await page.locator('input[type="submit"]').click();
});
test('should check versions and execute commands', async ({ wpCli, gfCli }) => {
const gfVersion = await gfCli.getGFVersion();
expect(gfVersion).toBeTruthy();
const isModern = await gfCli.isGF25OrNewer();
expect(typeof isModern).toBe('boolean');
const result = await wpCli.execa('wp', ['option', 'get', 'blogname']);
expect(result.exitCode).toBe(0);
});
test('should use element utilities', async ({ page, wpAuth, elementUtils }) => {
await wpAuth.login();
await page.goto('/wp-admin/admin.php?page=gf_edit_forms');
const values = await elementUtils.toValuesAndLabels('select option');
expect(Array.isArray(values)).toBe(true);
});
});Using Fixtures in beforeAll
The CLI fixtures (wpCli and gfCli) can be used in beforeAll hooks since they don't require a browser page:
test.describe('Setup-heavy tests', () => {
test.beforeAll(async ({ wpCli, gfCli }) => {
// These work in beforeAll because they don't need a page
await wpCli.bootstrap();
await gfCli.resetGF();
await gfCli.importForm('complex-form.json');
});
test('should work with pre-imported form', async ({ page, wpAuth }) => {
await wpAuth.login();
// Form is already imported from beforeAll
await page.goto('/complex-form');
});
});Manual Setup (Without Auto-Setup)
If you prefer manual control over setup, you can use the fixtures directly without the automatic bootstrap/resetGF:
import { test as base } from '@playwright/test';
import { gravityWizFixture } from '@gravitywiz/playwright-plugin-gravity-wiz';
const test = base.extend(gravityWizFixture(base));
test('manual setup example', async ({ wpCli, gfCli, wpAuth }) => {
// Manual setup - only when you need it
await wpCli.bootstrap();
await gfCli.resetGF();
await wpAuth.login();
// Your test logic here
});Available Methods by Fixture
WpCli Methods
wpCli.execa(command, args)- Execute any commandwpCli.bootstrap()- Prepare WordPress for testingwpCli.evalPhp(php)- Execute PHP code via WP-CLIwpCli.getOption(name)- Get WordPress optionwpCli.setOption(name, value)- Set WordPress option
GfCli Methods
gfCli.resetGF()- Reset Gravity Forms databasegfCli.getGFVersion()- Get Gravity Forms versiongfCli.isGF25OrNewer()- Check if GF 2.5+gfCli.getFormID(title)- Get form ID by titlegfCli.importForm(filename, title?)- Import formgfCli.importEntries(formID, jsonPath)- Import entries
WpAuth Methods
wpAuth.login(options?)- Login to WordPresswpAuth.logout()- Logout from WordPress
PageHelpers Methods
pageHelpers.see(text, selector?)- Check if text is visiblepageHelpers.goToChoicesSettings()- Navigate to GF field choicespageHelpers.retryUntil(options)- Retry until condition is met
FormHelpers Methods
formHelpers.importForm(filename, title?)- Import formformHelpers.importEntries(formID, jsonPath)- Import entries
ElementUtils Methods
elementUtils.toValuesAndLabels(selector, trim?)- Extract values/labelselementUtils.matchesOtherInputs(selector, otherSelector)- Compare elementselementUtils.doesNotMatchOtherInputs(selector, otherSelector)- Compare (negated)
Migration from Cypress
The new fixture structure provides better organization:
// Old Cypress approach
cy.login();
cy.bootstrap();
cy.resetGF();
cy.importForm('contact-form');
cy.see('Dashboard');
// New Playwright approach with focused fixtures
await wpAuth.login();
await wpCli.bootstrap(); // Or automatic via createTest()
await gfCli.resetGF(); // Or automatic via createTest()
await formHelpers.importForm('contact-form');
await pageHelpers.see('Dashboard');Migration from Old Playwright Plugin
If you're upgrading from the previous version with the monolithic gravityWiz fixture:
// Old approach
test('old way', async ({ gravityWiz }) => {
await gravityWiz.login();
await gravityWiz.bootstrap();
await gravityWiz.see('Dashboard');
});
// New approach
test('new way', async ({ wpAuth, pageHelpers }) => {
// bootstrap() runs automatically with createTest()
await wpAuth.login();
await pageHelpers.see('Dashboard');
});Prerequisites
Required Software
- Node.js 18+ and npm/yarn
- WordPress with WP-CLI installed and configured
- Gravity Forms plugin (licensed)
- Gravity Forms CLI plugin (automatically installed by setup)
Environment Setup
The plugin expects a WordPress environment accessible via WP-CLI. Common setups include:
- Local WordPress installation (XAMPP, MAMP, Local by Flywheel)
- Docker-based WordPress environment
- Remote WordPress site accessible via WP-CLI
Configuration
Global Setup Options
// global-setup.ts
import { globalSetup } from '@gravitywiz/playwright-plugin-gravity-wiz';
export default async function () {
return globalSetup({
emailsFolder: './test-emails', // Optional: custom email capture folder
});
}Playwright Configuration
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
globalSetup: require.resolve('./global-setup'),
globalTeardown: require.resolve('./global-teardown'),
use: {
baseURL: 'http://localhost', // Your WordPress URL
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
});Troubleshooting
Common Issues
WP-CLI Not Found:
# Ensure WP-CLI is installed and accessible
wp --infoPermission Errors:
# Fix WordPress file permissions
sudo chown -R www-data:www-data /path/to/wordpressPlugin Activation Fails:
- Ensure the plugin files are in the correct WordPress plugins directory
- Check WordPress error logs for detailed error messages
Tests Timeout:
- Increase Playwright timeout settings
- Check if WordPress is accessible at the configured baseURL
- Verify database connectivity
Debug Mode
Enable debug logging:
test('debug example', async ({ wpCli }) => {
// Your test code here
// Check for errors after test
const log = await wpCli.evalPhp('return file_get_contents(WP_CONTENT_DIR . "/debug.log");');
console.log('Debug log:', log.stdout);
});Performance Optimization
Parallel Testing
Playwright supports parallel test execution:
// playwright.config.ts
export default defineConfig({
workers: process.env.CI ? 1 : undefined, // Adjust based on your setup
fullyParallel: true,
});Test Isolation
Each test gets a fresh browser context, and WordPress state is automatically reset with createTest(). For manual control:
test.beforeEach(async ({ wpCli, gfCli }) => {
await wpCli.bootstrap(); // Reset WordPress state
await gfCli.resetGF(); // Reset Gravity Forms
});Development
# Install dependencies
yarn install
# Build the plugin
yarn build
# Run in development mode
yarn devLicense
GPL-2.0-or-later
