npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@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-wiz

Quick 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 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:

// 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 --info

Permission Errors:

# 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:

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 dev

License

GPL-2.0-or-later