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>
442 lines
No EOL
16 KiB
JavaScript
442 lines
No EOL
16 KiB
JavaScript
/**
|
|
* HVAC Final Comprehensive E2E Test Suite
|
|
* Complete end-to-end testing for event creation and editing functionality
|
|
*
|
|
* @package HVAC_Community_Events
|
|
* @version 2.0.0
|
|
* @created 2025-08-13
|
|
*/
|
|
|
|
const { test, expect, devices } = require('@playwright/test');
|
|
const path = require('path');
|
|
const fs = require('fs').promises;
|
|
|
|
// Test configuration
|
|
const BASE_URL = process.env.UPSKILL_STAGING_URL || 'https://upskill-staging.measurequick.com';
|
|
const TEST_TIMEOUT = 60000;
|
|
|
|
// Test credentials
|
|
const TEST_USER = {
|
|
email: 'test_trainer@example.com',
|
|
password: 'TestTrainer123!',
|
|
name: 'Test Trainer'
|
|
};
|
|
|
|
// Test data
|
|
const TEST_EVENT = {
|
|
title: `Test Event ${Date.now()}`,
|
|
description: 'This is a comprehensive test event created by Playwright E2E testing suite.',
|
|
startDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 days from now
|
|
endDate: new Date(Date.now() + 8 * 24 * 60 * 60 * 1000), // 8 days from now
|
|
venue: 'Test Training Center',
|
|
organizer: 'Test Training Organization',
|
|
category: 'HVAC Training',
|
|
tags: ['test', 'automation', 'e2e']
|
|
};
|
|
|
|
// Helper functions
|
|
async function login(page) {
|
|
await page.goto(`${BASE_URL}/wp-login.php`);
|
|
await page.fill('#user_login', TEST_USER.email);
|
|
await page.fill('#user_pass', TEST_USER.password);
|
|
await page.click('#wp-submit');
|
|
await page.waitForURL(/trainer\/dashboard/);
|
|
}
|
|
|
|
async function navigateToEventCreation(page) {
|
|
await page.goto(`${BASE_URL}/trainer/events/create/`);
|
|
await page.waitForSelector('.hvac-event-form-wrapper, iframe#tec-create-frame', { timeout: 10000 });
|
|
}
|
|
|
|
async function fillEventForm(page, eventData) {
|
|
// Check if using iframe
|
|
const iframe = await page.$('iframe#tec-create-frame');
|
|
const context = iframe ? await iframe.contentFrame() : page;
|
|
|
|
// Fill basic fields
|
|
await context.fill('input[name="post_title"], #tribe-events-title', eventData.title);
|
|
|
|
// Fill description with TinyMCE or textarea
|
|
const descriptionField = await context.$('#tinyMCE, #content, textarea[name="post_content"]');
|
|
if (descriptionField) {
|
|
await descriptionField.fill(eventData.description);
|
|
}
|
|
|
|
// Set dates
|
|
const startDateInput = await context.$('input[name="EventStartDate"], #EventStartDate');
|
|
if (startDateInput) {
|
|
await startDateInput.fill(eventData.startDate.toISOString().split('T')[0]);
|
|
}
|
|
|
|
const endDateInput = await context.$('input[name="EventEndDate"], #EventEndDate');
|
|
if (endDateInput) {
|
|
await endDateInput.fill(eventData.endDate.toISOString().split('T')[0]);
|
|
}
|
|
|
|
// Add venue if field exists
|
|
const venueInput = await context.$('input[name="venue[Venue]"], #venue-name');
|
|
if (venueInput) {
|
|
await venueInput.fill(eventData.venue);
|
|
}
|
|
|
|
// Add organizer if field exists
|
|
const organizerInput = await context.$('input[name="organizer[Organizer]"], #organizer-name');
|
|
if (organizerInput) {
|
|
await organizerInput.fill(eventData.organizer);
|
|
}
|
|
}
|
|
|
|
async function submitEventForm(page) {
|
|
const iframe = await page.$('iframe#tec-create-frame');
|
|
const context = iframe ? await iframe.contentFrame() : page;
|
|
|
|
// Find and click submit button
|
|
const submitButton = await context.$('button[type="submit"], input[type="submit"], .tribe-submit-event-button');
|
|
if (submitButton) {
|
|
await submitButton.click();
|
|
}
|
|
}
|
|
|
|
async function takeScreenshot(page, name) {
|
|
const screenshotDir = path.join(__dirname, '../../screenshots');
|
|
await fs.mkdir(screenshotDir, { recursive: true });
|
|
await page.screenshot({
|
|
path: path.join(screenshotDir, `${name}-${Date.now()}.png`),
|
|
fullPage: true
|
|
});
|
|
}
|
|
|
|
// Test suite
|
|
test.describe('HVAC Final Comprehensive Test Suite', () => {
|
|
test.setTimeout(TEST_TIMEOUT);
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
// Set viewport
|
|
await page.setViewportSize({ width: 1280, height: 720 });
|
|
});
|
|
|
|
test.describe('Authentication Tests', () => {
|
|
test('should login successfully as trainer', async ({ page }) => {
|
|
await page.goto(`${BASE_URL}/wp-login.php`);
|
|
await page.fill('#user_login', TEST_USER.email);
|
|
await page.fill('#user_pass', TEST_USER.password);
|
|
await page.click('#wp-submit');
|
|
|
|
// Verify redirect to dashboard
|
|
await expect(page).toHaveURL(/trainer\/dashboard/, { timeout: 10000 });
|
|
|
|
// Verify dashboard elements
|
|
await expect(page.locator('.hvac-dashboard-header')).toBeVisible();
|
|
await takeScreenshot(page, 'dashboard-after-login');
|
|
});
|
|
|
|
test('should maintain session across pages', async ({ page }) => {
|
|
await login(page);
|
|
|
|
// Navigate to different pages
|
|
await page.goto(`${BASE_URL}/trainer/certificate-reports/`);
|
|
await expect(page.locator('.hvac-page-header, h1')).toBeVisible();
|
|
|
|
await page.goto(`${BASE_URL}/trainer/profile/`);
|
|
await expect(page.locator('.hvac-profile-content, .hvac-page-header')).toBeVisible();
|
|
|
|
// Verify still logged in
|
|
const logoutLink = await page.$('a[href*="logout"]');
|
|
expect(logoutLink).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
test.describe('Event Creation Tests', () => {
|
|
test('should display event creation form with all fields', async ({ page }) => {
|
|
await login(page);
|
|
await navigateToEventCreation(page);
|
|
|
|
// Check for form presence
|
|
const formExists = await page.locator('.hvac-event-form-wrapper, iframe#tec-create-frame').isVisible();
|
|
expect(formExists).toBeTruthy();
|
|
|
|
// If iframe, check inside iframe
|
|
const iframe = await page.$('iframe#tec-create-frame');
|
|
if (iframe) {
|
|
const frame = await iframe.contentFrame();
|
|
|
|
// Check for required fields
|
|
await expect(frame.locator('input[name="post_title"], #tribe-events-title')).toBeVisible();
|
|
await expect(frame.locator('#tinyMCE, #content, textarea[name="post_content"]')).toBeVisible();
|
|
}
|
|
|
|
await takeScreenshot(page, 'event-creation-form');
|
|
});
|
|
|
|
test('should create event with minimal required fields', async ({ page }) => {
|
|
await login(page);
|
|
await navigateToEventCreation(page);
|
|
|
|
// Fill minimal required fields
|
|
await fillEventForm(page, {
|
|
title: `Minimal Test Event ${Date.now()}`,
|
|
description: 'Minimal test event description'
|
|
});
|
|
|
|
await takeScreenshot(page, 'event-form-filled-minimal');
|
|
|
|
// Submit form
|
|
await submitEventForm(page);
|
|
|
|
// Wait for success indication
|
|
await page.waitForTimeout(3000);
|
|
|
|
// Check for success message or redirect
|
|
const currentUrl = page.url();
|
|
const hasSuccess = currentUrl.includes('success') ||
|
|
currentUrl.includes('event') ||
|
|
currentUrl.includes('dashboard');
|
|
|
|
expect(hasSuccess).toBeTruthy();
|
|
await takeScreenshot(page, 'event-created-minimal');
|
|
});
|
|
|
|
test('should create event with all fields', async ({ page }) => {
|
|
await login(page);
|
|
await navigateToEventCreation(page);
|
|
|
|
// Fill all fields
|
|
await fillEventForm(page, TEST_EVENT);
|
|
|
|
await takeScreenshot(page, 'event-form-filled-complete');
|
|
|
|
// Submit form
|
|
await submitEventForm(page);
|
|
|
|
// Wait for processing
|
|
await page.waitForTimeout(3000);
|
|
|
|
await takeScreenshot(page, 'event-created-complete');
|
|
});
|
|
|
|
test('should validate required fields', async ({ page }) => {
|
|
await login(page);
|
|
await navigateToEventCreation(page);
|
|
|
|
// Try to submit without filling required fields
|
|
await submitEventForm(page);
|
|
|
|
// Check for validation messages
|
|
await page.waitForTimeout(2000);
|
|
|
|
const iframe = await page.$('iframe#tec-create-frame');
|
|
const context = iframe ? await iframe.contentFrame() : page;
|
|
|
|
// Look for error messages
|
|
const errorVisible = await context.locator('.error, .tribe-error, .validation-error').count() > 0;
|
|
|
|
await takeScreenshot(page, 'validation-errors');
|
|
});
|
|
});
|
|
|
|
test.describe('Event Editing Tests', () => {
|
|
test('should navigate to event list', async ({ page }) => {
|
|
await login(page);
|
|
await page.goto(`${BASE_URL}/trainer/events/`);
|
|
|
|
// Check for event list
|
|
await expect(page.locator('.hvac-events-list, .tribe-events-list, table')).toBeVisible();
|
|
await takeScreenshot(page, 'event-list');
|
|
});
|
|
|
|
test('should open event for editing', async ({ page }) => {
|
|
await login(page);
|
|
await page.goto(`${BASE_URL}/trainer/events/`);
|
|
|
|
// Find edit link for first event
|
|
const editLink = await page.$('a[href*="edit"], .edit-link, .tribe-edit-link');
|
|
if (editLink) {
|
|
await editLink.click();
|
|
await page.waitForTimeout(3000);
|
|
|
|
// Check if edit form loaded
|
|
const formVisible = await page.locator('.hvac-event-form-wrapper, iframe, form').isVisible();
|
|
expect(formVisible).toBeTruthy();
|
|
|
|
await takeScreenshot(page, 'event-edit-form');
|
|
}
|
|
});
|
|
|
|
test('should update event title', async ({ page }) => {
|
|
await login(page);
|
|
await page.goto(`${BASE_URL}/trainer/events/`);
|
|
|
|
// Find and click edit link
|
|
const editLink = await page.$('a[href*="edit"], .edit-link');
|
|
if (editLink) {
|
|
await editLink.click();
|
|
await page.waitForTimeout(3000);
|
|
|
|
// Update title
|
|
const iframe = await page.$('iframe');
|
|
const context = iframe ? await iframe.contentFrame() : page;
|
|
|
|
const titleInput = await context.$('input[name="post_title"], #tribe-events-title');
|
|
if (titleInput) {
|
|
await titleInput.fill(`Updated Event ${Date.now()}`);
|
|
await submitEventForm(page);
|
|
await page.waitForTimeout(3000);
|
|
|
|
await takeScreenshot(page, 'event-updated');
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
test.describe('Navigation Tests', () => {
|
|
test('should have working navigation menu', async ({ page }) => {
|
|
await login(page);
|
|
|
|
// Check for navigation menu
|
|
await expect(page.locator('.hvac-trainer-nav, .hvac-nav-menu')).toBeVisible();
|
|
|
|
// Test navigation links
|
|
const navLinks = [
|
|
{ selector: 'a[href*="dashboard"]', url: /dashboard/ },
|
|
{ selector: 'a[href*="certificate"]', url: /certificate/ },
|
|
{ selector: 'a[href*="profile"]', url: /profile/ }
|
|
];
|
|
|
|
for (const link of navLinks) {
|
|
const element = await page.$(link.selector);
|
|
if (element) {
|
|
const href = await element.getAttribute('href');
|
|
expect(href).toBeTruthy();
|
|
}
|
|
}
|
|
|
|
await takeScreenshot(page, 'navigation-menu');
|
|
});
|
|
|
|
test('should have mobile-responsive navigation', async ({ page }) => {
|
|
// Set mobile viewport
|
|
await page.setViewportSize({ width: 375, height: 667 });
|
|
|
|
await login(page);
|
|
|
|
// Check for hamburger menu
|
|
const hamburger = await page.$('.hvac-menu-toggle, .menu-toggle, .hamburger');
|
|
|
|
if (hamburger) {
|
|
await hamburger.click();
|
|
await page.waitForTimeout(500);
|
|
|
|
// Check if menu opened
|
|
const menuVisible = await page.locator('.hvac-nav-menu.mobile-active, .menu-open').isVisible();
|
|
|
|
await takeScreenshot(page, 'mobile-navigation-open');
|
|
}
|
|
});
|
|
});
|
|
|
|
test.describe('Cross-Browser Tests', () => {
|
|
['chromium', 'firefox', 'webkit'].forEach(browserName => {
|
|
test(`should work in ${browserName}`, async ({ browser }) => {
|
|
const context = await browser.newContext();
|
|
const page = await context.newPage();
|
|
|
|
await page.goto(`${BASE_URL}/wp-login.php`);
|
|
await page.fill('#user_login', TEST_USER.email);
|
|
await page.fill('#user_pass', TEST_USER.password);
|
|
await page.click('#wp-submit');
|
|
|
|
// Wait for dashboard
|
|
await page.waitForURL(/trainer\/dashboard/, { timeout: 15000 });
|
|
|
|
// Verify page loaded
|
|
const dashboardVisible = await page.locator('.hvac-dashboard-header, h1').isVisible();
|
|
expect(dashboardVisible).toBeTruthy();
|
|
|
|
await page.screenshot({
|
|
path: path.join(__dirname, `../../screenshots/cross-browser-${browserName}-${Date.now()}.png`)
|
|
});
|
|
|
|
await context.close();
|
|
});
|
|
});
|
|
});
|
|
|
|
test.describe('Performance Tests', () => {
|
|
test('should load dashboard within acceptable time', async ({ page }) => {
|
|
const startTime = Date.now();
|
|
|
|
await login(page);
|
|
|
|
const loadTime = Date.now() - startTime;
|
|
console.log(`Dashboard load time: ${loadTime}ms`);
|
|
|
|
// Should load within 10 seconds
|
|
expect(loadTime).toBeLessThan(10000);
|
|
});
|
|
|
|
test('should handle rapid navigation', async ({ page }) => {
|
|
await login(page);
|
|
|
|
// Rapidly navigate between pages
|
|
const pages = [
|
|
'/trainer/dashboard/',
|
|
'/trainer/events/',
|
|
'/trainer/certificate-reports/',
|
|
'/trainer/profile/'
|
|
];
|
|
|
|
for (const pagePath of pages) {
|
|
await page.goto(`${BASE_URL}${pagePath}`);
|
|
await page.waitForLoadState('domcontentloaded');
|
|
}
|
|
|
|
// Should not crash or hang
|
|
const finalPageLoaded = await page.locator('body').isVisible();
|
|
expect(finalPageLoaded).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
test.describe('Accessibility Tests', () => {
|
|
test('should have proper ARIA labels', async ({ page }) => {
|
|
await login(page);
|
|
|
|
// Check for ARIA labels on interactive elements
|
|
const buttons = await page.$$('button, a[role="button"]');
|
|
|
|
for (const button of buttons.slice(0, 5)) { // Check first 5 buttons
|
|
const ariaLabel = await button.getAttribute('aria-label');
|
|
const text = await button.textContent();
|
|
|
|
// Should have either aria-label or text content
|
|
expect(ariaLabel || text).toBeTruthy();
|
|
}
|
|
});
|
|
|
|
test('should support keyboard navigation', async ({ page }) => {
|
|
await login(page);
|
|
|
|
// Test tab navigation
|
|
await page.keyboard.press('Tab');
|
|
await page.keyboard.press('Tab');
|
|
await page.keyboard.press('Tab');
|
|
|
|
// Check if an element has focus
|
|
const focusedElement = await page.evaluate(() => document.activeElement.tagName);
|
|
expect(focusedElement).not.toBe('BODY');
|
|
});
|
|
});
|
|
});
|
|
|
|
// Export test configuration
|
|
module.exports = {
|
|
testDir: __dirname,
|
|
timeout: TEST_TIMEOUT,
|
|
retries: 1,
|
|
workers: 1,
|
|
use: {
|
|
baseURL: BASE_URL,
|
|
screenshot: 'only-on-failure',
|
|
video: 'retain-on-failure',
|
|
trace: 'on-first-retry'
|
|
}
|
|
}; |