///
interface ConsoleLog {
type: string;
args: any[];
timestamp: string;
url?: string;
}
// Configuration for filtering console logs
interface ConsoleFilterConfig {
enabled: boolean;
filters: Array<{
name: string;
patterns: string[];
matchAll?: boolean; // If true, all patterns must match. If false (default), any pattern match triggers filter
}>;
}
// Configure which console logs to filter out
const CONSOLE_FILTER_CONFIG: ConsoleFilterConfig = {
enabled: true, // Set to false to disable all filtering
filters: [
{
name: 'Billing 502 Errors',
patterns: ['billing/api', '502'],
matchAll: true // Both patterns must be present
},
{
name: 'Subscription Errors',
patterns: ['active-subscription', 'ERR_BAD_RESPONSE'],
matchAll: true
},
// Add more filters here as needed
// {
// name: 'React Warnings',
// patterns: ['React Router Future Flag Warning'],
// matchAll: false
// }
]
};
// Store captured console logs globally
let consoleLogs: ConsoleLog[] = [];
let isCapturing = false;
// Helper to stringify arguments for better readability
function stringifyArgs(args: any[]): string {
return args.map(arg => {
try {
if (typeof arg === 'object' && arg !== null) {
return JSON.stringify(arg, null, 2);
}
return String(arg);
} catch (e) {
return '[Object]';
}
}).join(' ');
}
// Helper to check if a message should be filtered
function shouldFilterMessage(message: string): boolean {
if (!CONSOLE_FILTER_CONFIG.enabled) {
return false;
}
for (const filter of CONSOLE_FILTER_CONFIG.filters) {
const matchAll = filter.matchAll ?? false;
if (matchAll) {
// All patterns must be present in the message
if (filter.patterns.every(pattern => message.includes(pattern))) {
return true; // Filter out this message
}
} else {
// Any pattern match triggers the filter
if (filter.patterns.some(pattern => message.includes(pattern))) {
return true; // Filter out this message
}
}
}
return false;
}
// Install console interceptors on window
function installConsoleInterceptors(win: any) {
const methods: (keyof Console)[] = ['log', 'error', 'warn'];
methods.forEach((method) => {
const originalMethod = (win.console[method] as Function).bind(win.console);
// Override the console method
win.console[method] = (...args: any[]) => {
if (isCapturing) {
// Get message for filtering and logging
const message = stringifyArgs(args);
// Check if this message should be filtered
if (shouldFilterMessage(message)) {
// Skip logging filtered messages but still call original method
originalMethod(...args);
return;
}
// Store the log
const logEntry: ConsoleLog = {
type: method,
args: args,
timestamp: new Date().toISOString(),
url: win.location.href
};
consoleLogs.push(logEntry);
// Immediately output to Cypress task for CI visibility
const logMessage = `[${new Date().toISOString()}] [CONSOLE.${method.toUpperCase()}] ${message}`;
// Log to Node.js console directly
console.log(logMessage);
// Also use cy.task for guaranteed CI visibility (if available)
try {
// Check if we're in a Cypress context and can use cy.task
if (typeof Cypress !== 'undefined' && Cypress.cy) {
Cypress.cy.task('log', logMessage, { log: false }).catch(() => {
// Ignore errors if cy.task is not available in current context
});
}
} catch (e) {
// Ignore errors if Cypress is not available
}
}
// Call original method
return originalMethod(...args);
};
});
}
// Start capturing console logs
Cypress.Commands.add('startConsoleCapture', () => {
consoleLogs = [];
isCapturing = true;
// Check if we're in CI environment
const isCi = Cypress.env('CI') || Cypress.env('GITHUB_ACTIONS');
cy.task('log', `[CONSOLE-LOGGER] Starting console capture (CI: ${!!isCi})`);
// Install on current window
cy.window({ log: false }).then((win) => {
installConsoleInterceptors(win);
// Test console capture immediately in CI
if (isCi) {
cy.task('log', '[CONSOLE-LOGGER] Console interceptors installed, testing...');
win.console.log('🧪 TEST: Console capture is working in CI environment');
}
});
// Install on all future windows (navigation, reload, etc.)
Cypress.on('window:before:load', (win) => {
installConsoleInterceptors(win);
});
cy.log('Console capture started');
});
// Stop capturing console logs
Cypress.Commands.add('stopConsoleCapture', () => {
isCapturing = false;
cy.log('Console capture stopped');
});
// Get all captured logs
Cypress.Commands.add('getConsoleLogs', () => {
return cy.wrap(consoleLogs, { log: false });
});
// Print captured logs summary
Cypress.Commands.add('printConsoleLogsSummary', () => {
const summary = {
total: consoleLogs.length,
errors: consoleLogs.filter(l => l.type === 'error').length,
warnings: consoleLogs.filter(l => l.type === 'warn').length,
logs: consoleLogs.filter(l => l.type === 'log').length,
info: consoleLogs.filter(l => l.type === 'info').length,
debug: consoleLogs.filter(l => l.type === 'debug').length
};
// Enhanced logging summary for CI visibility
const isCi = Cypress.env('CI') || Cypress.env('GITHUB_ACTIONS');
cy.task('log', '=== Console Logs Summary ===');
cy.task('log', `Total logs captured: ${summary.total}`);
cy.task('log', ` - Errors: ${summary.errors}`);
cy.task('log', ` - Warnings: ${summary.warnings}`);
cy.task('log', ` - Logs: ${summary.logs}`);
cy.task('log', ` - Info: ${summary.info}`);
cy.task('log', ` - Debug: ${summary.debug}`);
if (isCi && summary.total === 0) {
cy.task('log', '⚠️ WARNING: No console logs captured in CI environment!');
cy.task('log', ' This might indicate console interceptor is not working properly.');
cy.task('log', ' Check if the web app is loading correctly in CI.');
}
// Print all logs
if (consoleLogs.length > 0) {
cy.task('log', '=== Captured Console Logs ===');
consoleLogs.forEach((log, index) => {
const message = stringifyArgs(log.args);
cy.task('log', `[${index + 1}] ${log.timestamp} [${log.type.toUpperCase()}] (${log.url || 'unknown'}): ${message}`);
});
cy.task('log', '=== End of Console Logs ===');
} else {
cy.task('log', 'No console logs were captured');
}
});
// Clear captured logs
Cypress.Commands.add('clearConsoleLogs', () => {
consoleLogs = [];
});
// Add TypeScript definitions
declare global {
namespace Cypress {
interface Chainable {
/**
* Start capturing console logs from the application
*/
startConsoleCapture(): Chainable;
/**
* Stop capturing console logs
*/
stopConsoleCapture(): Chainable;
/**
* Get all captured console logs
*/
getConsoleLogs(): Chainable;
/**
* Print a summary of captured console logs
*/
printConsoleLogsSummary(): Chainable;
/**
* Clear all captured console logs
*/
clearConsoleLogs(): Chainable;
}
}
}
export {};