# 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": ["=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', ' { 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": ["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.