import { Page } from '@playwright/test'; export interface CapturedError { type: 'console' | 'page'; message: string; stack?: string; timestamp: number; } export class ConsoleErrorCapture { private errors: CapturedError[] = []; private allowlist: (string | RegExp)[] = []; constructor(private page: Page) { this.setupCapture(); } public setAllowlist(patterns: (string | RegExp)[]): void { this.allowlist = patterns; } private isAllowed(message: string): boolean { return this.allowlist.some(pattern => typeof pattern === 'string' ? message.includes(pattern) : pattern.test(message) ); } private setupCapture(): void { this.page.on('console', (msg) => { if (msg.type() === 'error') { this.errors.push({ type: 'console', message: msg.text(), timestamp: Date.now(), }); } }); this.page.on('pageerror', (error) => { this.errors.push({ type: 'page', message: error.message, stack: error.stack ?? '', timestamp: Date.now(), }); }); } public getErrors(): CapturedError[] { return this.errors; } public getUnexpectedErrors(): CapturedError[] { return this.errors.filter(e => !this.isAllowed(e.message)); } public format(): string { if (this.errors.length === 0) return 'No console errors captured.'; const unexpected = this.getUnexpectedErrors(); const allowed = this.errors.filter(e => this.isAllowed(e.message)); let output = '--- Console Error Capture ---\n'; if (unexpected.length > 0) { output += `UNEXPECTED ERRORS (${unexpected.length}):\n`; unexpected.forEach((e, i) => { output += `[${i + 1}] ${e.type.toUpperCase()}: ${e.message}\n`; if (e.stack) output += `Stack: ${e.stack}\n`; }); } if (allowed.length > 0) { output += `\nALLOWED ERRORS (${allowed.length}):\n`; allowed.forEach((e, i) => { output += `[${i + 1}] ${e.type.toUpperCase()}: ${e.message}\n`; }); } return output; } public hasErrors(): boolean { return this.errors.length > 0; } public hasUnexpectedErrors(): boolean { return this.getUnexpectedErrors().length > 0; } public clear(): void { this.errors = []; } public async waitForErrors(timeout: number = 1000): Promise { await this.page.waitForTimeout(timeout); return this.hasErrors(); } }