@gravitywiz/playwright-plugin-gravity-wiz
Version:
Playwright plugin for testing WordPress and Gravity Wiz plugins
470 lines (363 loc) • 12.7 kB
Markdown
# 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
```bash
npm install @gravitywiz/playwright-plugin-gravity-wiz
# or
yarn add @gravitywiz/playwright-plugin-gravity-wiz
```
## Quick Start
### 1. Create Test Setup
First, create the required setup files in your project root:
**global-setup.ts:**
```typescript
import { globalSetup } from '@gravitywiz/playwright-plugin-gravity-wiz';
export default async function () {
return globalSetup();
}
```
**global-teardown.ts:**
```typescript
import { globalTeardown } from '@gravitywiz/playwright-plugin-gravity-wiz';
export default async function () {
return globalTeardown();
}
```
### 2. Configure Playwright
**playwright.config.ts:**
```typescript
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
```typescript
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.
```typescript
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.
```typescript
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.
```typescript
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.
```typescript
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.
```typescript
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.
```typescript
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
```typescript
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('john@example.com');
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:
```typescript
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:
```typescript
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 command
- `wpCli.bootstrap()` - Prepare WordPress for testing
- `wpCli.evalPhp(php)` - Execute PHP code via WP-CLI
- `wpCli.getOption(name)` - Get WordPress option
- `wpCli.setOption(name, value)` - Set WordPress option
### GfCli Methods
- `gfCli.resetGF()` - Reset Gravity Forms database
- `gfCli.getGFVersion()` - Get Gravity Forms version
- `gfCli.isGF25OrNewer()` - Check if GF 2.5+
- `gfCli.getFormID(title)` - Get form ID by title
- `gfCli.importForm(filename, title?)` - Import form
- `gfCli.importEntries(formID, jsonPath)` - Import entries
### WpAuth Methods
- `wpAuth.login(options?)` - Login to WordPress
- `wpAuth.logout()` - Logout from WordPress
### PageHelpers Methods
- `pageHelpers.see(text, selector?)` - Check if text is visible
- `pageHelpers.goToChoicesSettings()` - Navigate to GF field choices
- `pageHelpers.retryUntil(options)` - Retry until condition is met
### FormHelpers Methods
- `formHelpers.importForm(filename, title?)` - Import form
- `formHelpers.importEntries(formID, jsonPath)` - Import entries
### ElementUtils Methods
- `elementUtils.toValuesAndLabels(selector, trim?)` - Extract values/labels
- `elementUtils.matchesOtherInputs(selector, otherSelector)` - Compare elements
- `elementUtils.doesNotMatchOtherInputs(selector, otherSelector)` - Compare (negated)
## Migration from Cypress
The new fixture structure provides better organization:
```typescript
// 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:
```typescript
// 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
```typescript
// 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
```typescript
// 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:**
```bash
# Ensure WP-CLI is installed and accessible
wp --info
```
**Permission Errors:**
```bash
# Fix WordPress file permissions
sudo chown -R www-data:www-data /path/to/wordpress
```
**Plugin 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:
```typescript
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:
```typescript
// 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:
```typescript
test.beforeEach(async ({ wpCli, gfCli }) => {
await wpCli.bootstrap(); // Reset WordPress state
await gfCli.resetGF(); // Reset Gravity Forms
});
```
## Development
```bash
# Install dependencies
yarn install
# Build the plugin
yarn build
# Run in development mode
yarn dev
```
## License
GPL-2.0-or-later