UNPKG

@gravitywiz/playwright-plugin-gravity-wiz

Version:

Playwright plugin for testing WordPress and Gravity Wiz plugins

470 lines (363 loc) 12.7 kB
# 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