## Major Enhancements ### 🏗️ Architecture & Infrastructure - Implement comprehensive Docker testing infrastructure with hermetic environment - Add Forgejo Actions CI/CD pipeline for automated deployments - Create Page Object Model (POM) testing architecture reducing test duplication by 90% - Establish security-first development patterns with input validation and output escaping ### 🧪 Testing Framework Modernization - Migrate 146+ tests from 80 duplicate files to centralized architecture - Add comprehensive E2E test suites for all user roles and workflows - Implement WordPress error detection with automatic site health monitoring - Create robust browser lifecycle management with proper cleanup ### 📚 Documentation & Guides - Add comprehensive development best practices guide - Create detailed administrator setup documentation - Establish user guides for trainers and master trainers - Document security incident reports and migration guides ### 🔧 Core Plugin Features - Enhance trainer profile management with certification system - Improve find trainer functionality with advanced filtering - Strengthen master trainer area with content management - Add comprehensive venue and organizer management ### 🛡️ Security & Reliability - Implement security-first patterns throughout codebase - Add comprehensive input validation and output escaping - Create secure credential management system - Establish proper WordPress role-based access control ### 🎯 WordPress Integration - Strengthen singleton pattern implementation across all classes - Enhance template hierarchy with proper WordPress integration - Improve page manager with hierarchical URL structure - Add comprehensive shortcode and menu system ### 🔍 Developer Experience - Add extensive debugging and troubleshooting tools - Create comprehensive test data seeding scripts - Implement proper error handling and logging - Establish consistent code patterns and standards ### 📊 Performance & Optimization - Optimize database queries and caching strategies - Improve asset loading and script management - Enhance template rendering performance - Streamline user experience across all interfaces 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
24 KiB
Docker Development Guide
Version: 2.0.0
Last Updated: August 28, 2025
Audience: Developers, QA Engineers
Platform: HVAC Community Events
Executive Summary
This guide provides comprehensive documentation for the Docker-based development and testing environment for the HVAC Community Events WordPress plugin. The environment includes a complete WordPress stack with testing tools, database management, and email testing capabilities.
Table of Contents
- Environment Overview
- Prerequisites
- Initial Setup
- Container Management
- Database Operations
- Test Framework Architecture
- Running Tests
- Debugging
- Performance Testing
- Troubleshooting
- Best Practices
- Advanced Configuration
Environment Overview
Architecture Diagram
┌─────────────────────────────────────────────────────────────┐
│ Host Machine │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Docker Compose Network │ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌───────────┐ │ │
│ │ │ WordPress │ │ MySQL │ │ Redis │ │ │
│ │ │ PHP 8.2 │◄─┤ 8.0 │◄─┤ Cache │ │ │
│ │ │ Port: 8080 │ │ Port: 3307 │ │Port: 6380 │ │ │
│ │ └──────────────┘ └──────────────┘ └───────────┘ │ │
│ │ │ │
│ │ ┌──────────────┐ ┌──────────────┐ ┌───────────┐ │ │
│ │ │ PhpMyAdmin │ │ Mailhog │ │ Selenium │ │ │
│ │ │ Port: 8081 │ │ Port: 8025 │ │ Port: 4444│ │ │
│ │ └──────────────┘ └──────────────┘ └───────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Test Files ◄──────► Plugin Source ◄──────► Test Results │
└─────────────────────────────────────────────────────────────┘
Service Details
| Service | Image | Port | Purpose |
|---|---|---|---|
| WordPress | wordpress:6.4-php8.2-apache | 8080 | Main application |
| MySQL | mysql:8.0 | 3307 | Database server |
| Redis | redis:7-alpine | 6380 | Object caching |
| PhpMyAdmin | phpmyadmin:5 | 8081 | Database management |
| Mailhog | mailhog/mailhog | 8025 | Email testing |
| Selenium | selenium/standalone-chrome | 4444 | Browser automation |
Prerequisites
System Requirements
Operating System:
- Linux (Ubuntu 20.04+, Debian 11+)
- macOS (11.0+)
- Windows 10/11 with WSL2
Docker:
version: "20.10+"
compose: "2.0+"
Resources:
RAM: "8GB minimum, 16GB recommended"
CPU: "4 cores minimum"
Disk: "20GB free space"
Development Tools:
- Node.js 16+
- npm or yarn
- Git
- Visual Studio Code (recommended)
Installation
Linux/macOS
# Install Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
# Install Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
# Verify installation
docker --version
docker compose version
Windows (WSL2)
# Install WSL2
wsl --install
# Install Docker Desktop
# Download from https://docker.com/products/docker-desktop
# Enable WSL2 integration in Docker Desktop settings
Initial Setup
1. Clone Repository
# Clone the repository
git clone https://github.com/your-org/upskill-event-manager.git
cd upskill-event-manager
# Checkout development branch
git checkout development
2. Environment Configuration
# Copy environment template
cp tests/.env.template tests/.env
# Edit environment variables
nano tests/.env
Environment Variables
# WordPress Configuration
WORDPRESS_DB_HOST=mysql-test
WORDPRESS_DB_USER=hvac_test_user
WORDPRESS_DB_PASSWORD=hvac_test_password
WORDPRESS_DB_NAME=hvac_test_db
WORDPRESS_DEBUG=1
WORDPRESS_DEBUG_LOG=1
WORDPRESS_DEBUG_DISPLAY=0
# Test Configuration
HVAC_TEST_MODE=true
HVAC_TEST_DATA_ISOLATION=true
HVAC_TEST_EMAIL=test@example.com
# Service Ports
WORDPRESS_PORT=8080
MYSQL_PORT=3307
REDIS_PORT=6380
PHPMYADMIN_PORT=8081
MAILHOG_PORT=8025
SELENIUM_PORT=4444
# Volumes
WORDPRESS_VOLUME=wordpress_test_data
MYSQL_VOLUME=mysql_test_data
REDIS_VOLUME=redis_test_data
3. Build and Start Containers
# Navigate to tests directory
cd tests
# Build and start all services
docker compose -f docker-compose.test.yml up -d --build
# Wait for services to be healthy
docker compose -f docker-compose.test.yml ps
# Check logs
docker compose -f docker-compose.test.yml logs -f
4. Initialize WordPress
# Install WordPress
docker compose exec wordpress-test wp core install \
--url="http://localhost:8080" \
--title="HVAC Test Site" \
--admin_user="admin" \
--admin_password="admin123" \
--admin_email="admin@test.local"
# Activate plugin
docker compose exec wordpress-test wp plugin activate hvac-community-events
# Install The Events Calendar
docker compose exec wordpress-test wp plugin install the-events-calendar --activate
# Create test pages
docker compose exec wordpress-test wp eval 'HVAC_Page_Manager::create_required_pages();'
# Flush permalinks
docker compose exec wordpress-test wp rewrite flush
5. Seed Test Data
# Create test users
./scripts/seed-test-users.sh
# Create test events
./scripts/seed-test-events.sh
# Import sample venues
docker compose exec wordpress-test wp import fixtures/venues.xml --authors=create
# Generate test certificates
docker compose exec wordpress-test wp eval 'HVAC_Test_Data::generate_certificates(50);'
Container Management
Starting and Stopping
# Start all containers
docker compose -f docker-compose.test.yml up -d
# Stop all containers (preserves data)
docker compose -f docker-compose.test.yml stop
# Stop and remove containers (preserves volumes)
docker compose -f docker-compose.test.yml down
# Stop and remove everything (including volumes)
docker compose -f docker-compose.test.yml down -v
# Restart specific service
docker compose -f docker-compose.test.yml restart wordpress-test
Accessing Services
# WordPress site
open http://localhost:8080
# WordPress admin
open http://localhost:8080/wp-admin
# Username: admin
# Password: admin123
# PhpMyAdmin
open http://localhost:8081
# Username: hvac_test_user
# Password: hvac_test_password
# Mailhog (email testing)
open http://localhost:8025
# Redis Commander (if installed)
docker run -d --name redis-commander \
--network hvac-test-network \
-p 8082:8081 \
rediscommander/redis-commander \
--redis-host redis-test
Executing Commands
# WordPress CLI
docker compose exec wordpress-test wp [command]
# MySQL CLI
docker compose exec mysql-test mysql -u root -p
# Redis CLI
docker compose exec redis-test redis-cli
# PHP commands
docker compose exec wordpress-test php [script.php]
# Bash shell
docker compose exec wordpress-test bash
Database Operations
Backup and Restore
# Backup database
docker compose exec mysql-test mysqldump \
-u hvac_test_user -phvac_test_password \
hvac_test_db > backup-$(date +%Y%m%d).sql
# Restore database
docker compose exec -T mysql-test mysql \
-u hvac_test_user -phvac_test_password \
hvac_test_db < backup-20250828.sql
# Export specific tables
docker compose exec mysql-test mysqldump \
-u hvac_test_user -phvac_test_password \
hvac_test_db wp_posts wp_postmeta > posts-backup.sql
Database Management
# Connect to MySQL
docker compose exec mysql-test mysql -u root -p
# Common queries
SHOW DATABASES;
USE hvac_test_db;
SHOW TABLES;
DESCRIBE wp_users;
# Check plugin tables
SHOW TABLES LIKE 'wp_hvac%';
# Query examples
SELECT * FROM wp_users WHERE user_login LIKE 'hvac_%';
SELECT COUNT(*) FROM wp_posts WHERE post_type = 'tribe_events';
Reset Database
#!/bin/bash
# reset-database.sh
# Drop and recreate database
docker compose exec mysql-test mysql -u root -p -e "
DROP DATABASE IF EXISTS hvac_test_db;
CREATE DATABASE hvac_test_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
GRANT ALL ON hvac_test_db.* TO 'hvac_test_user'@'%';
FLUSH PRIVILEGES;
"
# Reinstall WordPress
docker compose exec wordpress-test wp core install \
--url="http://localhost:8080" \
--title="HVAC Test Site" \
--admin_user="admin" \
--admin_password="admin123" \
--admin_email="admin@test.local"
# Reactivate plugins and recreate pages
docker compose exec wordpress-test wp plugin activate hvac-community-events
docker compose exec wordpress-test wp eval 'HVAC_Page_Manager::create_required_pages();'
Test Framework Architecture
Page Object Model (POM)
The test framework uses the Page Object Model pattern for maintainability and reusability:
// Structure
tests/
├── e2e/
│ ├── page-objects/
│ │ ├── BasePage.js
│ │ ├── LoginPage.js
│ │ ├── DashboardPage.js
│ │ ├── EventPage.js
│ │ └── VenuePage.js
│ ├── fixtures/
│ │ ├── users.json
│ │ ├── events.json
│ │ └── venues.json
│ ├── helpers/
│ │ ├── BrowserManager.js
│ │ ├── TestData.js
│ │ └── Utilities.js
│ └── tests/
│ ├── authentication.test.js
│ ├── event-management.test.js
│ └── venue-management.test.js
Browser Manager (Singleton)
// BrowserManager.js
const { chromium, firefox, webkit } = require('playwright');
class BrowserManager {
constructor() {
if (BrowserManager.instance) {
return BrowserManager.instance;
}
this.browser = null;
this.context = null;
this.page = null;
BrowserManager.instance = this;
}
async initialize(options = {}) {
const browserType = options.browser || 'chromium';
const headless = options.headless !== false;
this.browser = await chromium.launch({
headless,
args: ['--no-sandbox', '--disable-setuid-sandbox'],
});
this.context = await this.browser.newContext({
viewport: { width: 1920, height: 1080 },
ignoreHTTPSErrors: true,
...options.context,
});
this.page = await this.context.newPage();
// Set up error handling
this.page.on('pageerror', error => {
console.error('Page error:', error.message);
});
return this.page;
}
async cleanup() {
if (this.page) await this.page.close();
if (this.context) await this.context.close();
if (this.browser) await this.browser.close();
}
}
module.exports = new BrowserManager();
Test Configuration
// test.config.js
module.exports = {
baseURL: process.env.BASE_URL || 'http://localhost:8080',
timeout: 30000,
retries: 2,
workers: 4,
use: {
headless: process.env.HEADLESS === 'true',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
trace: 'on-first-retry',
},
projects: [
{
name: 'Chrome',
use: { browserName: 'chromium' },
},
{
name: 'Firefox',
use: { browserName: 'firefox' },
},
{
name: 'Safari',
use: { browserName: 'webkit' },
},
],
reporter: [
['html', { outputFolder: 'test-results/html' }],
['json', { outputFile: 'test-results/results.json' }],
['junit', { outputFile: 'test-results/junit.xml' }],
],
};
Running Tests
E2E Test Execution
# Run all tests (headless)
HEADLESS=true BASE_URL=http://localhost:8080 npm test
# Run specific test file
HEADLESS=true npm test -- test-master-trainer-e2e.js
# Run with visible browser
HEADLESS=false npm test
# Run specific test suite
npm test -- --grep "Event Management"
# Run in parallel
npm test -- --workers=4
# Generate HTML report
npm test -- --reporter=html
open test-results/index.html
Test Categories
# Authentication tests
node tests/e2e/auth.test.js
# Event management tests
node tests/e2e/events.test.js
# Venue management tests
node tests/e2e/venues.test.js
# Certificate generation tests
node tests/e2e/certificates.test.js
# Master trainer features
node tests/e2e/master-trainer.test.js
# Performance tests
node tests/performance/load-test.js
Cross-Browser Testing
# Chrome
BROWSER=chromium npm test
# Firefox
BROWSER=firefox npm test
# Safari (WebKit)
BROWSER=webkit npm test
# All browsers sequentially
npm run test:cross-browser
# All browsers in parallel
npm run test:cross-browser:parallel
Visual Regression Testing
# Capture baseline screenshots
npm run test:visual:baseline
# Run visual comparison tests
npm run test:visual:compare
# Update baseline images
npm run test:visual:update
# View diff report
open test-results/visual-diff/index.html
Debugging
Debug Mode
// Enable debug mode in tests
const DEBUG = process.env.DEBUG === 'true';
if (DEBUG) {
// Slow down actions
page.setDefaultTimeout(60000);
// Pause on failures
page.on('pageerror', async () => {
await page.pause();
});
// Take screenshots at each step
afterEach(async () => {
await page.screenshot({
path: `debug/step-${Date.now()}.png`
});
});
}
Interactive Debugging
# Launch browser with DevTools
PWDEBUG=1 node test-file.js
# Use Playwright Inspector
npx playwright test --debug
# Pause at specific point
await page.pause(); // Add in test code
Container Debugging
# View container logs
docker compose logs -f wordpress-test
# Access container shell
docker compose exec wordpress-test bash
# Check PHP errors
docker compose exec wordpress-test tail -f /var/log/apache2/error.log
# Monitor MySQL queries
docker compose exec mysql-test tail -f /var/log/mysql/query.log
# Debug WordPress
docker compose exec wordpress-test wp shell
Network Debugging
# Monitor network traffic
docker compose exec wordpress-test tcpdump -i any -w traffic.pcap
# Check container connectivity
docker compose exec wordpress-test ping mysql-test
# Inspect Docker network
docker network inspect hvac-test-network
# Port forwarding issues
netstat -tuln | grep 8080
Performance Testing
Load Testing Setup
// load-test.js
const { chromium } = require('playwright');
const { performance } = require('perf_hooks');
async function loadTest(config) {
const { concurrent = 10, iterations = 100 } = config;
const results = [];
const runTest = async () => {
const start = performance.now();
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
await page.goto('http://localhost:8080/trainer/dashboard/');
await page.waitForSelector('.hvac-dashboard');
const end = performance.now();
await browser.close();
return end - start;
};
// Run concurrent tests
for (let i = 0; i < iterations; i += concurrent) {
const batch = Array(concurrent).fill().map(() => runTest());
const times = await Promise.all(batch);
results.push(...times);
}
// Calculate statistics
const avg = results.reduce((a, b) => a + b, 0) / results.length;
const max = Math.max(...results);
const min = Math.min(...results);
console.log(`Average: ${avg}ms, Max: ${max}ms, Min: ${min}ms`);
}
// Run load test
loadTest({ concurrent: 20, iterations: 200 });
Performance Metrics
# Monitor container resources
docker stats
# MySQL performance
docker compose exec mysql-test mysqladmin -u root -p status
# Redis performance
docker compose exec redis-test redis-cli INFO stats
# Apache performance
docker compose exec wordpress-test apache2ctl -S
Troubleshooting
Common Issues
Container won't start
# Check for port conflicts
lsof -i :8080
lsof -i :3307
# Kill conflicting processes
kill -9 $(lsof -t -i:8080)
# Reset Docker
docker system prune -a
docker volume prune
Database connection errors
# Verify MySQL is running
docker compose ps mysql-test
# Check MySQL logs
docker compose logs mysql-test
# Test connection
docker compose exec wordpress-test wp db check
# Reset MySQL password
docker compose exec mysql-test mysql -u root -e "
ALTER USER 'hvac_test_user'@'%' IDENTIFIED BY 'hvac_test_password';
FLUSH PRIVILEGES;
"
Plugin activation fails
# Check PHP errors
docker compose exec wordpress-test tail -f /var/log/apache2/error.log
# Verify plugin files
docker compose exec wordpress-test ls -la /var/www/html/wp-content/plugins/hvac-community-events/
# Debug plugin activation
docker compose exec wordpress-test wp plugin activate hvac-community-events --debug
Tests timing out
// Increase timeout in test
test.setTimeout(60000);
// Or globally
module.exports = {
timeout: 60000,
// ...
};
// Debug slow operations
console.time('operation');
await slowOperation();
console.timeEnd('operation');
Reset Everything
#!/bin/bash
# full-reset.sh
# Stop and remove all containers
docker compose -f docker-compose.test.yml down -v
# Remove all test data
rm -rf wordpress_test_data/
rm -rf mysql_test_data/
rm -rf redis_test_data/
# Clean Docker system
docker system prune -a --volumes
# Rebuild and start fresh
docker compose -f docker-compose.test.yml up -d --build
# Wait for healthy state
sleep 30
# Initialize WordPress
./scripts/init-wordpress.sh
# Seed test data
./scripts/seed-all-data.sh
Best Practices
Development Workflow
-
Branch Strategy
# Create feature branch git checkout -b feature/new-venue-system # Make changes and test locally docker compose up -d npm test # Commit with conventional commits git commit -m "feat: implement new venue management system" -
Test-Driven Development
// Write test first test('should create new venue', async () => { await venuePage.createVenue({ name: 'Test Venue', address: '123 Test St', }); expect(await venuePage.venueExists('Test Venue')).toBe(true); }); // Then implement feature -
Data Isolation
// Use unique test data const testId = Date.now(); const venueName = `Venue_${testId}`; // Clean up after tests afterEach(async () => { await cleanup(testId); });
Code Quality
-
Linting
# JavaScript npm run lint # PHP docker compose exec wordpress-test ./vendor/bin/phpcs # Fix automatically npm run lint:fix -
Code Coverage
# Generate coverage report npm run test:coverage # View report open coverage/index.html -
Security Scanning
# Scan for vulnerabilities npm audit # PHP dependencies docker compose exec wordpress-test ./vendor/bin/security-checker security:check
Performance Optimization
-
Container Resources
# docker-compose.yml services: wordpress-test: deploy: resources: limits: cpus: '2' memory: 2G reservations: cpus: '1' memory: 1G -
Caching Strategy
# Enable Redis object cache docker compose exec wordpress-test wp plugin install redis-cache --activate docker compose exec wordpress-test wp redis enable -
Database Optimization
-- Add indexes ALTER TABLE wp_posts ADD INDEX idx_type_status (post_type, post_status); ALTER TABLE wp_postmeta ADD INDEX idx_meta_key (meta_key); -- Optimize tables OPTIMIZE TABLE wp_posts; OPTIMIZE TABLE wp_postmeta;
Advanced Configuration
Custom Docker Network
# docker-compose.override.yml
networks:
hvac-test-network:
driver: bridge
ipam:
config:
- subnet: 172.28.0.0/16
gateway: 172.28.0.1
SSL Configuration
# Generate self-signed certificate
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout nginx/ssl/private.key \
-out nginx/ssl/certificate.crt
# Add nginx proxy container
services:
nginx:
image: nginx:alpine
ports:
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/ssl:/etc/nginx/ssl
Multi-Site Testing
# Enable WordPress Multisite
environment:
WORDPRESS_CONFIG_EXTRA: |
define('WP_ALLOW_MULTISITE', true);
define('MULTISITE', true);
define('SUBDOMAIN_INSTALL', false);
define('DOMAIN_CURRENT_SITE', 'localhost');
define('PATH_CURRENT_SITE', '/');
define('SITE_ID_CURRENT_SITE', 1);
define('BLOG_ID_CURRENT_SITE', 1);
CI/CD Integration
# .github/workflows/test.yml
name: E2E Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Start Docker Compose
run: |
docker compose -f tests/docker-compose.test.yml up -d
sleep 30
- name: Initialize WordPress
run: |
docker compose exec -T wordpress-test wp core install \
--url="http://localhost:8080" \
--title="Test" \
--admin_user="admin" \
--admin_password="admin123" \
--admin_email="test@test.com"
- name: Run Tests
run: |
npm ci
npm test
- name: Upload Results
if: always()
uses: actions/upload-artifact@v3
with:
name: test-results
path: test-results/
Quick Reference
Essential Commands
# Start environment
docker compose -f tests/docker-compose.test.yml up -d
# Stop environment
docker compose -f tests/docker-compose.test.yml down
# View logs
docker compose -f tests/docker-compose.test.yml logs -f
# Run tests
HEADLESS=true npm test
# Access WordPress
open http://localhost:8080
# Access database
open http://localhost:8081
# View emails
open http://localhost:8025
# Shell access
docker compose exec wordpress-test bash
# WP-CLI
docker compose exec wordpress-test wp [command]
Service URLs
| Service | URL | Credentials |
|---|---|---|
| WordPress | http://localhost:8080 | admin / admin123 |
| WordPress Admin | http://localhost:8080/wp-admin | admin / admin123 |
| PhpMyAdmin | http://localhost:8081 | hvac_test_user / hvac_test_password |
| Mailhog | http://localhost:8025 | No auth required |
| Redis Commander | http://localhost:8082 | No auth required |
File Locations
# Plugin source
./
# Test files
./tests/
# Docker config
./tests/docker-compose.test.yml
# Test results
./test-results/
# Screenshots
./screenshots/
# Fixtures
./tests/fixtures/
This guide is maintained by the HVAC Community Events development team. For updates or issues, please submit a pull request or open an issue in the repository.
Document Version: 2.0.0
Last Updated: August 28, 2025
Next Review: September 28, 2025