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>
540 lines
No EOL
20 KiB
JavaScript
540 lines
No EOL
20 KiB
JavaScript
/**
|
|
* Test Data Manager
|
|
* Centralized test data management for HVAC testing framework
|
|
*/
|
|
|
|
const fs = require('fs').promises;
|
|
const path = require('path');
|
|
|
|
class TestDataManager {
|
|
constructor(environment = 'staging') {
|
|
this.environment = environment;
|
|
this.dataCache = new Map();
|
|
this.fixturesPath = path.join(__dirname, 'fixtures');
|
|
this.accounts = null;
|
|
this.testData = null;
|
|
}
|
|
|
|
/**
|
|
* Initialize test data manager
|
|
* @returns {Promise<void>}
|
|
*/
|
|
async initialize() {
|
|
await this.loadTestAccounts();
|
|
await this.loadTestData();
|
|
await this.loadFixtures();
|
|
}
|
|
|
|
/**
|
|
* Load test accounts for different environments
|
|
* @returns {Promise<void>}
|
|
*/
|
|
async loadTestAccounts() {
|
|
this.accounts = {
|
|
staging: {
|
|
masterTrainer: {
|
|
username: 'test_master',
|
|
password: 'TestMaster123!',
|
|
email: 'test_master@example.com',
|
|
role: 'master_trainer',
|
|
displayName: 'Test Master Trainer',
|
|
capabilities: ['manage_events', 'manage_trainers', 'view_announcements']
|
|
},
|
|
alternateMasterTrainer: {
|
|
username: 'JoeMedosch@gmail.com',
|
|
password: 'JoeTrainer2025@',
|
|
email: 'JoeMedosch@gmail.com',
|
|
role: 'master_trainer',
|
|
displayName: 'Joe Medosch',
|
|
capabilities: ['manage_events', 'manage_trainers', 'view_announcements']
|
|
},
|
|
trainer: {
|
|
username: 'test_trainer',
|
|
password: 'TestTrainer123!',
|
|
email: 'test_trainer@example.com',
|
|
role: 'hvac_trainer',
|
|
displayName: 'Test Trainer',
|
|
capabilities: ['create_events', 'manage_profile', 'view_leads']
|
|
},
|
|
admin: {
|
|
username: process.env.STAGING_ADMIN_USER || 'admin',
|
|
password: process.env.STAGING_ADMIN_PASSWORD || 'admin_password',
|
|
email: 'admin@example.com',
|
|
role: 'administrator',
|
|
displayName: 'Site Administrator',
|
|
capabilities: ['manage_options', 'manage_users', 'manage_plugins']
|
|
}
|
|
},
|
|
production: {
|
|
masterTrainer: {
|
|
username: process.env.PROD_MASTER_USERNAME,
|
|
password: process.env.PROD_MASTER_PASSWORD,
|
|
email: process.env.PROD_MASTER_EMAIL,
|
|
role: 'master_trainer',
|
|
displayName: 'Production Master Trainer',
|
|
capabilities: ['manage_events', 'manage_trainers', 'view_announcements']
|
|
},
|
|
trainer: {
|
|
username: process.env.PROD_TRAINER_USERNAME,
|
|
password: process.env.PROD_TRAINER_PASSWORD,
|
|
email: process.env.PROD_TRAINER_EMAIL,
|
|
role: 'hvac_trainer',
|
|
displayName: 'Production Trainer',
|
|
capabilities: ['create_events', 'manage_profile', 'view_leads']
|
|
}
|
|
},
|
|
local: {
|
|
masterTrainer: {
|
|
username: 'master_local',
|
|
password: 'MasterLocal123!',
|
|
email: 'master@localhost.dev',
|
|
role: 'master_trainer',
|
|
displayName: 'Local Master Trainer',
|
|
capabilities: ['manage_events', 'manage_trainers', 'view_announcements']
|
|
},
|
|
trainer: {
|
|
username: 'trainer_local',
|
|
password: 'TrainerLocal123!',
|
|
email: 'trainer@localhost.dev',
|
|
role: 'hvac_trainer',
|
|
displayName: 'Local Trainer',
|
|
capabilities: ['create_events', 'manage_profile', 'view_leads']
|
|
},
|
|
admin: {
|
|
username: 'admin',
|
|
password: 'admin123',
|
|
email: 'admin@localhost.dev',
|
|
role: 'administrator',
|
|
displayName: 'Local Admin',
|
|
capabilities: ['manage_options', 'manage_users', 'manage_plugins']
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Load test data for different scenarios
|
|
* @returns {Promise<void>}
|
|
*/
|
|
async loadTestData() {
|
|
this.testData = {
|
|
events: {
|
|
basicEvent: {
|
|
title: 'Test HVAC Training Event',
|
|
description: 'This is a test event for HVAC training purposes.',
|
|
startDate: this.getFutureDate(7), // 7 days from now
|
|
endDate: this.getFutureDate(8), // 8 days from now
|
|
startTime: '09:00:00',
|
|
endTime: '17:00:00',
|
|
location: 'Test Training Center',
|
|
address: '123 Test Street, Test City, TS 12345',
|
|
capacity: 20,
|
|
status: 'published',
|
|
eventType: 'training',
|
|
categories: ['hvac', 'training', 'test']
|
|
},
|
|
fullEvent: {
|
|
title: 'Comprehensive HVAC Certification Course',
|
|
description: 'Complete HVAC certification training with hands-on experience.',
|
|
startDate: this.getFutureDate(14),
|
|
endDate: this.getFutureDate(16),
|
|
startTime: '08:30:00',
|
|
endTime: '18:00:00',
|
|
location: 'Advanced Training Facility',
|
|
address: '456 Training Avenue, Education City, ED 54321',
|
|
capacity: 15,
|
|
price: 299.99,
|
|
instructorNotes: 'Bring work clothes and safety equipment',
|
|
prerequisites: 'Basic electrical knowledge required',
|
|
materials: 'All materials provided',
|
|
certification: 'EPA 608 Certification',
|
|
status: 'published',
|
|
eventType: 'certification',
|
|
categories: ['hvac', 'certification', 'advanced']
|
|
},
|
|
pastEvent: {
|
|
title: 'Past HVAC Workshop',
|
|
description: 'This event has already occurred.',
|
|
startDate: this.getPastDate(30),
|
|
endDate: this.getPastDate(30),
|
|
startTime: '10:00:00',
|
|
endTime: '16:00:00',
|
|
location: 'Past Event Venue',
|
|
address: '789 Past Street, History City, HI 98765',
|
|
capacity: 12,
|
|
status: 'completed',
|
|
eventType: 'workshop'
|
|
}
|
|
},
|
|
venues: {
|
|
basicVenue: {
|
|
name: 'Test Training Center',
|
|
address: '123 Test Street',
|
|
city: 'Test City',
|
|
state: 'TS',
|
|
zipCode: '12345',
|
|
phone: '555-TEST-001',
|
|
email: 'contact@testcenter.com',
|
|
capacity: 25,
|
|
facilities: ['parking', 'wifi', 'projector'],
|
|
notes: 'Accessible venue with modern facilities'
|
|
},
|
|
advancedVenue: {
|
|
name: 'Advanced Training Facility',
|
|
address: '456 Training Avenue',
|
|
city: 'Education City',
|
|
state: 'ED',
|
|
zipCode: '54321',
|
|
phone: '555-ADV-002',
|
|
email: 'info@advancedtraining.com',
|
|
website: 'https://advancedtraining.com',
|
|
capacity: 30,
|
|
facilities: ['parking', 'wifi', 'projector', 'lab_equipment', 'tools'],
|
|
notes: 'Full HVAC lab with latest equipment'
|
|
}
|
|
},
|
|
organizers: {
|
|
testOrganizer: {
|
|
name: 'Test Training Organization',
|
|
contactName: 'Jane Organizer',
|
|
email: 'jane@testorg.com',
|
|
phone: '555-ORG-001',
|
|
website: 'https://testorg.com',
|
|
address: '123 Organization Street, Org City, OG 12345',
|
|
notes: 'Primary test organizer for training events'
|
|
},
|
|
corporateOrganizer: {
|
|
name: 'Corporate HVAC Training',
|
|
contactName: 'John Corporate',
|
|
email: 'john@corporate-hvac.com',
|
|
phone: '555-CORP-002',
|
|
website: 'https://corporate-hvac.com',
|
|
address: '789 Corporate Plaza, Business City, BC 67890',
|
|
taxId: '12-3456789',
|
|
notes: 'Large scale training provider'
|
|
}
|
|
},
|
|
announcements: {
|
|
generalAnnouncement: {
|
|
title: 'Test General Announcement',
|
|
content: 'This is a test announcement for general information.',
|
|
priority: 'normal',
|
|
targetAudience: 'all',
|
|
startDate: this.getCurrentDate(),
|
|
endDate: this.getFutureDate(30),
|
|
status: 'published',
|
|
author: 'Test Master Trainer'
|
|
},
|
|
urgentAnnouncement: {
|
|
title: 'Urgent: Test Emergency Announcement',
|
|
content: 'This is an urgent test announcement that requires immediate attention.',
|
|
priority: 'high',
|
|
targetAudience: 'trainers',
|
|
startDate: this.getCurrentDate(),
|
|
endDate: this.getFutureDate(7),
|
|
status: 'published',
|
|
urgent: true,
|
|
emailNotification: true
|
|
}
|
|
},
|
|
forms: {
|
|
eventRegistration: {
|
|
firstName: 'Test',
|
|
lastName: 'Participant',
|
|
email: 'test.participant@example.com',
|
|
phone: '555-PART-001',
|
|
company: 'Test Company LLC',
|
|
experience: 'beginner',
|
|
specialRequirements: 'None',
|
|
emergencyContact: 'Emergency Contact',
|
|
emergencyPhone: '555-EMRG-001'
|
|
},
|
|
trainerProfile: {
|
|
firstName: 'Test',
|
|
lastName: 'Trainer',
|
|
email: 'test.trainer@example.com',
|
|
phone: '555-TRAIN-001',
|
|
company: 'HVAC Training Pro',
|
|
experience: '5-10 years',
|
|
certifications: ['EPA 608', 'NATE Certified'],
|
|
specialties: ['Installation', 'Maintenance', 'Troubleshooting'],
|
|
bio: 'Experienced HVAC professional with focus on training.',
|
|
website: 'https://hvactrainingpro.com',
|
|
linkedIn: 'https://linkedin.com/in/testtrainer'
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Load fixtures from JSON files
|
|
* @returns {Promise<void>}
|
|
*/
|
|
async loadFixtures() {
|
|
try {
|
|
// Ensure fixtures directory exists
|
|
await fs.mkdir(this.fixturesPath, { recursive: true });
|
|
|
|
// Load existing fixtures or create defaults
|
|
await this.loadOrCreateFixture('users.json', this.accounts[this.environment] || this.accounts.staging);
|
|
await this.loadOrCreateFixture('events.json', this.testData.events);
|
|
await this.loadOrCreateFixture('venues.json', this.testData.venues);
|
|
await this.loadOrCreateFixture('organizers.json', this.testData.organizers);
|
|
await this.loadOrCreateFixture('announcements.json', this.testData.announcements);
|
|
|
|
} catch (error) {
|
|
console.warn(`Failed to load fixtures: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Load fixture file or create with default data
|
|
* @param {string} filename - Fixture filename
|
|
* @param {Object} defaultData - Default data if file doesn't exist
|
|
* @returns {Promise<Object>}
|
|
*/
|
|
async loadOrCreateFixture(filename, defaultData) {
|
|
const filePath = path.join(this.fixturesPath, filename);
|
|
|
|
try {
|
|
const content = await fs.readFile(filePath, 'utf8');
|
|
const data = JSON.parse(content);
|
|
this.dataCache.set(filename, data);
|
|
return data;
|
|
} catch (error) {
|
|
// File doesn't exist, create with default data
|
|
await fs.writeFile(filePath, JSON.stringify(defaultData, null, 2));
|
|
this.dataCache.set(filename, defaultData);
|
|
return defaultData;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get test account by role
|
|
* @param {string} role - User role (masterTrainer, trainer, admin, etc.)
|
|
* @returns {Object|null}
|
|
*/
|
|
getTestAccount(role) {
|
|
const envAccounts = this.accounts[this.environment] || this.accounts.staging;
|
|
return envAccounts[role] || null;
|
|
}
|
|
|
|
/**
|
|
* Get all test accounts for current environment
|
|
* @returns {Object}
|
|
*/
|
|
getAllTestAccounts() {
|
|
return this.accounts[this.environment] || this.accounts.staging;
|
|
}
|
|
|
|
/**
|
|
* Get test data by category and type
|
|
* @param {string} category - Data category (events, venues, etc.)
|
|
* @param {string} type - Data type (basicEvent, fullEvent, etc.)
|
|
* @returns {Object|null}
|
|
*/
|
|
getTestData(category, type) {
|
|
if (!this.testData[category]) return null;
|
|
return this.testData[category][type] || null;
|
|
}
|
|
|
|
/**
|
|
* Get all test data for a category
|
|
* @param {string} category - Data category
|
|
* @returns {Object|null}
|
|
*/
|
|
getTestDataCategory(category) {
|
|
return this.testData[category] || null;
|
|
}
|
|
|
|
/**
|
|
* Generate unique test data
|
|
* @param {string} category - Data category
|
|
* @param {string} type - Data type
|
|
* @param {Object} overrides - Properties to override
|
|
* @returns {Object}
|
|
*/
|
|
generateUniqueTestData(category, type, overrides = {}) {
|
|
const baseData = this.getTestData(category, type);
|
|
if (!baseData) return null;
|
|
|
|
const uniqueData = { ...baseData };
|
|
const timestamp = Date.now();
|
|
|
|
// Add unique identifiers
|
|
if (uniqueData.title) {
|
|
uniqueData.title = `${uniqueData.title} - ${timestamp}`;
|
|
}
|
|
if (uniqueData.name) {
|
|
uniqueData.name = `${uniqueData.name} - ${timestamp}`;
|
|
}
|
|
if (uniqueData.email) {
|
|
uniqueData.email = uniqueData.email.replace('@', `+${timestamp}@`);
|
|
}
|
|
|
|
// Apply overrides
|
|
Object.assign(uniqueData, overrides);
|
|
|
|
return uniqueData;
|
|
}
|
|
|
|
/**
|
|
* Create test event data with random variations
|
|
* @param {Object} overrides - Properties to override
|
|
* @returns {Object}
|
|
*/
|
|
createRandomEventData(overrides = {}) {
|
|
const eventTypes = ['training', 'workshop', 'certification', 'seminar'];
|
|
const locations = ['Training Center A', 'Workshop Venue B', 'Conference Hall C'];
|
|
const cities = ['Training City', 'Workshop Town', 'Education Village'];
|
|
|
|
const randomEvent = {
|
|
title: `${this.getRandomElement(['Advanced', 'Basic', 'Intermediate'])} HVAC ${this.getRandomElement(['Training', 'Workshop', 'Course'])}`,
|
|
description: 'Comprehensive HVAC training with hands-on experience.',
|
|
startDate: this.getFutureDate(Math.floor(Math.random() * 30) + 1),
|
|
endDate: this.getFutureDate(Math.floor(Math.random() * 30) + 2),
|
|
startTime: '09:00:00',
|
|
endTime: '17:00:00',
|
|
location: this.getRandomElement(locations),
|
|
address: `${Math.floor(Math.random() * 999) + 100} ${this.getRandomElement(['Main', 'Training', 'Education'])} Street, ${this.getRandomElement(cities)}, TC 12345`,
|
|
capacity: Math.floor(Math.random() * 30) + 10,
|
|
eventType: this.getRandomElement(eventTypes),
|
|
status: 'published'
|
|
};
|
|
|
|
return { ...randomEvent, ...overrides };
|
|
}
|
|
|
|
/**
|
|
* Get protected URLs for security testing
|
|
* @returns {string[]}
|
|
*/
|
|
getProtectedUrls() {
|
|
return [
|
|
'/trainer/dashboard/',
|
|
'/trainer/venue/list/',
|
|
'/trainer/venue/manage/',
|
|
'/trainer/organizer/manage/',
|
|
'/trainer/profile/training-leads/',
|
|
'/master-trainer/master-dashboard/',
|
|
'/master-trainer/events/',
|
|
'/master-trainer/google-sheets/',
|
|
'/master-trainer/announcements/',
|
|
'/master-trainer/pending-approvals/',
|
|
'/master-trainer/trainers/',
|
|
'/master-trainer/communication-templates/'
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get role-based access test scenarios
|
|
* @returns {Array}
|
|
*/
|
|
getRoleAccessTestScenarios() {
|
|
const masterTrainer = this.getTestAccount('masterTrainer');
|
|
const trainer = this.getTestAccount('trainer');
|
|
|
|
return [
|
|
// Master trainer should have access to master trainer pages
|
|
{ user: masterTrainer, url: '/master-trainer/master-dashboard/', expectedAccess: true },
|
|
{ user: masterTrainer, url: '/master-trainer/events/', expectedAccess: true },
|
|
{ user: masterTrainer, url: '/master-trainer/trainers/', expectedAccess: true },
|
|
|
|
// Regular trainer should NOT have access to master trainer pages
|
|
{ user: trainer, url: '/master-trainer/master-dashboard/', expectedAccess: false },
|
|
{ user: trainer, url: '/master-trainer/events/', expectedAccess: false },
|
|
{ user: trainer, url: '/master-trainer/trainers/', expectedAccess: false },
|
|
|
|
// Regular trainer should have access to trainer pages
|
|
{ user: trainer, url: '/trainer/dashboard/', expectedAccess: true },
|
|
{ user: trainer, url: '/trainer/venue/manage/', expectedAccess: true },
|
|
{ user: trainer, url: '/trainer/organizer/manage/', expectedAccess: true }
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get current date in YYYY-MM-DD format
|
|
* @returns {string}
|
|
*/
|
|
getCurrentDate() {
|
|
return new Date().toISOString().split('T')[0];
|
|
}
|
|
|
|
/**
|
|
* Get future date in YYYY-MM-DD format
|
|
* @param {number} daysFromNow - Days in the future
|
|
* @returns {string}
|
|
*/
|
|
getFutureDate(daysFromNow) {
|
|
const date = new Date();
|
|
date.setDate(date.getDate() + daysFromNow);
|
|
return date.toISOString().split('T')[0];
|
|
}
|
|
|
|
/**
|
|
* Get past date in YYYY-MM-DD format
|
|
* @param {number} daysAgo - Days in the past
|
|
* @returns {string}
|
|
*/
|
|
getPastDate(daysAgo) {
|
|
const date = new Date();
|
|
date.setDate(date.getDate() - daysAgo);
|
|
return date.toISOString().split('T')[0];
|
|
}
|
|
|
|
/**
|
|
* Get random element from array
|
|
* @param {Array} array - Array to select from
|
|
* @returns {*}
|
|
* @private
|
|
*/
|
|
getRandomElement(array) {
|
|
return array[Math.floor(Math.random() * array.length)];
|
|
}
|
|
|
|
/**
|
|
* Save test data to fixture file
|
|
* @param {string} filename - Fixture filename
|
|
* @param {Object} data - Data to save
|
|
* @returns {Promise<void>}
|
|
*/
|
|
async saveFixture(filename, data) {
|
|
const filePath = path.join(this.fixturesPath, filename);
|
|
await fs.writeFile(filePath, JSON.stringify(data, null, 2));
|
|
this.dataCache.set(filename, data);
|
|
}
|
|
|
|
/**
|
|
* Clear all cached test data
|
|
* @returns {void}
|
|
*/
|
|
clearCache() {
|
|
this.dataCache.clear();
|
|
}
|
|
|
|
/**
|
|
* Get fixture data
|
|
* @param {string} filename - Fixture filename
|
|
* @returns {Object|null}
|
|
*/
|
|
getFixture(filename) {
|
|
return this.dataCache.get(filename) || null;
|
|
}
|
|
}
|
|
|
|
// Singleton instance
|
|
let testDataManager = null;
|
|
|
|
/**
|
|
* Get singleton TestDataManager instance
|
|
* @param {string} environment - Environment name
|
|
* @returns {TestDataManager}
|
|
*/
|
|
function getTestDataManager(environment = 'staging') {
|
|
if (!testDataManager || testDataManager.environment !== environment) {
|
|
testDataManager = new TestDataManager(environment);
|
|
}
|
|
return testDataManager;
|
|
}
|
|
|
|
module.exports = { TestDataManager, getTestDataManager }; |