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>
775 lines
No EOL
31 KiB
JavaScript
775 lines
No EOL
31 KiB
JavaScript
/**
|
|
* Theme Independence Test Suite
|
|
*
|
|
* Tests that the HVAC Community Events plugin works independently of themes:
|
|
* - Layout consistency across different themes
|
|
* - Asset loading without theme dependencies
|
|
* - Template fallback mechanisms
|
|
* - CSS isolation verification
|
|
* - No hardcoded theme-specific code
|
|
* - Responsive design consistency
|
|
*
|
|
* @package HVAC_Community_Events
|
|
* @version 3.0.0
|
|
* @created 2025-08-20
|
|
*/
|
|
|
|
const { test, expect, authHelpers } = require('../helpers/auth-fixtures');
|
|
const path = require('path');
|
|
|
|
// Test configuration
|
|
const BASE_URL = process.env.UPSKILL_STAGING_URL || 'https://upskill-staging.measurequick.com';
|
|
const TEST_TIMEOUT = 90000;
|
|
|
|
// Theme-independent pages to test
|
|
const PLUGIN_PAGES = [
|
|
'/trainer/dashboard/',
|
|
'/trainer/profile/',
|
|
'/trainer/events/',
|
|
'/trainer/events/create/',
|
|
'/trainer/certificate-reports/',
|
|
'/master-trainer/master-dashboard/',
|
|
'/find-trainer/'
|
|
];
|
|
|
|
// Expected core layout elements (theme-independent)
|
|
const CORE_ELEMENTS = {
|
|
navigation: ['.hvac-trainer-nav', '.hvac-nav-menu', 'nav[class*="hvac"]'],
|
|
content: ['.hvac-page-wrapper', '.hvac-content', 'main[class*="hvac"]'],
|
|
forms: ['.hvac-form-wrapper', 'form[class*="hvac"]'],
|
|
buttons: ['.hvac-button', 'button[class*="hvac"]'],
|
|
headers: ['.hvac-page-header', '.hvac-dashboard-header']
|
|
};
|
|
|
|
// CSS properties that should be consistent regardless of theme
|
|
const LAYOUT_PROPERTIES = [
|
|
'display',
|
|
'position',
|
|
'width',
|
|
'max-width',
|
|
'padding',
|
|
'margin',
|
|
'flex-direction',
|
|
'grid-template-columns'
|
|
];
|
|
|
|
// Helper functions
|
|
async function loginAsTrainer(page) {
|
|
await authHelpers.loginAs(page, 'trainer');
|
|
}
|
|
|
|
async function getCurrentTheme(page) {
|
|
return await page.evaluate(() => {
|
|
// Try to determine active theme from various indicators
|
|
const body = document.body;
|
|
const bodyClasses = Array.from(body.classList);
|
|
|
|
// Check for theme-specific body classes
|
|
const themeClasses = bodyClasses.filter(cls =>
|
|
cls.includes('theme-') ||
|
|
cls.includes('astra') ||
|
|
cls.includes('twentytwenty') ||
|
|
cls.includes('genesis') ||
|
|
cls.includes('divi') ||
|
|
cls.includes('avada')
|
|
);
|
|
|
|
// Check for theme-specific stylesheets
|
|
const stylesheets = Array.from(document.querySelectorAll('link[rel="stylesheet"]'))
|
|
.map(link => link.href)
|
|
.filter(href => href.includes('themes/'));
|
|
|
|
const themeFromStylesheet = stylesheets.length > 0 ?
|
|
stylesheets[0].match(/themes\/([^\/]+)/)?.[1] : 'unknown';
|
|
|
|
return {
|
|
bodyClasses: themeClasses,
|
|
detectedTheme: themeFromStylesheet,
|
|
totalStylesheets: stylesheets.length
|
|
};
|
|
});
|
|
}
|
|
|
|
async function checkElementConsistency(page, selectors) {
|
|
const elements = [];
|
|
|
|
for (const selector of selectors) {
|
|
const element = await page.$(selector);
|
|
if (element) {
|
|
const styles = await element.evaluate((el, properties) => {
|
|
const computed = window.getComputedStyle(el);
|
|
const result = {};
|
|
properties.forEach(prop => {
|
|
result[prop] = computed.getPropertyValue(prop);
|
|
});
|
|
return result;
|
|
}, LAYOUT_PROPERTIES);
|
|
|
|
const boundingBox = await element.boundingBox();
|
|
|
|
elements.push({
|
|
selector,
|
|
styles,
|
|
boundingBox,
|
|
isVisible: await element.isVisible()
|
|
});
|
|
}
|
|
}
|
|
|
|
return elements;
|
|
}
|
|
|
|
async function analyzePluginAssets(page) {
|
|
return await page.evaluate(() => {
|
|
const assets = {
|
|
hvacCss: [],
|
|
hvacJs: [],
|
|
themeCss: [],
|
|
themeJs: [],
|
|
conflicts: []
|
|
};
|
|
|
|
// Analyze CSS files
|
|
Array.from(document.querySelectorAll('link[rel="stylesheet"]')).forEach(link => {
|
|
if (link.href.includes('hvac') || link.href.includes('community-events')) {
|
|
assets.hvacCss.push(link.href);
|
|
} else if (link.href.includes('themes/')) {
|
|
assets.themeCss.push(link.href);
|
|
}
|
|
});
|
|
|
|
// Analyze JS files
|
|
Array.from(document.querySelectorAll('script[src]')).forEach(script => {
|
|
if (script.src.includes('hvac') || script.src.includes('community-events')) {
|
|
assets.hvacJs.push(script.src);
|
|
} else if (script.src.includes('themes/')) {
|
|
assets.themeJs.push(script.src);
|
|
}
|
|
});
|
|
|
|
// Check for CSS conflicts
|
|
const hvacElements = document.querySelectorAll('[class*="hvac"]');
|
|
hvacElements.forEach(el => {
|
|
const computed = window.getComputedStyle(el);
|
|
|
|
// Check if theme styles are overriding plugin styles
|
|
const backgroundImage = computed.backgroundImage;
|
|
const fontFamily = computed.fontFamily;
|
|
|
|
if (backgroundImage !== 'none' && !backgroundImage.includes('hvac')) {
|
|
assets.conflicts.push({
|
|
element: el.className,
|
|
property: 'background-image',
|
|
value: backgroundImage
|
|
});
|
|
}
|
|
});
|
|
|
|
return assets;
|
|
});
|
|
}
|
|
|
|
async function checkResponsiveConsistency(page, breakpoints = [1200, 768, 480]) {
|
|
const results = [];
|
|
|
|
for (const breakpoint of breakpoints) {
|
|
await page.setViewportSize({ width: breakpoint, height: 720 });
|
|
await page.waitForTimeout(1000);
|
|
|
|
// Check navigation visibility and behavior
|
|
const navState = await page.evaluate(() => {
|
|
const nav = document.querySelector('.hvac-trainer-nav, .hvac-nav-menu');
|
|
const hamburger = document.querySelector('.hvac-menu-toggle, .menu-toggle');
|
|
|
|
return {
|
|
navVisible: nav ? window.getComputedStyle(nav).display !== 'none' : false,
|
|
hamburgerVisible: hamburger ? window.getComputedStyle(hamburger).display !== 'none' : false,
|
|
navPosition: nav ? window.getComputedStyle(nav).position : 'none'
|
|
};
|
|
});
|
|
|
|
// Check content layout
|
|
const contentState = await page.evaluate(() => {
|
|
const container = document.querySelector('.hvac-page-wrapper, .hvac-content, main');
|
|
const sidebar = document.querySelector('.sidebar, .widget-area');
|
|
|
|
return {
|
|
containerWidth: container ? container.offsetWidth : 0,
|
|
hasFlexLayout: container ? window.getComputedStyle(container).display.includes('flex') : false,
|
|
sidebarVisible: sidebar ? window.getComputedStyle(sidebar).display !== 'none' : false
|
|
};
|
|
});
|
|
|
|
results.push({
|
|
breakpoint,
|
|
navigation: navState,
|
|
content: contentState
|
|
});
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
async function takeThemeScreenshot(page, name, theme) {
|
|
const screenshotDir = path.join(__dirname, '../../screenshots/theme-independence');
|
|
await require('fs').promises.mkdir(screenshotDir, { recursive: true });
|
|
await page.screenshot({
|
|
path: path.join(screenshotDir, `${name}-${theme}-${Date.now()}.png`),
|
|
fullPage: true
|
|
});
|
|
}
|
|
|
|
test.describe('Theme Independence Tests', () => {
|
|
test.setTimeout(TEST_TIMEOUT);
|
|
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.setViewportSize({ width: 1280, height: 720 });
|
|
// Login before each test to ensure authenticated access
|
|
await authHelpers.loginAs(page, 'trainer');
|
|
});
|
|
|
|
test.describe('Layout Consistency Tests', () => {
|
|
test('should maintain consistent layout across plugin pages', async ({ page }) => {
|
|
|
|
const currentTheme = await getCurrentTheme(page);
|
|
console.log('Current theme detected:', currentTheme);
|
|
|
|
const pageLayouts = {};
|
|
|
|
// Test each plugin page
|
|
for (const pagePath of PLUGIN_PAGES) {
|
|
try {
|
|
await page.goto(`${BASE_URL}${pagePath}`, { timeout: 15000 });
|
|
await page.waitForLoadState('domcontentloaded');
|
|
|
|
// Check for core plugin elements
|
|
const elements = await checkElementConsistency(page, [
|
|
'.hvac-page-wrapper',
|
|
'.hvac-content',
|
|
'.hvac-nav-menu',
|
|
'main'
|
|
]);
|
|
|
|
pageLayouts[pagePath] = elements;
|
|
|
|
// Verify page has plugin content wrapper
|
|
const hasWrapper = await page.locator('.hvac-page-wrapper, .hvac-content, main').count() > 0;
|
|
expect(hasWrapper).toBeTruthy();
|
|
|
|
console.log(`Layout check for ${pagePath}: OK`);
|
|
|
|
} catch (error) {
|
|
console.log(`Layout check for ${pagePath} failed:`, error.message);
|
|
}
|
|
}
|
|
|
|
// Verify layout consistency
|
|
const wrapperElements = Object.values(pageLayouts)
|
|
.map(layout => layout.find(el => el.selector === '.hvac-page-wrapper'))
|
|
.filter(Boolean);
|
|
|
|
if (wrapperElements.length > 1) {
|
|
const firstLayout = wrapperElements[0];
|
|
const inconsistencies = wrapperElements.slice(1).filter(layout => {
|
|
return layout.styles.display !== firstLayout.styles.display ||
|
|
layout.styles.maxWidth !== firstLayout.styles.maxWidth;
|
|
});
|
|
|
|
expect(inconsistencies.length).toBeLessThan(wrapperElements.length / 2);
|
|
}
|
|
|
|
await takeThemeScreenshot(page, 'layout-consistency', currentTheme.detectedTheme);
|
|
});
|
|
|
|
test('should use theme-independent container widths', async ({ page }) => {
|
|
|
|
const containerSpecs = [];
|
|
|
|
for (const pagePath of PLUGIN_PAGES.slice(0, 3)) { // Test subset for speed
|
|
await page.goto(`${BASE_URL}${pagePath}`);
|
|
|
|
const containerInfo = await page.evaluate(() => {
|
|
const containers = document.querySelectorAll('.hvac-page-wrapper, .hvac-content, .container');
|
|
|
|
return Array.from(containers).map(container => ({
|
|
className: container.className,
|
|
offsetWidth: container.offsetWidth,
|
|
clientWidth: container.clientWidth,
|
|
computedWidth: window.getComputedStyle(container).width,
|
|
computedMaxWidth: window.getComputedStyle(container).maxWidth
|
|
}));
|
|
});
|
|
|
|
containerSpecs.push({
|
|
page: pagePath,
|
|
containers: containerInfo
|
|
});
|
|
}
|
|
|
|
// Check for consistent max-width usage
|
|
const maxWidths = containerSpecs.flatMap(spec =>
|
|
spec.containers.map(c => c.computedMaxWidth)
|
|
).filter(w => w !== 'none');
|
|
|
|
if (maxWidths.length > 0) {
|
|
const uniqueMaxWidths = [...new Set(maxWidths)];
|
|
console.log('Container max-widths found:', uniqueMaxWidths);
|
|
|
|
// Should use consistent max-width values
|
|
expect(uniqueMaxWidths.length).toBeLessThan(4); // Allow some variation
|
|
}
|
|
});
|
|
|
|
test('should handle missing theme support gracefully', async ({ page }) => {
|
|
await page.goto(`${BASE_URL}/trainer/dashboard/`);
|
|
|
|
// Simulate theme support removal
|
|
await page.evaluate(() => {
|
|
// Remove theme support indicators
|
|
const themeElements = document.querySelectorAll('[class*="theme-"], [class*="astra"]');
|
|
themeElements.forEach(el => {
|
|
el.classList.forEach(cls => {
|
|
if (cls.includes('theme-') || cls.includes('astra')) {
|
|
el.classList.remove(cls);
|
|
}
|
|
});
|
|
});
|
|
|
|
// Remove theme stylesheets temporarily
|
|
const themeStyles = document.querySelectorAll('link[href*="themes/"]');
|
|
themeStyles.forEach(link => {
|
|
link.disabled = true;
|
|
});
|
|
});
|
|
|
|
await page.waitForTimeout(1000);
|
|
|
|
// Check if plugin still functions
|
|
const pluginFunctional = await page.evaluate(() => {
|
|
const navMenu = document.querySelector('.hvac-nav-menu, .hvac-trainer-nav');
|
|
const content = document.querySelector('.hvac-content, .hvac-page-wrapper');
|
|
|
|
return {
|
|
hasNavigation: !!navMenu,
|
|
hasContent: !!content,
|
|
contentVisible: content ? window.getComputedStyle(content).display !== 'none' : false
|
|
};
|
|
});
|
|
|
|
expect(pluginFunctional.hasContent).toBeTruthy();
|
|
console.log('Plugin graceful degradation:', pluginFunctional);
|
|
});
|
|
});
|
|
|
|
test.describe('Asset Independence Tests', () => {
|
|
test('should load plugin assets independently', async ({ page }) => {
|
|
await page.goto(`${BASE_URL}/trainer/dashboard/`);
|
|
|
|
const assetAnalysis = await analyzePluginAssets(page);
|
|
|
|
// Should have plugin-specific assets
|
|
expect(assetAnalysis.hvacCss.length).toBeGreaterThan(0);
|
|
console.log('HVAC CSS files:', assetAnalysis.hvacCss.length);
|
|
console.log('Theme CSS files:', assetAnalysis.themeCss.length);
|
|
|
|
// Check for asset conflicts
|
|
if (assetAnalysis.conflicts.length > 0) {
|
|
console.log('Theme conflicts detected:', assetAnalysis.conflicts);
|
|
|
|
// Should have minimal conflicts
|
|
expect(assetAnalysis.conflicts.length).toBeLessThan(5);
|
|
}
|
|
|
|
// Verify plugin assets load before theme assets
|
|
const loadOrder = await page.evaluate(() => {
|
|
const allStyles = Array.from(document.querySelectorAll('link[rel="stylesheet"]'));
|
|
const hvacIndex = allStyles.findIndex(link =>
|
|
link.href.includes('hvac') || link.href.includes('community-events')
|
|
);
|
|
const themeIndex = allStyles.findIndex(link => link.href.includes('themes/'));
|
|
|
|
return { hvacIndex, themeIndex, total: allStyles.length };
|
|
});
|
|
|
|
console.log('Asset load order:', loadOrder);
|
|
});
|
|
|
|
test('should not depend on theme-specific CSS classes', async ({ page }) => {
|
|
await page.goto(`${BASE_URL}/trainer/dashboard/`);
|
|
|
|
// Check for theme-specific dependencies
|
|
const themeDependencies = await page.evaluate(() => {
|
|
const hvacElements = document.querySelectorAll('[class*="hvac"]');
|
|
const dependencies = [];
|
|
|
|
hvacElements.forEach(el => {
|
|
const classes = Array.from(el.classList);
|
|
const themeClasses = classes.filter(cls =>
|
|
cls.includes('astra') ||
|
|
cls.includes('twentytwenty') ||
|
|
cls.includes('genesis') ||
|
|
cls.includes('theme-')
|
|
);
|
|
|
|
if (themeClasses.length > 0) {
|
|
dependencies.push({
|
|
element: el.tagName + '.' + classes.join('.'),
|
|
themeClasses
|
|
});
|
|
}
|
|
});
|
|
|
|
return dependencies;
|
|
});
|
|
|
|
// Should have minimal theme dependencies
|
|
expect(themeDependencies.length).toBeLessThan(10);
|
|
console.log('Theme class dependencies:', themeDependencies.length);
|
|
|
|
if (themeDependencies.length > 0) {
|
|
console.log('Dependencies found:', themeDependencies.slice(0, 3));
|
|
}
|
|
});
|
|
|
|
test('should handle theme stylesheet conflicts', async ({ page }) => {
|
|
await page.goto(`${BASE_URL}/trainer/dashboard/`);
|
|
|
|
// Test critical plugin elements for style conflicts
|
|
const criticalElements = [
|
|
'.hvac-nav-menu',
|
|
'.hvac-button',
|
|
'.hvac-form-wrapper',
|
|
'.hvac-page-header'
|
|
];
|
|
|
|
const styleConflicts = [];
|
|
|
|
for (const selector of criticalElements) {
|
|
const element = await page.$(selector);
|
|
if (element) {
|
|
const styles = await element.evaluate(el => {
|
|
const computed = window.getComputedStyle(el);
|
|
return {
|
|
display: computed.display,
|
|
position: computed.position,
|
|
zIndex: computed.zIndex,
|
|
fontSize: computed.fontSize,
|
|
color: computed.color
|
|
};
|
|
});
|
|
|
|
// Check for unexpected style values that might indicate conflicts
|
|
if (styles.display === 'none' && selector.includes('nav')) {
|
|
styleConflicts.push({ selector, issue: 'Navigation hidden' });
|
|
}
|
|
|
|
if (styles.zIndex === 'auto' && selector.includes('nav')) {
|
|
styleConflicts.push({ selector, issue: 'No z-index set' });
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log('Style conflicts detected:', styleConflicts.length);
|
|
expect(styleConflicts.length).toBeLessThan(3);
|
|
});
|
|
});
|
|
|
|
test.describe('Responsive Design Independence Tests', () => {
|
|
test('should maintain responsive behavior regardless of theme', async ({ page }) => {
|
|
await page.goto(`${BASE_URL}/trainer/dashboard/`);
|
|
|
|
const responsiveResults = await checkResponsiveConsistency(page);
|
|
|
|
// Verify navigation adapts correctly at all breakpoints
|
|
responsiveResults.forEach(result => {
|
|
console.log(`Breakpoint ${result.breakpoint}px:`, {
|
|
nav: result.navigation.navVisible,
|
|
hamburger: result.navigation.hamburgerVisible,
|
|
contentWidth: result.content.containerWidth
|
|
});
|
|
|
|
// At mobile breakpoints, either nav should be hidden or hamburger should be visible
|
|
if (result.breakpoint <= 768) {
|
|
const mobileNavHandled = !result.navigation.navVisible || result.navigation.hamburgerVisible;
|
|
expect(mobileNavHandled).toBeTruthy();
|
|
}
|
|
|
|
// Content should never be zero width
|
|
expect(result.content.containerWidth).toBeGreaterThan(0);
|
|
});
|
|
|
|
await takeThemeScreenshot(page, 'responsive-design', 'current');
|
|
});
|
|
|
|
test('should handle mobile navigation independently', async ({ page }) => {
|
|
await page.setViewportSize({ width: 375, height: 667 }); // Mobile viewport
|
|
|
|
await page.goto(`${BASE_URL}/trainer/dashboard/`);
|
|
|
|
// Check for mobile navigation
|
|
const mobileNav = await page.evaluate(() => {
|
|
const hamburger = document.querySelector('.hvac-menu-toggle, .menu-toggle, .hamburger');
|
|
const navMenu = document.querySelector('.hvac-nav-menu, .hvac-trainer-nav');
|
|
|
|
return {
|
|
hasHamburger: !!hamburger,
|
|
hamburgerVisible: hamburger ? window.getComputedStyle(hamburger).display !== 'none' : false,
|
|
navHidden: navMenu ? window.getComputedStyle(navMenu).display === 'none' : true
|
|
};
|
|
});
|
|
|
|
console.log('Mobile navigation state:', mobileNav);
|
|
|
|
// Should have mobile navigation solution
|
|
const hasMobileNav = mobileNav.hasHamburger || !mobileNav.navHidden;
|
|
expect(hasMobileNav).toBeTruthy();
|
|
|
|
// If hamburger exists, test functionality
|
|
if (mobileNav.hasHamburger) {
|
|
const hamburger = await page.$('.hvac-menu-toggle, .menu-toggle, .hamburger');
|
|
if (hamburger) {
|
|
await hamburger.click();
|
|
await page.waitForTimeout(500);
|
|
|
|
const menuOpened = await page.evaluate(() => {
|
|
const menu = document.querySelector('.hvac-nav-menu');
|
|
return menu ? window.getComputedStyle(menu).display !== 'none' : false;
|
|
});
|
|
|
|
expect(menuOpened).toBeTruthy();
|
|
}
|
|
}
|
|
});
|
|
|
|
test('should maintain form layout on all devices', async ({ page }) => {
|
|
|
|
const breakpoints = [1200, 768, 480];
|
|
const formResults = [];
|
|
|
|
for (const breakpoint of breakpoints) {
|
|
await page.setViewportSize({ width: breakpoint, height: 720 });
|
|
await page.goto(`${BASE_URL}/trainer/profile/edit/`);
|
|
await page.waitForTimeout(1000);
|
|
|
|
const formLayout = await page.evaluate(() => {
|
|
const form = document.querySelector('form');
|
|
const inputs = document.querySelectorAll('input, select, textarea');
|
|
|
|
if (!form) return null;
|
|
|
|
return {
|
|
formWidth: form.offsetWidth,
|
|
inputCount: inputs.length,
|
|
stackedInputs: Array.from(inputs).filter(input => {
|
|
const rect = input.getBoundingClientRect();
|
|
return rect.width > form.offsetWidth * 0.8; // Nearly full width = stacked
|
|
}).length
|
|
};
|
|
});
|
|
|
|
if (formLayout) {
|
|
formResults.push({
|
|
breakpoint,
|
|
...formLayout
|
|
});
|
|
|
|
// Form should be usable at all breakpoints
|
|
expect(formLayout.formWidth).toBeGreaterThan(200);
|
|
|
|
// At mobile breakpoints, inputs should be mostly stacked
|
|
if (breakpoint <= 768) {
|
|
const stackedRatio = formLayout.stackedInputs / formLayout.inputCount;
|
|
expect(stackedRatio).toBeGreaterThan(0.5);
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log('Form responsive results:', formResults);
|
|
});
|
|
});
|
|
|
|
test.describe('Template Fallback Tests', () => {
|
|
test('should provide default templates when theme lacks support', async ({ page }) => {
|
|
|
|
// Test pages that might not have theme support
|
|
const fallbackPages = [
|
|
'/trainer/certificate-reports/',
|
|
'/trainer/events/create/',
|
|
'/trainer/organizer/manage/'
|
|
];
|
|
|
|
for (const pagePath of fallbackPages) {
|
|
await page.goto(`${BASE_URL}${pagePath}`);
|
|
|
|
// Check if page loads with plugin template
|
|
const hasTemplate = await page.evaluate(() => {
|
|
return !!(
|
|
document.querySelector('.hvac-page-wrapper') ||
|
|
document.querySelector('.hvac-template') ||
|
|
document.body.className.includes('hvac-page')
|
|
);
|
|
});
|
|
|
|
expect(hasTemplate).toBeTruthy();
|
|
console.log(`Template fallback for ${pagePath}: OK`);
|
|
|
|
// Check for WordPress integration
|
|
const hasWordPressElements = await page.evaluate(() => {
|
|
return !!(
|
|
document.querySelector('header, .site-header') &&
|
|
document.querySelector('footer, .site-footer')
|
|
);
|
|
});
|
|
|
|
expect(hasWordPressElements).toBeTruthy();
|
|
}
|
|
});
|
|
|
|
test('should handle missing theme functions gracefully', async ({ page }) => {
|
|
await page.goto(`${BASE_URL}/trainer/dashboard/`);
|
|
|
|
// Simulate missing theme functions
|
|
const errorCount = await page.evaluate(() => {
|
|
let errors = 0;
|
|
|
|
// Override console.error to catch theme-related errors
|
|
const originalError = console.error;
|
|
console.error = function(...args) {
|
|
const message = args.join(' ');
|
|
if (message.includes('theme') || message.includes('undefined function')) {
|
|
errors++;
|
|
}
|
|
originalError.apply(console, args);
|
|
};
|
|
|
|
// Try to trigger theme function calls
|
|
try {
|
|
// Simulate missing theme support checks
|
|
if (typeof window.themeSupports !== 'undefined') {
|
|
window.themeSupports.customLogo();
|
|
}
|
|
} catch (e) {
|
|
if (e.message.includes('theme')) {
|
|
errors++;
|
|
}
|
|
}
|
|
|
|
return errors;
|
|
});
|
|
|
|
// Should handle missing theme functions without errors
|
|
expect(errorCount).toBeLessThan(3);
|
|
console.log('Theme function errors:', errorCount);
|
|
});
|
|
|
|
test('should maintain functionality with minimal theme support', async ({ page }) => {
|
|
|
|
// Test core functionality without theme enhancements
|
|
const coreFeatures = [
|
|
{
|
|
name: 'Navigation',
|
|
test: async () => {
|
|
await page.goto(`${BASE_URL}/trainer/dashboard/`);
|
|
return await page.locator('.hvac-nav-menu, nav').count() > 0;
|
|
}
|
|
},
|
|
{
|
|
name: 'Forms',
|
|
test: async () => {
|
|
await page.goto(`${BASE_URL}/trainer/profile/edit/`);
|
|
return await page.locator('form').count() > 0;
|
|
}
|
|
},
|
|
{
|
|
name: 'Content Display',
|
|
test: async () => {
|
|
await page.goto(`${BASE_URL}/trainer/events/`);
|
|
return await page.locator('.hvac-content, main').count() > 0;
|
|
}
|
|
}
|
|
];
|
|
|
|
for (const feature of coreFeatures) {
|
|
const works = await feature.test();
|
|
expect(works).toBeTruthy();
|
|
console.log(`Core feature '${feature.name}' working:`, works);
|
|
}
|
|
});
|
|
});
|
|
|
|
test.describe('CSS Isolation Tests', () => {
|
|
test('should not interfere with theme styles', async ({ page }) => {
|
|
await page.goto(`${BASE_URL}/`); // Homepage - theme territory
|
|
|
|
// Check if plugin CSS affects theme elements
|
|
const themeInterference = await page.evaluate(() => {
|
|
const themeElements = document.querySelectorAll('header, footer, .site-main, .content-area');
|
|
const issues = [];
|
|
|
|
themeElements.forEach(el => {
|
|
const computed = window.getComputedStyle(el);
|
|
|
|
// Check for unexpected plugin-style properties
|
|
if (computed.backgroundColor && computed.backgroundColor.includes('hvac')) {
|
|
issues.push('HVAC background color on theme element');
|
|
}
|
|
|
|
if (computed.fontFamily && computed.fontFamily.includes('HVAC')) {
|
|
issues.push('HVAC font on theme element');
|
|
}
|
|
});
|
|
|
|
return issues;
|
|
});
|
|
|
|
expect(themeInterference.length).toBeLessThan(2);
|
|
console.log('Theme interference issues:', themeInterference.length);
|
|
});
|
|
|
|
test('should scope plugin styles correctly', async ({ page }) => {
|
|
await page.goto(`${BASE_URL}/trainer/dashboard/`);
|
|
|
|
// Check CSS specificity and scoping
|
|
const scopingAnalysis = await page.evaluate(() => {
|
|
const hvacElements = document.querySelectorAll('[class*="hvac"]');
|
|
const properlyScoped = [];
|
|
const unscoped = [];
|
|
|
|
hvacElements.forEach(el => {
|
|
const classes = Array.from(el.classList);
|
|
const hasHvacClass = classes.some(cls => cls.startsWith('hvac-'));
|
|
|
|
if (hasHvacClass) {
|
|
properlyScoped.push(el.tagName);
|
|
} else {
|
|
unscoped.push(el.tagName);
|
|
}
|
|
});
|
|
|
|
return {
|
|
properlyScoped: properlyScoped.length,
|
|
unscoped: unscoped.length,
|
|
scopingRatio: properlyScoped.length / (properlyScoped.length + unscoped.length)
|
|
};
|
|
});
|
|
|
|
// Should have good scoping ratio
|
|
expect(scopingAnalysis.scopingRatio).toBeGreaterThan(0.7);
|
|
console.log('CSS scoping analysis:', scopingAnalysis);
|
|
});
|
|
});
|
|
});
|
|
|
|
// Export theme independence test configuration
|
|
module.exports = {
|
|
testDir: __dirname,
|
|
timeout: TEST_TIMEOUT,
|
|
retries: 1,
|
|
workers: 1, // Sequential for consistent testing
|
|
use: {
|
|
baseURL: BASE_URL,
|
|
screenshot: 'only-on-failure',
|
|
video: 'retain-on-failure',
|
|
trace: 'on-first-retry'
|
|
}
|
|
}; |