Some checks are pending
HVAC Plugin CI/CD Pipeline / Security Analysis (push) Waiting to run
HVAC Plugin CI/CD Pipeline / Code Quality & Standards (push) Waiting to run
HVAC Plugin CI/CD Pipeline / Unit Tests (push) Waiting to run
HVAC Plugin CI/CD Pipeline / Integration Tests (push) Waiting to run
HVAC Plugin CI/CD Pipeline / Deploy to Staging (push) Blocked by required conditions
HVAC Plugin CI/CD Pipeline / Deploy to Production (push) Blocked by required conditions
HVAC Plugin CI/CD Pipeline / Notification (push) Blocked by required conditions
Security Monitoring & Compliance / Dependency Vulnerability Scan (push) Waiting to run
Security Monitoring & Compliance / Secrets & Credential Scan (push) Waiting to run
Security Monitoring & Compliance / WordPress Security Analysis (push) Waiting to run
Security Monitoring & Compliance / Static Code Security Analysis (push) Waiting to run
Security Monitoring & Compliance / Security Compliance Validation (push) Waiting to run
Security Monitoring & Compliance / Security Summary Report (push) Blocked by required conditions
Security Monitoring & Compliance / Security Team Notification (push) Blocked by required conditions
- Add 90+ test files including E2E, unit, and integration tests - Implement Page Object Model (POM) architecture - Add Docker testing environment with comprehensive services - Include modernized test framework with error recovery - Add specialized test suites for master trainer and trainer workflows - Update .gitignore to properly track test infrastructure 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
469 lines
No EOL
15 KiB
JavaScript
469 lines
No EOL
15 KiB
JavaScript
/**
|
|
* WordPress Utilities for HVAC Testing Framework
|
|
*
|
|
* Provides WordPress-specific functionality:
|
|
* - WP-CLI integration for database management
|
|
* - Cache clearing and rewrite rule flushing
|
|
* - Test data seeding and cleanup
|
|
* - User management and role assignments
|
|
*
|
|
* @package HVAC_Community_Events
|
|
* @version 2.0.0
|
|
* @created 2025-08-27
|
|
*/
|
|
|
|
const { exec } = require('child_process');
|
|
const { promisify } = require('util');
|
|
const fs = require('fs').promises;
|
|
const path = require('path');
|
|
const ConfigManager = require('../core/ConfigManager');
|
|
|
|
const execAsync = promisify(exec);
|
|
|
|
class WordPressUtils {
|
|
constructor() {
|
|
this.config = ConfigManager;
|
|
this.wpCliPath = this.config.get('wordpress.cliPath', 'wp');
|
|
this.baseUrl = this.config.get('app.baseUrl');
|
|
this.timeout = 30000; // 30 seconds for WP-CLI commands
|
|
}
|
|
|
|
/**
|
|
* Execute WP-CLI command with error handling
|
|
*/
|
|
async executeWpCli(command, options = {}) {
|
|
const fullCommand = `${this.wpCliPath} ${command} --url="${this.baseUrl}" --allow-root`;
|
|
|
|
try {
|
|
console.log(`🔧 WP-CLI: ${command}`);
|
|
const { stdout, stderr } = await execAsync(fullCommand, {
|
|
timeout: options.timeout || this.timeout,
|
|
cwd: options.cwd || process.cwd()
|
|
});
|
|
|
|
if (stderr && !options.ignoreStderr) {
|
|
console.warn(`⚠️ WP-CLI Warning: ${stderr}`);
|
|
}
|
|
|
|
return stdout.trim();
|
|
} catch (error) {
|
|
console.error(`❌ WP-CLI Error (${command}):`, error.message);
|
|
throw new Error(`WP-CLI command failed: ${command} - ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Flush WordPress rewrite rules
|
|
*/
|
|
async flushRewriteRules() {
|
|
try {
|
|
await this.executeWpCli('rewrite flush');
|
|
console.log('✅ Rewrite rules flushed');
|
|
} catch (error) {
|
|
console.warn('Could not flush rewrite rules:', error.message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear WordPress cache (if caching plugin is available)
|
|
*/
|
|
async clearCache() {
|
|
const cacheCommands = [
|
|
'cache flush', // Object cache
|
|
'transient delete --all', // Transients
|
|
'rewrite flush' // Rewrite rules
|
|
];
|
|
|
|
for (const command of cacheCommands) {
|
|
try {
|
|
await this.executeWpCli(command, { ignoreStderr: true });
|
|
} catch (error) {
|
|
// Cache clearing might fail if no cache plugin is installed
|
|
console.log(`Cache command skipped: ${command}`);
|
|
}
|
|
}
|
|
|
|
console.log('🗑️ WordPress cache cleared');
|
|
}
|
|
|
|
/**
|
|
* Create test user with specific role
|
|
*/
|
|
async createTestUser(username, email, role, password = null) {
|
|
// Generate password if not provided
|
|
if (!password) {
|
|
password = `Test${role}123!`;
|
|
}
|
|
|
|
try {
|
|
// Check if user already exists
|
|
const userExists = await this.executeWpCli(`user get ${username}`, { ignoreStderr: true })
|
|
.then(() => true)
|
|
.catch(() => false);
|
|
|
|
if (userExists) {
|
|
console.log(`👤 User already exists: ${username}`);
|
|
|
|
// Update user role if needed
|
|
await this.executeWpCli(`user set-role ${username} ${role}`);
|
|
|
|
return { username, email, password, existed: true };
|
|
}
|
|
|
|
// Create new user
|
|
await this.executeWpCli(`user create ${username} ${email} --role=${role} --user_pass="${password}"`);
|
|
|
|
console.log(`✅ Created test user: ${username} (${role})`);
|
|
return { username, email, password, existed: false };
|
|
|
|
} catch (error) {
|
|
throw new Error(`Failed to create test user ${username}: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete test user
|
|
*/
|
|
async deleteTestUser(username) {
|
|
try {
|
|
await this.executeWpCli(`user delete ${username} --yes`);
|
|
console.log(`🗑️ Deleted test user: ${username}`);
|
|
} catch (error) {
|
|
console.warn(`Could not delete user ${username}:`, error.message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set up test data for HVAC plugin
|
|
*/
|
|
async seedTestData(testId) {
|
|
console.log(`🌱 Seeding test data for: ${testId}`);
|
|
|
|
try {
|
|
// Create test events
|
|
await this.createTestEvents(testId);
|
|
|
|
// Create test venues
|
|
await this.createTestVenues(testId);
|
|
|
|
// Create test organizers
|
|
await this.createTestOrganizers(testId);
|
|
|
|
console.log('✅ Test data seeded successfully');
|
|
} catch (error) {
|
|
console.error('❌ Failed to seed test data:', error.message);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create test events
|
|
*/
|
|
async createTestEvents(testId) {
|
|
const events = [
|
|
{
|
|
title: `Test HVAC Training Event - ${testId}`,
|
|
content: 'Test event for automated testing',
|
|
status: 'publish',
|
|
meta: {
|
|
'_hvac_test_id': testId,
|
|
'_hvac_test_event': '1'
|
|
}
|
|
}
|
|
];
|
|
|
|
for (const event of events) {
|
|
try {
|
|
// Create the event post
|
|
const postCommand = `post create --post_type=tribe_events --post_title="${event.title}" --post_content="${event.content}" --post_status=${event.status} --porcelain`;
|
|
const postId = await this.executeWpCli(postCommand);
|
|
|
|
// Add meta fields
|
|
for (const [key, value] of Object.entries(event.meta)) {
|
|
await this.executeWpCli(`post meta add ${postId} ${key} "${value}"`);
|
|
}
|
|
|
|
console.log(`📅 Created test event: ${event.title} (ID: ${postId})`);
|
|
} catch (error) {
|
|
console.warn(`Could not create test event: ${event.title}`, error.message);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create test venues
|
|
*/
|
|
async createTestVenues(testId) {
|
|
const venues = [
|
|
{
|
|
title: `Test Venue - ${testId}`,
|
|
content: 'Test venue for automated testing',
|
|
meta: {
|
|
'_hvac_test_id': testId,
|
|
'_VenueAddress': '123 Test Street',
|
|
'_VenueCity': 'Test City',
|
|
'_VenueState': 'Test State',
|
|
'_VenueZip': '12345'
|
|
}
|
|
}
|
|
];
|
|
|
|
for (const venue of venues) {
|
|
try {
|
|
const postCommand = `post create --post_type=tribe_venue --post_title="${venue.title}" --post_content="${venue.content}" --post_status=publish --porcelain`;
|
|
const postId = await this.executeWpCli(postCommand);
|
|
|
|
// Add meta fields
|
|
for (const [key, value] of Object.entries(venue.meta)) {
|
|
await this.executeWpCli(`post meta add ${postId} ${key} "${value}"`);
|
|
}
|
|
|
|
console.log(`🏢 Created test venue: ${venue.title} (ID: ${postId})`);
|
|
} catch (error) {
|
|
console.warn(`Could not create test venue: ${venue.title}`, error.message);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create test organizers
|
|
*/
|
|
async createTestOrganizers(testId) {
|
|
const organizers = [
|
|
{
|
|
title: `Test Organizer - ${testId}`,
|
|
content: 'Test organizer for automated testing',
|
|
meta: {
|
|
'_hvac_test_id': testId,
|
|
'_OrganizerPhone': '555-123-4567',
|
|
'_OrganizerEmail': `test-organizer-${testId}@example.com`
|
|
}
|
|
}
|
|
];
|
|
|
|
for (const organizer of organizers) {
|
|
try {
|
|
const postCommand = `post create --post_type=tribe_organizer --post_title="${organizer.title}" --post_content="${organizer.content}" --post_status=publish --porcelain`;
|
|
const postId = await this.executeWpCli(postCommand);
|
|
|
|
// Add meta fields
|
|
for (const [key, value] of Object.entries(organizer.meta)) {
|
|
await this.executeWpCli(`post meta add ${postId} ${key} "${value}"`);
|
|
}
|
|
|
|
console.log(`👤 Created test organizer: ${organizer.title} (ID: ${postId})`);
|
|
} catch (error) {
|
|
console.warn(`Could not create test organizer: ${organizer.title}`, error.message);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clean up test data
|
|
*/
|
|
async cleanupTestData(testId) {
|
|
console.log(`🧹 Cleaning up test data for: ${testId}`);
|
|
|
|
try {
|
|
// Find and delete test posts
|
|
const testPosts = await this.executeWpCli(`post list --meta_key=_hvac_test_id --meta_value="${testId}" --field=ID`);
|
|
|
|
if (testPosts.trim()) {
|
|
const postIds = testPosts.split('\n').filter(id => id.trim());
|
|
|
|
for (const postId of postIds) {
|
|
await this.executeWpCli(`post delete ${postId} --force`);
|
|
}
|
|
|
|
console.log(`🗑️ Deleted ${postIds.length} test posts`);
|
|
}
|
|
|
|
// Clean up orphaned meta
|
|
await this.executeWpCli(`db query "DELETE FROM wp_postmeta WHERE meta_key = '_hvac_test_id' AND meta_value = '${testId}'"`);
|
|
|
|
} catch (error) {
|
|
console.warn('Could not fully clean up test data:', error.message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if plugin is active
|
|
*/
|
|
async isPluginActive(pluginName) {
|
|
try {
|
|
const activePlugins = await this.executeWpCli('plugin list --status=active --field=name');
|
|
return activePlugins.includes(pluginName);
|
|
} catch (error) {
|
|
console.warn(`Could not check plugin status for ${pluginName}:`, error.message);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Activate plugin
|
|
*/
|
|
async activatePlugin(pluginName) {
|
|
try {
|
|
await this.executeWpCli(`plugin activate ${pluginName}`);
|
|
console.log(`✅ Activated plugin: ${pluginName}`);
|
|
} catch (error) {
|
|
throw new Error(`Failed to activate plugin ${pluginName}: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get WordPress version
|
|
*/
|
|
async getWordPressVersion() {
|
|
try {
|
|
const version = await this.executeWpCli('core version');
|
|
return version.trim();
|
|
} catch (error) {
|
|
console.warn('Could not get WordPress version:', error.message);
|
|
return 'unknown';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update database after schema changes
|
|
*/
|
|
async updateDatabase() {
|
|
try {
|
|
await this.executeWpCli('core update-db');
|
|
console.log('✅ Database updated');
|
|
} catch (error) {
|
|
console.warn('Could not update database:', error.message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Import test data from SQL file
|
|
*/
|
|
async importDatabase(sqlFilePath) {
|
|
try {
|
|
const absolutePath = path.resolve(sqlFilePath);
|
|
await this.executeWpCli(`db import "${absolutePath}"`);
|
|
console.log(`✅ Imported database from: ${sqlFilePath}`);
|
|
} catch (error) {
|
|
throw new Error(`Failed to import database: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Export database to SQL file
|
|
*/
|
|
async exportDatabase(outputPath) {
|
|
try {
|
|
const absolutePath = path.resolve(outputPath);
|
|
await this.executeWpCli(`db export "${absolutePath}"`);
|
|
console.log(`✅ Exported database to: ${outputPath}`);
|
|
return absolutePath;
|
|
} catch (error) {
|
|
throw new Error(`Failed to export database: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reset database to clean state
|
|
*/
|
|
async resetDatabase() {
|
|
try {
|
|
await this.executeWpCli('db reset --yes');
|
|
console.log('✅ Database reset to clean state');
|
|
} catch (error) {
|
|
throw new Error(`Failed to reset database: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get site URL
|
|
*/
|
|
async getSiteUrl() {
|
|
try {
|
|
return await this.executeWpCli('option get siteurl');
|
|
} catch (error) {
|
|
console.warn('Could not get site URL:', error.message);
|
|
return this.baseUrl;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set WordPress option
|
|
*/
|
|
async setOption(optionName, optionValue) {
|
|
try {
|
|
await this.executeWpCli(`option update ${optionName} "${optionValue}"`);
|
|
console.log(`✅ Set option: ${optionName} = ${optionValue}`);
|
|
} catch (error) {
|
|
console.warn(`Could not set option ${optionName}:`, error.message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get WordPress option
|
|
*/
|
|
async getOption(optionName) {
|
|
try {
|
|
return await this.executeWpCli(`option get ${optionName}`);
|
|
} catch (error) {
|
|
console.warn(`Could not get option ${optionName}:`, error.message);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Run WordPress cron
|
|
*/
|
|
async runCron() {
|
|
try {
|
|
await this.executeWpCli('cron event run --due-now');
|
|
console.log('✅ WordPress cron executed');
|
|
} catch (error) {
|
|
console.warn('Could not run cron:', error.message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check WordPress environment health
|
|
*/
|
|
async checkHealth() {
|
|
const health = {
|
|
wpVersion: 'unknown',
|
|
pluginsActive: false,
|
|
databaseConnected: false,
|
|
writableUploads: false
|
|
};
|
|
|
|
try {
|
|
// Check WordPress version
|
|
health.wpVersion = await this.getWordPressVersion();
|
|
|
|
// Check if HVAC plugin is active
|
|
health.pluginsActive = await this.isPluginActive('hvac-community-events');
|
|
|
|
// Check database connection
|
|
try {
|
|
await this.executeWpCli('db check');
|
|
health.databaseConnected = true;
|
|
} catch (error) {
|
|
health.databaseConnected = false;
|
|
}
|
|
|
|
// Check uploads directory
|
|
try {
|
|
await this.executeWpCli('eval "wp_upload_dir();"');
|
|
health.writableUploads = true;
|
|
} catch (error) {
|
|
health.writableUploads = false;
|
|
}
|
|
|
|
} catch (error) {
|
|
console.warn('Health check incomplete:', error.message);
|
|
}
|
|
|
|
console.log('🏥 WordPress Health Check:', health);
|
|
return health;
|
|
}
|
|
}
|
|
|
|
module.exports = WordPressUtils; |