964 lines
29 KiB
Markdown
964 lines
29 KiB
Markdown
# PluginCompass External WordPress Testing System
|
|
|
|
## Executive Summary
|
|
|
|
A production-ready testing system that uses an externally hosted WordPress site with WP-CLI to verify plugin functionality. Supports high concurrency (20+ sessions) through multisite subsite isolation, with two testing modes (automated WP-CLI commands and visual browser testing).
|
|
|
|
---
|
|
|
|
## Architecture Overview
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ PluginCompass CLI Users │
|
|
│ (20+ Concurrent Sessions) │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ Test Orchestrator Layer │
|
|
│ - Session Queue Manager (prevents conflicts) │
|
|
│ - Subsite Provisioning (auto-creates test sites) │
|
|
│ - Resource Cleanup (automatic teardown) │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ External WordPress Multisite │
|
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
│ │ Session 1 │ │ Session 2 │ │ Session N │ │
|
|
│ │ Subsite │ │ Subsite │ │ Subsite │ │
|
|
│ │ /test-abc │ │ /test-def │ │ /test-xyz │ │
|
|
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
|
│ │
|
|
│ Shared: Core WP, Plugins, Themes (isolated per subsite) │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Core Components
|
|
|
|
### 1. Test Orchestrator (`test_orchestrator.js`)
|
|
|
|
Central controller managing all test sessions.
|
|
|
|
**Responsibilities:**
|
|
- Queue incoming test requests
|
|
- Provision subsites automatically
|
|
- Manage plugin installations
|
|
- Coordinate cleanup
|
|
- Prevent cross-session contamination
|
|
|
|
**Configuration:**
|
|
```javascript
|
|
const TEST_CONFIG = {
|
|
// External WP Site Connection
|
|
wpHost: process.env.TEST_WP_HOST || 'testsite.example.com',
|
|
wpSshUser: process.env.TEST_WP_SSH_USER || 'wordpress',
|
|
wpSshKey: process.env.TEST_WP_SSH_KEY || '~/.ssh/wp-test-key',
|
|
wpPath: process.env.TEST_WP_PATH || '/var/www/html',
|
|
|
|
// Multisite Settings
|
|
enableMultisite: true,
|
|
subsitePrefix: 'test',
|
|
subsiteDomain: 'testsite.example.com',
|
|
|
|
// Concurrency
|
|
maxConcurrentTests: 20,
|
|
queueTimeout: 300000, // 5 minutes
|
|
testTimeout: 600000, // 10 minutes
|
|
|
|
// Cleanup
|
|
autoCleanup: true,
|
|
cleanupDelay: 3600000, // 1 hour after test completion
|
|
|
|
// Testing Modes
|
|
enableVisualTesting: process.env.ENABLE_VISUAL_TESTING === 'true',
|
|
visualTestBrowser: 'chromium', // chromium, firefox, webkit
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
### 2. New Tool: `test_plugin_external_wp`
|
|
|
|
**Tool Name:** `test_plugin_external_wp`
|
|
|
|
**Description:** Deploys and tests plugin on external WordPress site with full isolation. Automatically provisions subsite, installs dependencies, runs verification tests, and provides detailed results.
|
|
|
|
**Parameters:**
|
|
```json
|
|
{
|
|
"name": "test_plugin_external_wp",
|
|
"parameters": {
|
|
"type": "object",
|
|
"properties": {
|
|
"plugin_path": {
|
|
"type": "string",
|
|
"description": "Local path to generated plugin directory"
|
|
},
|
|
"test_mode": {
|
|
"type": "string",
|
|
"enum": ["cli", "visual", "both"],
|
|
"default": "cli",
|
|
"description": "Testing mode: cli (WP-CLI commands), visual (browser automation), or both"
|
|
},
|
|
"required_plugins": {
|
|
"type": "array",
|
|
"description": "Other plugins that must be installed for this plugin to work",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"plugin_slug": { "type": "string" },
|
|
"version": { "type": "string" },
|
|
"source": {
|
|
"type": "string",
|
|
"enum": ["wordpress.org", "url", "local"],
|
|
"default": "wordpress.org"
|
|
},
|
|
"source_url": { "type": "string" },
|
|
"activate": { "type": "boolean", "default": true }
|
|
},
|
|
"required": ["plugin_slug"]
|
|
}
|
|
},
|
|
"test_scenarios": {
|
|
"type": "array",
|
|
"description": "Specific test scenarios to verify",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"name": { "type": "string" },
|
|
"type": {
|
|
"type": "string",
|
|
"enum": ["endpoint", "admin_page", "ajax", "shortcode", "hook", "visual", "custom"]
|
|
},
|
|
"url": { "type": "string" },
|
|
"selector": { "type": "string" },
|
|
"expected_text": { "type": "string" },
|
|
"wp_cli_command": { "type": "string" },
|
|
"assertions": {
|
|
"type": "object",
|
|
"properties": {
|
|
"status_code": { "type": "number" },
|
|
"contains": { "type": "array", "items": { "type": "string" } },
|
|
"not_contains": { "type": "array", "items": { "type": "string" } },
|
|
"wp_cli_success": { "type": "boolean" }
|
|
}
|
|
}
|
|
},
|
|
"required": ["name", "type"]
|
|
}
|
|
},
|
|
"visual_tests": {
|
|
"type": "array",
|
|
"description": "Visual testing scenarios (only used when test_mode is 'visual' or 'both')",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"name": { "type": "string" },
|
|
"url": { "type": "string" },
|
|
"actions": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"action": {
|
|
"type": "string",
|
|
"enum": ["goto", "click", "fill", "wait", "screenshot", "evaluate"]
|
|
},
|
|
"selector": { "type": "string" },
|
|
"value": { "type": "string" },
|
|
"timeout": { "type": "number" }
|
|
}
|
|
}
|
|
},
|
|
"assertions": {
|
|
"type": "object",
|
|
"properties": {
|
|
"visible": { "type": "array", "items": { "type": "string" } },
|
|
"hidden": { "type": "array", "items": { "type": "string" } },
|
|
"text_contains": { "type": "array", "items": { "type": "string" } },
|
|
"no_console_errors": { "type": "boolean" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"timeout": {
|
|
"type": "number",
|
|
"default": 300,
|
|
"description": "Test timeout in seconds"
|
|
},
|
|
"auto_fix": {
|
|
"type": "boolean",
|
|
"default": true,
|
|
"description": "Automatically retry and fix on test failure"
|
|
},
|
|
"max_fix_attempts": {
|
|
"type": "number",
|
|
"default": 3,
|
|
"description": "Maximum auto-fix attempts before giving up"
|
|
}
|
|
},
|
|
"required": ["plugin_path"]
|
|
}
|
|
}
|
|
```
|
|
|
|
**Return Value:**
|
|
```javascript
|
|
{
|
|
"ok": true,
|
|
"session_id": "sess_abc123",
|
|
"subsite_url": "https://testsite.example.com/test-abc123",
|
|
"test_results": {
|
|
"mode": "both",
|
|
"cli_tests": {
|
|
"passed": 5,
|
|
"failed": 0,
|
|
"results": [
|
|
{
|
|
"name": "Plugin activates without errors",
|
|
"status": "passed",
|
|
"command": "wp plugin activate test-plugin",
|
|
"output": "Success: Activated 1 of 1 plugins.",
|
|
"duration": 2340
|
|
},
|
|
{
|
|
"name": "Custom login endpoint responds",
|
|
"status": "passed",
|
|
"command": "wp eval 'echo wp_remote_retrieve_body(wp_remote_get(home_url(\"/custom-login\")));'",
|
|
"assertions": {
|
|
"contains": ["<form", "login"],
|
|
"status_code": 200
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"visual_tests": {
|
|
"passed": 3,
|
|
"failed": 0,
|
|
"screenshots": [
|
|
{
|
|
"name": "login-page",
|
|
"path": "/results/sess_abc123/login-page.png",
|
|
"url": "https://testsite.example.com/test-abc123/custom-login"
|
|
}
|
|
]
|
|
}
|
|
},
|
|
"installed_plugins": [
|
|
{ "slug": "woocommerce", "version": "8.0.0", "status": "active" },
|
|
{ "slug": "test-plugin", "version": "1.0.0", "status": "active" }
|
|
],
|
|
"errors": [],
|
|
"warnings": [],
|
|
"duration": 45230,
|
|
"cleanup_scheduled": "2024-01-15T10:30:00Z"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Testing Modes
|
|
|
|
### Mode 1: WP-CLI Automated Testing
|
|
|
|
**Use Case:** Fast, deterministic testing without browser overhead
|
|
|
|
**How it works:**
|
|
1. Deploy plugin to subsite
|
|
2. Run WP-CLI commands to verify functionality
|
|
3. Check HTTP endpoints via `wp eval` with `wp_remote_get()`
|
|
4. Verify database state changes
|
|
5. Check error logs
|
|
|
|
**Example Test Scenarios:**
|
|
```javascript
|
|
[
|
|
{
|
|
"name": "Plugin activates cleanly",
|
|
"type": "custom",
|
|
"wp_cli_command": "wp plugin activate {plugin_slug} --skip-plugins",
|
|
"assertions": {
|
|
"wp_cli_success": true,
|
|
"not_contains": ["Fatal error", "Parse error", "Warning"]
|
|
}
|
|
},
|
|
{
|
|
"name": "Custom endpoint accessible",
|
|
"type": "endpoint",
|
|
"url": "/custom-login",
|
|
"wp_cli_command": "wp eval 'echo wp_remote_retrieve_response_code(wp_remote_get(home_url(\"/custom-login\")));'",
|
|
"assertions": {
|
|
"status_code": 200,
|
|
"contains": ["<form", "name=\"log\""]
|
|
}
|
|
},
|
|
{
|
|
"name": "Rewrite rules flushed",
|
|
"type": "custom",
|
|
"wp_cli_command": "wp rewrite list --match=/custom-login --format=json",
|
|
"assertions": {
|
|
"wp_cli_success": true,
|
|
"contains": ["custom-login"]
|
|
}
|
|
},
|
|
{
|
|
"name": "No PHP errors in logs",
|
|
"type": "custom",
|
|
"wp_cli_command": "tail -n 50 /var/log/wp-errors.log | grep -i 'test-plugin' || echo 'No errors found'",
|
|
"assertions": {
|
|
"not_contains": ["Fatal error", "Parse error", "test-plugin"]
|
|
}
|
|
}
|
|
]
|
|
```
|
|
|
|
**Benefits:**
|
|
- Fast (5-30 seconds per test)
|
|
- No browser dependencies
|
|
- Perfect for API/endpoint testing
|
|
- Can check database state directly
|
|
- Scales to 100+ concurrent tests
|
|
|
|
---
|
|
|
|
### Mode 2: Visual Browser Testing
|
|
|
|
**Use Case:** UI verification, JavaScript functionality, styling checks
|
|
|
|
**How it works:**
|
|
1. Deploy plugin to subsite
|
|
2. Launch headless browser (Playwright)
|
|
3. Navigate to specified URLs
|
|
4. Perform user interactions (click, type, submit)
|
|
5. Capture screenshots
|
|
6. Verify visual elements and JavaScript execution
|
|
|
|
**Example Visual Tests:**
|
|
```javascript
|
|
[
|
|
{
|
|
"name": "Login form renders correctly",
|
|
"url": "/custom-login",
|
|
"actions": [
|
|
{ "action": "goto", "url": "/custom-login" },
|
|
{ "action": "screenshot", "name": "initial-load" },
|
|
{ "action": "wait", "selector": "form" }
|
|
],
|
|
"assertions": {
|
|
"visible": ["input[name='log']", "input[name='pwd']", ".submit-button"],
|
|
"no_console_errors": true
|
|
}
|
|
},
|
|
{
|
|
"name": "Add to cart button works",
|
|
"url": "/shop",
|
|
"actions": [
|
|
{ "action": "goto", "url": "/shop" },
|
|
{ "action": "click", "selector": "[data-product_id='123']" },
|
|
{ "action": "wait", "timeout": 2000 },
|
|
{ "action": "screenshot", "name": "after-click" }
|
|
],
|
|
"assertions": {
|
|
"visible": [".cart-count"],
|
|
"text_contains": ["1 item"],
|
|
"no_console_errors": true
|
|
}
|
|
},
|
|
{
|
|
"name": "Admin settings page loads",
|
|
"url": "/wp-admin/admin.php?page=my-plugin",
|
|
"actions": [
|
|
{
|
|
"action": "evaluate",
|
|
"value": "document.querySelector('#user_login').value = 'admin'; document.querySelector('#user_pass').value = 'password'; document.querySelector('#wp-submit').click();"
|
|
},
|
|
{ "action": "wait", "url": "/wp-admin/admin.php?page=my-plugin" },
|
|
{ "action": "screenshot", "name": "admin-page" }
|
|
],
|
|
"assertions": {
|
|
"visible": [".wrap h1", "form"],
|
|
"no_console_errors": true
|
|
}
|
|
}
|
|
]
|
|
```
|
|
|
|
**Benefits:**
|
|
- Catches visual/styling issues
|
|
- Verifies JavaScript execution
|
|
- Tests actual user workflows
|
|
- Screenshots provide proof
|
|
- Finds timing/race condition issues
|
|
|
|
---
|
|
|
|
## Session Isolation Strategy
|
|
|
|
### High Concurrency Solution: Multisite Subsites
|
|
|
|
**Why Multisite:**
|
|
- Each session gets completely isolated WordPress instance
|
|
- Shared core (efficient) but isolated content/options
|
|
- Can run 20+ tests simultaneously without conflicts
|
|
- Automatic cleanup by deleting subsite
|
|
|
|
**Setup Requirements:**
|
|
1. Convert hosted WP to multisite (one-time)
|
|
2. Enable subdomain or subdirectory mode
|
|
3. Configure wildcard DNS or subdirectory rewrite rules
|
|
|
|
**Subsite Provisioning:**
|
|
```javascript
|
|
class SubsiteProvisioner {
|
|
async createTestSubsite(sessionId) {
|
|
const slug = `test-${sessionId.substring(0, 8)}`;
|
|
const title = `Test Environment ${sessionId}`;
|
|
const adminEmail = 'test@example.com';
|
|
|
|
// Create subsite via WP-CLI
|
|
await this.runWpCli(`
|
|
wp site create
|
|
--slug=${slug}
|
|
--title="${title}"
|
|
--email=${adminEmail}
|
|
`);
|
|
|
|
// Configure subsite
|
|
await this.runWpCli(`
|
|
wp site switch --url=https://${this.config.subsiteDomain}/${slug}
|
|
wp option update blogname "Test Site"
|
|
wp option update permalink_structure "/%postname%/"
|
|
wp rewrite flush
|
|
`);
|
|
|
|
return {
|
|
slug,
|
|
url: `https://${this.config.subsiteDomain}/${slug}`,
|
|
adminUrl: `https://${this.config.subsiteDomain}/${slug}/wp-admin`
|
|
};
|
|
}
|
|
|
|
async deleteTestSubsite(slug) {
|
|
await this.runWpCli(`wp site delete --slug=${slug} --yes`);
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Dependency Management
|
|
|
|
### Installing Required Plugins
|
|
|
|
The AI can specify dependencies that must be present:
|
|
|
|
```javascript
|
|
{
|
|
"required_plugins": [
|
|
{
|
|
"plugin_slug": "woocommerce",
|
|
"version": ">=8.0",
|
|
"source": "wordpress.org",
|
|
"activate": true
|
|
},
|
|
{
|
|
"plugin_slug": "advanced-custom-fields",
|
|
"version": "6.2.0",
|
|
"source": "wordpress.org",
|
|
"activate": true
|
|
},
|
|
{
|
|
"plugin_slug": "custom-premium-plugin",
|
|
"source": "url",
|
|
"source_url": "https://example.com/plugins/custom.zip",
|
|
"activate": true
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Installation Process:**
|
|
```javascript
|
|
class PluginInstaller {
|
|
async installPlugin(subsiteUrl, pluginSpec) {
|
|
const { plugin_slug, source, source_url, activate } = pluginSpec;
|
|
|
|
switch (source) {
|
|
case 'wordpress.org':
|
|
await this.runWpCli(`
|
|
wp --url=${subsiteUrl} plugin install ${plugin_slug} --activate
|
|
`);
|
|
break;
|
|
|
|
case 'url':
|
|
// Download and install from URL
|
|
await this.runWpCli(`
|
|
wp --url=${subsiteUrl} plugin install ${source_url} --activate
|
|
`);
|
|
break;
|
|
|
|
case 'local':
|
|
// Copy from local path to subsite
|
|
const targetPath = `${this.config.wpPath}/wp-content/plugins/${plugin_slug}`;
|
|
await this.ssh.copyFile(source_url, targetPath);
|
|
if (activate) {
|
|
await this.runWpCli(`
|
|
wp --url=${subsiteUrl} plugin activate ${plugin_slug}
|
|
`);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Queue Management for High Concurrency
|
|
|
|
### Session Queue System
|
|
|
|
**Challenge:** Even with multisite, some operations (like subsite creation) can have race conditions.
|
|
|
|
**Solution:** Queue system with parallel execution lanes
|
|
|
|
```javascript
|
|
class TestQueue {
|
|
constructor(maxConcurrent = 20) {
|
|
this.maxConcurrent = maxConcurrent;
|
|
this.activeSessions = new Map();
|
|
this.pendingQueue = [];
|
|
this.lanes = new Array(maxConcurrent).fill(null); // Execution lanes
|
|
}
|
|
|
|
async enqueue(testRequest) {
|
|
const sessionId = this.generateSessionId();
|
|
|
|
// Find available lane
|
|
const laneIndex = this.findAvailableLane();
|
|
|
|
if (laneIndex === -1) {
|
|
// All lanes busy, add to pending
|
|
return new Promise((resolve) => {
|
|
this.pendingQueue.push({
|
|
sessionId,
|
|
request: testRequest,
|
|
resolve,
|
|
enqueuedAt: Date.now()
|
|
});
|
|
});
|
|
}
|
|
|
|
// Execute immediately in available lane
|
|
return this.executeInLane(laneIndex, sessionId, testRequest);
|
|
}
|
|
|
|
async executeInLane(laneIndex, sessionId, request) {
|
|
this.lanes[laneIndex] = sessionId;
|
|
|
|
try {
|
|
const result = await this.runTest(sessionId, request);
|
|
return result;
|
|
} finally {
|
|
this.lanes[laneIndex] = null;
|
|
this.processQueue();
|
|
}
|
|
}
|
|
|
|
processQueue() {
|
|
if (this.pendingQueue.length === 0) return;
|
|
|
|
const laneIndex = this.findAvailableLane();
|
|
if (laneIndex === -1) return;
|
|
|
|
const next = this.pendingQueue.shift();
|
|
|
|
// Check for timeout
|
|
if (Date.now() - next.enqueuedAt > TEST_CONFIG.queueTimeout) {
|
|
next.resolve({
|
|
ok: false,
|
|
error: 'Test queue timeout - too many concurrent tests'
|
|
});
|
|
this.processQueue();
|
|
return;
|
|
}
|
|
|
|
this.executeInLane(laneIndex, next.sessionId, next.request)
|
|
.then(next.resolve)
|
|
.catch(error => next.resolve({ ok: false, error: error.message }));
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Complete Workflow
|
|
|
|
### Step-by-Step Process
|
|
|
|
```
|
|
User Request
|
|
↓
|
|
AI Generates Plugin Code
|
|
↓
|
|
AI Calls test_plugin_external_wp
|
|
↓
|
|
┌─────────────────────────────────────┐
|
|
│ 1. QUEUE & PREPARE │
|
|
│ - Add to test queue │
|
|
│ - Wait for available lane │
|
|
│ - Generate session ID │
|
|
└─────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────┐
|
|
│ 2. PROVISION SUBSITE │
|
|
│ - Create multisite subsite │
|
|
│ - Configure permalinks │
|
|
│ - Set up test database tables │
|
|
│ Duration: 3-5 seconds │
|
|
└─────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────┐
|
|
│ 3. INSTALL DEPENDENCIES │
|
|
│ - Install WordPress (if needed) │
|
|
│ - Install WooCommerce │
|
|
│ - Install other required plugins │
|
|
│ - Activate all │
|
|
│ Duration: 10-30 seconds │
|
|
└─────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────┐
|
|
│ 4. DEPLOY TEST PLUGIN │
|
|
│ - Copy plugin files via SFTP │
|
|
│ - Activate plugin │
|
|
│ - Check for activation errors │
|
|
│ Duration: 2-5 seconds │
|
|
└─────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────┐
|
|
│ 5. RUN TESTS │
|
|
│ CLI Mode: │
|
|
│ - WP-CLI verification commands │
|
|
│ - HTTP endpoint checks │
|
|
│ - Database state validation │
|
|
│ - Error log scanning │
|
|
│ │
|
|
│ Visual Mode (if enabled): │
|
|
│ - Launch headless browser │
|
|
│ - Navigate to test URLs │
|
|
│ - Execute user interactions │
|
|
│ - Capture screenshots │
|
|
│ - Check JavaScript console │
|
|
│ Duration: 10-60 seconds │
|
|
└─────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────┐
|
|
│ 6. EVALUATE & AUTO-FIX (if needed) │
|
|
│ IF tests failed AND auto_fix=true:│
|
|
│ - Analyze failure patterns │
|
|
│ - Generate fix suggestions │
|
|
│ - Modify plugin code │
|
|
│ - Re-deploy and re-test │
|
|
│ - Max 3 attempts │
|
|
└─────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────┐
|
|
│ 7. RETURN RESULTS │
|
|
│ - Compile test results │
|
|
│ - Include screenshots (visual) │
|
|
│ - Provide fix recommendations │
|
|
│ - Schedule cleanup │
|
|
└─────────────────────────────────────┘
|
|
↓
|
|
AI Receives Results
|
|
↓
|
|
IF passed → Complete task
|
|
IF failed → Fix issues and re-call tool
|
|
↓
|
|
┌─────────────────────────────────────┐
|
|
│ 8. CLEANUP (async, after delay) │
|
|
│ - Delete subsite │
|
|
│ - Remove plugin files │
|
|
│ - Clear test data │
|
|
│ - Free up lane │
|
|
└─────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Error Handling & Auto-Fix
|
|
|
|
### Common Failures & Fixes
|
|
|
|
```javascript
|
|
const AUTO_FIX_PATTERNS = [
|
|
{
|
|
pattern: /Rewrite rules not working/i,
|
|
check: async (subsite) => {
|
|
const rules = await runWpCli(`wp --url=${subsite} rewrite list`);
|
|
return !rules.includes('custom-login');
|
|
},
|
|
fix: async (pluginPath) => {
|
|
// Add flush_rewrite_rules() to activation hook
|
|
await editFile(pluginPath + '/includes/activation.php',
|
|
'function activate_plugin() {',
|
|
'function activate_plugin() {\n flush_rewrite_rules();'
|
|
);
|
|
}
|
|
},
|
|
{
|
|
pattern: /Undefined function.*wc_/i,
|
|
check: async (subsite) => {
|
|
const logs = await runWpCli(`tail -n 20 /var/log/wp-errors.log`);
|
|
return logs.includes('Call to undefined function wc_');
|
|
},
|
|
fix: async (pluginPath) => {
|
|
// Add WooCommerce dependency check
|
|
await editFile(pluginPath + '/main.php',
|
|
'<?php',
|
|
'<?php\n// Check WooCommerce is active\nif (!in_array(\'woocommerce/woocommerce.php\', apply_filters(\'active_plugins\', get_option(\'active_plugins\')))) {\n return;\n}'
|
|
);
|
|
}
|
|
},
|
|
{
|
|
pattern: /CSS not loading/i,
|
|
check: async (subsite) => {
|
|
const html = await runWpCli(`wp --url=${subsite} eval 'echo wp_remote_retrieve_body(wp_remote_get(home_url("/custom-login")));'`);
|
|
return !html.includes('custom-login.css');
|
|
},
|
|
fix: async (pluginPath) => {
|
|
// Ensure CSS is enqueued
|
|
await editFile(pluginPath + '/includes/enqueue.php',
|
|
'',
|
|
'wp_enqueue_style(\'custom-login-css\', plugins_url(\'css/custom-login.css\', __FILE__));'
|
|
);
|
|
}
|
|
}
|
|
];
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration & Environment Variables
|
|
|
|
### Required Environment Variables
|
|
|
|
```bash
|
|
# WordPress Test Site Connection
|
|
TEST_WP_HOST=testsite.example.com
|
|
TEST_WP_SSH_USER=wordpress
|
|
TEST_WP_SSH_KEY_PATH=/path/to/ssh/key
|
|
TEST_WP_PATH=/var/www/html
|
|
|
|
# Multisite Configuration
|
|
TEST_WP_MULTISITE=true
|
|
TEST_WP_SUBSITE_DOMAIN=testsite.example.com
|
|
|
|
# Testing Configuration
|
|
TEST_ENABLE_VISUAL=true
|
|
TEST_VISUAL_BROWSER=chromium
|
|
TEST_MAX_CONCURRENT=20
|
|
TEST_TIMEOUT=300
|
|
TEST_AUTO_CLEANUP=true
|
|
TEST_CLEANUP_DELAY=3600
|
|
|
|
# Optional: Browser Testing (for visual mode)
|
|
TEST_BROWSER_HEADLESS=true
|
|
TEST_BROWSER_TIMEOUT=30000
|
|
TEST_SCREENSHOT_PATH=/var/results/screenshots
|
|
```
|
|
|
|
---
|
|
|
|
## Implementation Phases
|
|
|
|
### Phase 1: Core Infrastructure (Week 1)
|
|
- [ ] Set up multisite WordPress
|
|
- [ ] Implement SSH/SFTP connection layer
|
|
- [ ] Create `test_plugin_external_wp` tool
|
|
- [ ] Build subsite provisioning system
|
|
- [ ] Basic CLI test mode
|
|
|
|
### Phase 2: Testing Modes (Week 2)
|
|
- [ ] Implement CLI test scenarios
|
|
- [ ] Add visual testing with Playwright
|
|
- [ ] Create queue management system
|
|
- [ ] Build dependency installer
|
|
|
|
### Phase 3: Auto-Fix & Polish (Week 3)
|
|
- [ ] Implement auto-fix patterns
|
|
- [ ] Add retry logic
|
|
- [ ] Error classification
|
|
- [ ] Result formatting for AI
|
|
|
|
### Phase 4: Production Ready (Week 4)
|
|
- [ ] Concurrent session testing
|
|
- [ ] Performance optimization
|
|
- [ ] Documentation
|
|
- [ ] Monitoring & alerting
|
|
|
|
---
|
|
|
|
## Example Usage in AI Workflow
|
|
|
|
### Example 1: Custom Login Plugin
|
|
|
|
**User:** "Create a plugin that adds a custom login page at /vendor-login"
|
|
|
|
**AI Actions:**
|
|
1. Generates plugin code
|
|
2. Calls `test_plugin_external_wp`:
|
|
|
|
```javascript
|
|
{
|
|
"plugin_path": "./vendor-login-plugin",
|
|
"test_mode": "both",
|
|
"required_plugins": [],
|
|
"test_scenarios": [
|
|
{
|
|
"name": "Endpoint accessible",
|
|
"type": "endpoint",
|
|
"url": "/vendor-login",
|
|
"assertions": {
|
|
"status_code": 200,
|
|
"contains": ["<form", "login"]
|
|
}
|
|
},
|
|
{
|
|
"name": "Rewrite rule exists",
|
|
"type": "custom",
|
|
"wp_cli_command": "wp rewrite list --match=/vendor-login",
|
|
"assertions": {
|
|
"contains": ["vendor-login"]
|
|
}
|
|
}
|
|
],
|
|
"visual_tests": [
|
|
{
|
|
"name": "Login form renders",
|
|
"url": "/vendor-login",
|
|
"actions": [
|
|
{ "action": "goto", "url": "/vendor-login" },
|
|
{ "action": "screenshot", "name": "login-page" }
|
|
],
|
|
"assertions": {
|
|
"visible": ["input[name='log']", "input[type='submit']"]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Result:**
|
|
- Subsite created: `https://testsite.example.com/test-a3f7d2`
|
|
- Plugin installed and activated
|
|
- Tests run (5 CLI, 3 visual)
|
|
- Screenshot: `login-page.png` showing working form
|
|
- AI confirms: "Plugin tested and verified - custom login page working"
|
|
|
|
---
|
|
|
|
### Example 2: WooCommerce Payment Gateway
|
|
|
|
**User:** "Create a WooCommerce payment gateway"
|
|
|
|
**AI Actions:**
|
|
```javascript
|
|
{
|
|
"plugin_path": "./custom-gateway",
|
|
"test_mode": "both",
|
|
"required_plugins": [
|
|
{ "plugin_slug": "woocommerce", "activate": true }
|
|
],
|
|
"test_scenarios": [
|
|
{
|
|
"name": "Gateway registered",
|
|
"type": "custom",
|
|
"wp_cli_command": "wp eval 'var_dump(array_keys(WC()->payment_gateways->payment_gateways()));'",
|
|
"assertions": {
|
|
"contains": ["custom_gateway"]
|
|
}
|
|
},
|
|
{
|
|
"name": "Checkout loads without errors",
|
|
"type": "endpoint",
|
|
"url": "/checkout",
|
|
"assertions": {
|
|
"status_code": 200,
|
|
"not_contains": ["Fatal error", "Warning"]
|
|
}
|
|
}
|
|
],
|
|
"visual_tests": [
|
|
{
|
|
"name": "Gateway appears in checkout",
|
|
"url": "/checkout",
|
|
"actions": [
|
|
{ "action": "goto", "url": "/product/test-product" },
|
|
{ "action": "click", "selector": ".add_to_cart_button" },
|
|
{ "action": "wait", "timeout": 2000 },
|
|
{ "action": "goto", "url": "/checkout" },
|
|
{ "action": "screenshot", "name": "checkout-gateway" }
|
|
],
|
|
"assertions": {
|
|
"visible": ["#payment_method_custom_gateway"],
|
|
"no_console_errors": true
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Monitoring & Maintenance
|
|
|
|
### Health Checks
|
|
|
|
```javascript
|
|
// Periodic health check
|
|
async function healthCheck() {
|
|
const checks = {
|
|
ssh: await checkSshConnection(),
|
|
wp_cli: await checkWpCli(),
|
|
multisite: await checkMultisiteEnabled(),
|
|
disk_space: await checkDiskSpace(),
|
|
queue_length: testQueue.pendingQueue.length
|
|
};
|
|
|
|
if (Object.values(checks).some(c => !c.ok)) {
|
|
await alertAdmin(checks);
|
|
}
|
|
}
|
|
```
|
|
|
|
### Metrics to Track
|
|
- Test queue length and wait times
|
|
- Average test duration per mode
|
|
- Failure rate by plugin type
|
|
- Auto-fix success rate
|
|
- Resource usage (disk, memory)
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
This system provides:
|
|
|
|
1. **Full Isolation:** Each test runs in its own multisite subsite
|
|
2. **High Concurrency:** Queue system handles 20+ simultaneous tests
|
|
3. **Two Testing Modes:**
|
|
- CLI mode: Fast, deterministic WP-CLI testing
|
|
- Visual mode: Real browser automation with screenshots
|
|
4. **Automatic Setup:** Provisions subsite, installs dependencies, deploys plugin
|
|
5. **Auto-Fix:** Attempts to fix common failures automatically
|
|
6. **Proof of Work:** Returns screenshots, logs, and detailed test results
|
|
7. **Cleanup:** Automatic teardown after test completion
|
|
|
|
**Result:** Users receive plugins that are proven to work on a real WordPress environment, with objective evidence of functionality.
|