## 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>
220 lines
No EOL
8.1 KiB
JavaScript
220 lines
No EOL
8.1 KiB
JavaScript
const { chromium } = require('playwright');
|
||
|
||
console.log('🔍 FIND A TRAINER COMPREHENSIVE TESTING');
|
||
console.log('=====================================');
|
||
|
||
const BASE_URL = process.env.BASE_URL || 'https://upskill-staging.measurequick.com';
|
||
|
||
(async () => {
|
||
let browser;
|
||
let testResults = {
|
||
total: 0,
|
||
passed: 0,
|
||
failed: 0,
|
||
details: []
|
||
};
|
||
|
||
function addTest(name, passed, details = '') {
|
||
testResults.total++;
|
||
if (passed) {
|
||
testResults.passed++;
|
||
console.log(`✅ ${name}`);
|
||
} else {
|
||
testResults.failed++;
|
||
console.log(`❌ ${name}${details ? ': ' + details : ''}`);
|
||
}
|
||
testResults.details.push({ name, passed, details });
|
||
}
|
||
|
||
try {
|
||
browser = await chromium.launch({
|
||
headless: process.env.HEADLESS !== 'false',
|
||
timeout: 30000
|
||
});
|
||
|
||
const page = await browser.newPage();
|
||
|
||
console.log('\n🌐 Loading Find a Trainer page...');
|
||
await page.goto(`${BASE_URL}/find-a-trainer/`);
|
||
await page.waitForLoadState('networkidle', { timeout: 20000 });
|
||
|
||
// Test 1: Page loads successfully
|
||
const title = await page.title();
|
||
addTest('Page loads with correct title', title.includes('Find') || title.includes('Trainer'));
|
||
|
||
// Test 2: Search input has correct class
|
||
console.log('\n🔍 Testing search input...');
|
||
const searchInput = await page.locator('#hvac-trainer-search');
|
||
const searchInputExists = await searchInput.count() > 0;
|
||
addTest('Search input exists', searchInputExists);
|
||
|
||
if (searchInputExists) {
|
||
const hasClass = await searchInput.getAttribute('class');
|
||
const hasCorrectClass = hasClass && hasClass.includes('hvac-search-input');
|
||
addTest('Search input has hvac-search-input class', hasCorrectClass, hasClass);
|
||
|
||
// Test search functionality
|
||
await searchInput.fill('test');
|
||
await page.waitForTimeout(1000);
|
||
await searchInput.clear();
|
||
addTest('Search input can be typed in and cleared', true);
|
||
}
|
||
|
||
// Test 3: Filter buttons exist and are clickable
|
||
console.log('\n🔘 Testing filter buttons...');
|
||
const filterButtons = await page.locator('.hvac-filter-btn, .hvac-filter-button');
|
||
const filterCount = await filterButtons.count();
|
||
addTest('Filter buttons found', filterCount > 0, `Found ${filterCount} buttons`);
|
||
|
||
// Test 4: Training Format filter modal
|
||
console.log('\n📋 Testing Training Format filter...');
|
||
const formatButton = await page.locator('.hvac-filter-btn[data-filter="training_format"], .hvac-filter-button[data-filter="training_format"]');
|
||
const formatButtonExists = await formatButton.count() > 0;
|
||
addTest('Training Format filter button exists', formatButtonExists);
|
||
|
||
if (formatButtonExists) {
|
||
await formatButton.click();
|
||
await page.waitForTimeout(1000);
|
||
|
||
const modal = await page.locator('#hvac-filter-modal');
|
||
const modalVisible = await modal.isVisible();
|
||
addTest('Training Format modal opens', modalVisible);
|
||
|
||
if (modalVisible) {
|
||
const options = await page.locator('.hvac-filter-option').count();
|
||
addTest('Training Format has filter options', options > 0, `Found ${options} options`);
|
||
|
||
// Close modal
|
||
const closeBtn = await page.locator('.hvac-close-modal, .close');
|
||
if (await closeBtn.count() > 0) {
|
||
await closeBtn.click();
|
||
await page.waitForTimeout(500);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Test 5: Training Resources filter modal
|
||
console.log('\n📚 Testing Training Resources filter...');
|
||
const resourcesButton = await page.locator('.hvac-filter-btn[data-filter="training_resources"], .hvac-filter-button[data-filter="training_resources"]');
|
||
const resourcesButtonExists = await resourcesButton.count() > 0;
|
||
addTest('Training Resources filter button exists', resourcesButtonExists);
|
||
|
||
if (resourcesButtonExists) {
|
||
await resourcesButton.click();
|
||
await page.waitForTimeout(1000);
|
||
|
||
const modal = await page.locator('#hvac-filter-modal');
|
||
const modalVisible = await modal.isVisible();
|
||
addTest('Training Resources modal opens', modalVisible);
|
||
|
||
if (modalVisible) {
|
||
const options = await page.locator('.hvac-filter-option').count();
|
||
addTest('Training Resources has filter options', options > 0, `Found ${options} options`);
|
||
|
||
// Test that options are not all clumped together
|
||
const optionTexts = await page.locator('.hvac-filter-option label').allTextContents();
|
||
const uniqueOptions = [...new Set(optionTexts)];
|
||
addTest('Training Resources options are distinct', uniqueOptions.length > 1, `${uniqueOptions.length} unique options`);
|
||
|
||
// Close modal
|
||
const closeBtn = await page.locator('.hvac-close-modal, .close');
|
||
if (await closeBtn.count() > 0) {
|
||
await closeBtn.click();
|
||
await page.waitForTimeout(500);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Test 6: Map functionality
|
||
console.log('\n🗺️ Testing map functionality...');
|
||
const mapContainer = await page.locator('#hvac-trainer-map, .hvac-map-container, #map');
|
||
const mapExists = await mapContainer.count() > 0;
|
||
addTest('Map container exists', mapExists);
|
||
|
||
if (mapExists) {
|
||
// Wait for map to potentially load
|
||
await page.waitForTimeout(3000);
|
||
|
||
// Check for map-related elements
|
||
const mapControls = await page.locator('.leaflet-control, .amcharts-map, .ol-zoom').count();
|
||
addTest('Map controls/elements present', mapControls > 0, `Found ${mapControls} map elements`);
|
||
}
|
||
|
||
// Test 7: Check for JavaScript errors
|
||
console.log('\n🔧 Checking for JavaScript errors...');
|
||
const logs = await page.evaluate(() => {
|
||
return window.console ? window.console.logs || [] : [];
|
||
});
|
||
|
||
// Listen for console errors during page interaction
|
||
let hasJSErrors = false;
|
||
page.on('console', msg => {
|
||
if (msg.type() === 'error') {
|
||
hasJSErrors = true;
|
||
console.log(` JS Error: ${msg.text()}`);
|
||
}
|
||
});
|
||
|
||
// Trigger some interactions to check for errors
|
||
try {
|
||
await page.locator('#hvac-trainer-search').fill('test search');
|
||
await page.waitForTimeout(1000);
|
||
addTest('No JavaScript errors on search interaction', !hasJSErrors);
|
||
} catch (e) {
|
||
addTest('Search interaction without errors', false, e.message);
|
||
}
|
||
|
||
// Test 8: AJAX endpoints accessibility
|
||
console.log('\n🔄 Testing AJAX endpoints...');
|
||
try {
|
||
const response = await page.evaluate(async () => {
|
||
const formData = new FormData();
|
||
formData.append('action', 'hvac_filter_trainers');
|
||
formData.append('search_term', '');
|
||
formData.append('filters', JSON.stringify({}));
|
||
|
||
const response = await fetch('/wp-admin/admin-ajax.php', {
|
||
method: 'POST',
|
||
body: formData
|
||
});
|
||
|
||
return {
|
||
status: response.status,
|
||
ok: response.ok
|
||
};
|
||
});
|
||
|
||
addTest('AJAX filter endpoint accessible', response.ok, `Status: ${response.status}`);
|
||
} catch (e) {
|
||
addTest('AJAX filter endpoint accessible', false, e.message);
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error('\n💥 Critical Error:', error.message);
|
||
addTest('Test suite execution', false, error.message);
|
||
} finally {
|
||
if (browser) {
|
||
await browser.close();
|
||
}
|
||
}
|
||
|
||
// Final Results
|
||
console.log('\n📊 TEST RESULTS');
|
||
console.log('===============');
|
||
console.log(`Total Tests: ${testResults.total}`);
|
||
console.log(`Passed: ${testResults.passed} ✅`);
|
||
console.log(`Failed: ${testResults.failed} ❌`);
|
||
console.log(`Success Rate: ${Math.round((testResults.passed / testResults.total) * 100)}%`);
|
||
|
||
if (testResults.failed > 0) {
|
||
console.log('\n❌ Failed Tests:');
|
||
testResults.details.filter(t => !t.passed).forEach(test => {
|
||
console.log(` • ${test.name}${test.details ? ': ' + test.details : ''}`);
|
||
});
|
||
}
|
||
|
||
const success = testResults.failed === 0;
|
||
console.log(`\n🎯 OVERALL RESULT: ${success ? '✅ ALL TESTS PASSED' : '❌ SOME TESTS FAILED'}`);
|
||
|
||
process.exit(success ? 0 : 1);
|
||
})(); |