134 lines
3.0 KiB
TypeScript
134 lines
3.0 KiB
TypeScript
import { Page, ConsoleMessage } from '@playwright/test';
|
|
|
|
export interface ConsoleError {
|
|
type: 'error' | 'warning' | 'pageerror';
|
|
message: string;
|
|
location?: string;
|
|
timestamp: Date;
|
|
}
|
|
|
|
/**
|
|
* ConsoleMonitor - Aggregates and tracks all console output
|
|
*
|
|
* Purpose: Catch ANY runtime errors during Electron app lifecycle
|
|
*
|
|
* Critical Detections:
|
|
* - "Module has been externalized for browser compatibility"
|
|
* - "__dirname is not defined"
|
|
* - "require is not defined"
|
|
* - Any uncaught exceptions
|
|
*/
|
|
export class ConsoleMonitor {
|
|
private errors: ConsoleError[] = [];
|
|
private warnings: ConsoleError[] = [];
|
|
private isMonitoring = false;
|
|
|
|
/**
|
|
* Start monitoring console output on the page
|
|
*/
|
|
startMonitoring(page: Page): void {
|
|
if (this.isMonitoring) {
|
|
return;
|
|
}
|
|
|
|
// Monitor console.error calls
|
|
page.on('console', (msg: ConsoleMessage) => {
|
|
if (msg.type() === 'error') {
|
|
this.errors.push({
|
|
type: 'error',
|
|
message: msg.text(),
|
|
location: msg.location()?.url,
|
|
timestamp: new Date(),
|
|
});
|
|
} else if (msg.type() === 'warning') {
|
|
this.warnings.push({
|
|
type: 'warning',
|
|
message: msg.text(),
|
|
location: msg.location()?.url,
|
|
timestamp: new Date(),
|
|
});
|
|
}
|
|
});
|
|
|
|
// Monitor uncaught exceptions
|
|
page.on('pageerror', (error: Error) => {
|
|
const errorObj: ConsoleError = {
|
|
type: 'pageerror',
|
|
message: error.message,
|
|
timestamp: new Date(),
|
|
};
|
|
if (error.stack) {
|
|
errorObj.location = error.stack;
|
|
}
|
|
this.errors.push(errorObj);
|
|
});
|
|
|
|
this.isMonitoring = true;
|
|
}
|
|
|
|
/**
|
|
* Check if any errors were detected
|
|
*/
|
|
hasErrors(): boolean {
|
|
return this.errors.length > 0;
|
|
}
|
|
|
|
/**
|
|
* Get all detected errors
|
|
*/
|
|
getErrors(): ConsoleError[] {
|
|
return [...this.errors];
|
|
}
|
|
|
|
/**
|
|
* Get all detected warnings
|
|
*/
|
|
getWarnings(): ConsoleError[] {
|
|
return [...this.warnings];
|
|
}
|
|
|
|
/**
|
|
* Format errors for test output
|
|
*/
|
|
formatErrors(): string {
|
|
if (this.errors.length === 0) {
|
|
return 'No errors detected';
|
|
}
|
|
|
|
const lines = ['Console errors detected during test:', ''];
|
|
|
|
this.errors.forEach((error, index) => {
|
|
lines.push(`${index + 1}. [${error.type}] ${error.message}`);
|
|
if (error.location) {
|
|
lines.push(` Location: ${error.location}`);
|
|
}
|
|
lines.push('');
|
|
});
|
|
|
|
return lines.join('\n');
|
|
}
|
|
|
|
/**
|
|
* Check for specific browser context errors
|
|
*/
|
|
hasBrowserContextErrors(): boolean {
|
|
const contextErrorPatterns = [
|
|
/has been externalized for browser compatibility/i,
|
|
/__dirname is not defined/i,
|
|
/require is not defined/i,
|
|
/Cannot access .* in client code/i,
|
|
];
|
|
|
|
return this.errors.some(error =>
|
|
contextErrorPatterns.some(pattern => pattern.test(error.message))
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Reset monitoring state
|
|
*/
|
|
reset(): void {
|
|
this.errors = [];
|
|
this.warnings = [];
|
|
}
|
|
} |