/** * WordPress Error Detection Utility * Detects critical WordPress errors that would block testing * * Usage: * const errorDetector = new WordPressErrorDetector(page); * const error = await errorDetector.detectCriticalErrors(); * if (error) { * throw new Error(`Critical WordPress Error: ${error.type} - ${error.message}`); * } */ class WordPressErrorDetector { constructor(page) { this.page = page; } /** * Detect critical WordPress errors that would block testing * @returns {Object|null} Error object or null if no errors */ async detectCriticalErrors() { try { // Check for fatal PHP errors const fatalError = await this.checkFatalPhpError(); if (fatalError) return fatalError; // Check for database connection errors const dbError = await this.checkDatabaseError(); if (dbError) return dbError; // Check for WordPress maintenance mode const maintenanceError = await this.checkMaintenanceMode(); if (maintenanceError) return maintenanceError; // Check for plugin/theme errors const pluginError = await this.checkPluginThemeErrors(); if (pluginError) return pluginError; // Check for HTTP error codes in page response const httpError = await this.checkHttpErrors(); if (httpError) return httpError; return null; } catch (e) { return { type: 'DETECTION_ERROR', message: `Error while detecting WordPress errors: ${e.message}`, blocking: true }; } } /** * Check for fatal PHP errors */ async checkFatalPhpError() { const pageContent = await this.page.content(); const fatalErrorPatterns = [ /Fatal error:/i, /Parse error:/i, /Fatal Error:/i, /PHP Fatal error:/i, /Uncaught Error:/i, /Call to undefined function/i, /Maximum execution time exceeded/i, /Allowed memory size.*exhausted/i ]; for (const pattern of fatalErrorPatterns) { if (pattern.test(pageContent)) { const match = pageContent.match(pattern); return { type: 'FATAL_PHP_ERROR', message: match ? match[0] : 'Fatal PHP error detected', blocking: true, details: this.extractErrorContext(pageContent, pattern) }; } } return null; } /** * Check for database connection errors */ async checkDatabaseError() { const pageContent = await this.page.content(); const dbErrorPatterns = [ /Error establishing a database connection/i, /Database connection error/i, /Can't connect to MySQL server/i, /Access denied for user/i, /MySQL server has gone away/i, /Lost connection to MySQL server/i ]; for (const pattern of dbErrorPatterns) { if (pattern.test(pageContent)) { return { type: 'DATABASE_ERROR', message: 'Database connection error detected', blocking: true, details: this.extractErrorContext(pageContent, pattern) }; } } return null; } /** * Check for WordPress maintenance mode */ async checkMaintenanceMode() { const pageContent = await this.page.content(); const maintenancePatterns = [ /Briefly unavailable for scheduled maintenance/i, /The site is temporarily down for maintenance/i, /Maintenance mode is on/i ]; for (const pattern of maintenancePatterns) { if (pattern.test(pageContent)) { return { type: 'MAINTENANCE_MODE', message: 'WordPress site is in maintenance mode', blocking: true, temporary: true }; } } return null; } /** * Check for plugin/theme errors */ async checkPluginThemeErrors() { const pageContent = await this.page.content(); const pluginErrorPatterns = [ /Plugin could not be activated because it triggered a fatal error/i, /The plugin generated.*characters of unexpected output/i, /There has been a critical error on this website/i, /Something went wrong/i ]; for (const pattern of pluginErrorPatterns) { if (pattern.test(pageContent)) { return { type: 'PLUGIN_THEME_ERROR', message: 'Plugin or theme error detected', blocking: true, details: this.extractErrorContext(pageContent, pattern) }; } } return null; } /** * Check for HTTP error responses */ async checkHttpErrors() { try { const response = this.page.response(); if (!response) return null; const status = response.status(); if (status >= 500) { return { type: 'HTTP_SERVER_ERROR', message: `HTTP ${status} error`, blocking: true, statusCode: status, statusText: response.statusText() }; } if (status === 404) { const url = response.url(); // Only consider 404 blocking for critical WordPress files if (url.includes('wp-admin') || url.includes('wp-login')) { return { type: 'HTTP_NOT_FOUND', message: `Critical WordPress resource not found: ${url}`, blocking: true, statusCode: status }; } } return null; } catch (e) { return null; // Non-blocking if we can't check HTTP status } } /** * Extract error context from page content */ extractErrorContext(content, pattern) { try { const match = content.match(pattern); if (!match) return null; const startIndex = match.index; const contextStart = Math.max(0, startIndex - 200); const contextEnd = Math.min(content.length, startIndex + 500); return content.substring(contextStart, contextEnd).replace(/\s+/g, ' ').trim(); } catch (e) { return null; } } /** * Check if the current page has WordPress admin access */ async checkWordPressAccess() { try { const title = await this.page.title(); const url = this.page.url(); // Check for WordPress indicators const isWordPress = title.toLowerCase().includes('wordpress') || await this.page.$('body.wp-admin') !== null || await this.page.$('body.login') !== null || url.includes('wp-admin') || url.includes('wp-login'); if (!isWordPress) { return { type: 'WORDPRESS_ACCESS_ERROR', message: 'Unable to access WordPress - site may be down or not responding', blocking: true, url: url, title: title }; } return null; } catch (e) { return { type: 'ACCESS_CHECK_ERROR', message: `Error checking WordPress access: ${e.message}`, blocking: true }; } } /** * Get comprehensive error report */ async getErrorReport() { const errors = []; const criticalError = await this.detectCriticalErrors(); if (criticalError) errors.push(criticalError); const accessError = await this.checkWordPressAccess(); if (accessError) errors.push(accessError); return { hasErrors: errors.length > 0, blockingErrors: errors.filter(e => e.blocking), allErrors: errors, timestamp: new Date().toISOString(), url: this.page.url() }; } } module.exports = WordPressErrorDetector;