/** * 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} */ async initialize() { await this.loadTestAccounts(); await this.loadTestData(); await this.loadFixtures(); } /** * Load test accounts for different environments * @returns {Promise} */ 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} */ 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} */ 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} */ 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} */ 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 };