upskill-event-manager/tests/framework/base/BasePage.js
Ben 7c9ca65cf2
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
feat: add comprehensive test framework and test files
- 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>
2025-08-29 23:23:26 -03:00

345 lines
No EOL
9.5 KiB
JavaScript

/**
* Base Page Object - Foundation for all page objects
* Provides common functionality for WordPress pages
*/
const { getBrowserManager } = require('../browser/BrowserManager');
class BasePage {
constructor(page = null) {
this.page = page || getBrowserManager().getCurrentPage();
this.url = '';
this.title = '';
this.selectors = {};
}
/**
* Navigate to this page
* @param {Object} options - Navigation options
* @returns {Promise<void>}
*/
async navigate(options = {}) {
if (!this.url) {
throw new Error('Page URL not defined');
}
await this.page.goto(this.url, {
waitUntil: 'networkidle',
timeout: 30000,
...options
});
await this.waitForPageLoad();
}
/**
* Wait for page to be loaded and ready
* @returns {Promise<void>}
*/
async waitForPageLoad() {
// Wait for document ready
await this.page.waitForLoadState('domcontentloaded');
// Wait for any WordPress-specific loading
await this.waitForWordPressReady();
// Wait for any page-specific loading
await this.waitForPageReady();
}
/**
* Wait for WordPress-specific elements to be ready
* @returns {Promise<void>}
*/
async waitForWordPressReady() {
try {
// Wait for WordPress admin bar or body class
await this.page.waitForSelector('body.logged-in, body.wp-core-ui, #wpadminbar', {
timeout: 10000
});
} catch (error) {
// Not a WordPress page or user not logged in - continue
}
// Wait for jQuery if present
try {
await this.page.waitForFunction(() =>
window.jQuery !== undefined || window.$ !== undefined,
{ timeout: 5000 }
);
} catch (error) {
// jQuery not present - continue
}
}
/**
* Wait for page-specific elements to be ready
* Override in subclasses for page-specific waiting
* @returns {Promise<void>}
*/
async waitForPageReady() {
// Override in subclasses
}
/**
* Check if element exists
* @param {string} selector - CSS selector
* @returns {Promise<boolean>}
*/
async hasElement(selector) {
try {
const element = await this.page.$(selector);
return element !== null;
} catch (error) {
return false;
}
}
/**
* Wait for element to be visible
* @param {string} selector - CSS selector
* @param {number} timeout - Timeout in milliseconds
* @returns {Promise<void>}
*/
async waitForElement(selector, timeout = 30000) {
await this.page.waitForSelector(selector, {
visible: true,
timeout
});
}
/**
* Wait for element to be hidden/removed
* @param {string} selector - CSS selector
* @param {number} timeout - Timeout in milliseconds
* @returns {Promise<void>}
*/
async waitForElementHidden(selector, timeout = 30000) {
await this.page.waitForSelector(selector, {
hidden: true,
timeout
});
}
/**
* Click element with retry and wait
* @param {string} selector - CSS selector
* @param {Object} options - Click options
* @returns {Promise<void>}
*/
async clickElement(selector, options = {}) {
await this.waitForElement(selector);
// Scroll element into view
await this.page.locator(selector).scrollIntoViewIfNeeded();
// Wait for element to be stable
await this.page.locator(selector).waitFor({ state: 'visible' });
// Click with retry
await this.page.click(selector, {
timeout: 10000,
...options
});
}
/**
* Fill input field with validation
* @param {string} selector - CSS selector
* @param {string} value - Value to fill
* @param {Object} options - Fill options
* @returns {Promise<void>}
*/
async fillField(selector, value, options = {}) {
await this.waitForElement(selector);
// Clear existing content
await this.page.fill(selector, '', { timeout: 10000 });
// Fill with new value
await this.page.fill(selector, value, {
timeout: 10000,
...options
});
// Verify the value was set
const actualValue = await this.page.inputValue(selector);
if (actualValue !== value) {
throw new Error(`Failed to fill field ${selector}. Expected: ${value}, Got: ${actualValue}`);
}
}
/**
* Select option from dropdown
* @param {string} selector - CSS selector
* @param {string|Object} option - Option value or object with label/value
* @returns {Promise<void>}
*/
async selectOption(selector, option) {
await this.waitForElement(selector);
if (typeof option === 'string') {
await this.page.selectOption(selector, option);
} else {
await this.page.selectOption(selector, {
label: option.label,
value: option.value
});
}
}
/**
* Get text content of element
* @param {string} selector - CSS selector
* @returns {Promise<string>}
*/
async getElementText(selector) {
await this.waitForElement(selector);
return await this.page.textContent(selector);
}
/**
* Get attribute value of element
* @param {string} selector - CSS selector
* @param {string} attribute - Attribute name
* @returns {Promise<string|null>}
*/
async getElementAttribute(selector, attribute) {
await this.waitForElement(selector);
return await this.page.getAttribute(selector, attribute);
}
/**
* Check if element is visible
* @param {string} selector - CSS selector
* @returns {Promise<boolean>}
*/
async isElementVisible(selector) {
try {
return await this.page.isVisible(selector);
} catch (error) {
return false;
}
}
/**
* Check if element is enabled
* @param {string} selector - CSS selector
* @returns {Promise<boolean>}
*/
async isElementEnabled(selector) {
try {
return await this.page.isEnabled(selector);
} catch (error) {
return false;
}
}
/**
* Wait for page URL to match pattern
* @param {RegExp|string} pattern - URL pattern to match
* @param {number} timeout - Timeout in milliseconds
* @returns {Promise<void>}
*/
async waitForUrl(pattern, timeout = 30000) {
await this.page.waitForURL(pattern, { timeout });
}
/**
* Get current page URL
* @returns {string}
*/
getCurrentUrl() {
return this.page.url();
}
/**
* Get page title
* @returns {Promise<string>}
*/
async getPageTitle() {
return await this.page.title();
}
/**
* Take screenshot of current page
* @param {string} filename - Screenshot filename
* @returns {Promise<string>} Path to screenshot
*/
async takeScreenshot(filename) {
const browserManager = getBrowserManager();
return await browserManager.takeScreenshot(filename);
}
/**
* Execute JavaScript on page
* @param {string|Function} script - JavaScript to execute
* @param {...*} args - Arguments to pass to script
* @returns {Promise<*>}
*/
async executeScript(script, ...args) {
return await this.page.evaluate(script, ...args);
}
/**
* Wait for AJAX requests to complete
* @param {number} timeout - Timeout in milliseconds
* @returns {Promise<void>}
*/
async waitForAjaxComplete(timeout = 10000) {
try {
await this.page.waitForFunction(() => {
// Check if jQuery is available and has no active requests
if (window.jQuery) {
return window.jQuery.active === 0;
}
// Fallback: check if no pending fetch requests
return !window.fetch || window.fetch.length === 0;
}, { timeout });
} catch (error) {
console.warn('AJAX wait timeout - continuing anyway');
}
}
/**
* Scroll to element
* @param {string} selector - CSS selector
* @returns {Promise<void>}
*/
async scrollToElement(selector) {
await this.waitForElement(selector);
await this.page.locator(selector).scrollIntoViewIfNeeded();
}
/**
* Hover over element
* @param {string} selector - CSS selector
* @returns {Promise<void>}
*/
async hoverElement(selector) {
await this.waitForElement(selector);
await this.page.hover(selector);
}
/**
* Double click element
* @param {string} selector - CSS selector
* @returns {Promise<void>}
*/
async doubleClickElement(selector) {
await this.waitForElement(selector);
await this.page.dblclick(selector);
}
/**
* Right click element
* @param {string} selector - CSS selector
* @returns {Promise<void>}
*/
async rightClickElement(selector) {
await this.waitForElement(selector);
await this.page.click(selector, { button: 'right' });
}
}
module.exports = BasePage;