Open admah opened 2 years ago
Hello @flotwig, may you please update your great plugin so it is compatible with the Cypress 10? 🙏 There is no alternative for debugging console logs. Many thanks!
I have found that the plugin still works OK UNLESS you have a plugin after it that also listens to before:browser:launch
After trying to get this plugin to work with Cypress 10 i have to say, that it doesn't work in headless mode.
The Chrome debugger gets disconnected after the first suite and then is gone... no reconnect.
Maybe if someone is interested i've got it to work. I will just post it here because i don't think that this repo is getting some updates:
You can install the plugin that way:
async setupNodeEvents(on, _config) {
require('./src/plugins/cypress-log-to-output/index').install(on);
},
The key change is to do the debugger connect in the before:spec
hook:
function install(on, filter, options = {}) {
eventFilter = filter;
recordLogs = options.recordLogs;
on('before:browser:launch', browserLaunchHandler)
on('before:spec', tryConnect)
}
I also added some cleanup logic to the tryConnect function and some logging improvements, here is the full version:
const CDP = require('chrome-remote-interface')
const chalk = require('chalk')
let eventFilter
let recordLogs
let remoteDebugPort
let CDPInstance
let messageLog = [];
const severityColors = {
'verbose': (a) => a,
'info': chalk.blue,
'warning': chalk.yellow,
'error': chalk.red
}
const severityIcons = {
'verbose': ' ',
'info': '🛈',
'warning': '⚠',
'error': '⚠',
}
function debugLog(msg) {
// suppress with DEBUG=-cypress-log-to-output
if (process.env.DEBUG && process.env.DEBUG.includes('-cypress-log-to-output')) {
return
}
log(`[cypress-log-to-output] ${msg}`)
}
function log(msg) {
console.log(msg)
}
function logEntry(params) {
if (eventFilter && !eventFilter('browser', params.entry)) {
return
}
const { level, source, text, timestamp, url, lineNumber, stackTrace, args } = params.entry
const color = severityColors[level]
const icon = severityIcons[level]
const prefix = `[${new Date(timestamp).toISOString()}] ${icon} `
const prefixSpacer = ' '.repeat(prefix.length)
let logMessage = `${prefix}${chalk.bold(level)} (${source}): ${text}`;
log(color(logMessage));
recordLogMessage(logMessage);
const logAdditional = (msg) => {
let additionalLogMessage = `${prefixSpacer}${msg}`;
log(color(additionalLogMessage));
recordLogMessage(additionalLogMessage);
};
if (url) {
logAdditional(`${chalk.bold('URL')}: ${url}`)
}
if (stackTrace && lineNumber) {
logAdditional(`Stack trace line number: ${lineNumber}`)
logAdditional(`Stack trace description: ${stackTrace.description}`)
logAdditional(`Stack call frames: ${stackTrace.callFrames.join(', ')}`)
}
if (args) {
logAdditional(`Arguments:`)
logAdditional(' ' + JSON.stringify(args, null, 2).split('\n').join(`\n${prefixSpacer} `).trimRight())
}
}
function logConsole(params) {
if (eventFilter && !eventFilter('console', params)) {
return
}
const { type, args, timestamp } = params
const level = type === 'error' ? 'error' : 'verbose'
const color = severityColors[level]
const icon = severityIcons[level]
const prefix = `[${new Date(timestamp).toISOString()}] ${icon} `
const prefixSpacer = ' '.repeat(prefix.length)
let logMessage = `${prefix}${chalk.bold(`console.${type}`)} called`;
log(color(logMessage));
recordLogMessage(logMessage);
const logAdditional = (msg) => {
let logMessage = `${prefixSpacer}${msg}`;
log(color(logMessage));
recordLogMessage(logMessage);
};
if (args) {
logAdditional(`Arguments:`)
logAdditional(' ' + JSON.stringify(args.map(i => i.value), null, 2).split('\n').join(`\n${prefixSpacer} `).trimRight())
}
}
function install(on, filter, options = {}) {
eventFilter = filter;
recordLogs = options.recordLogs;
on('before:browser:launch', browserLaunchHandler)
on('before:spec', tryConnect)
}
function recordLogMessage(logMessage) {
if (recordLogs) {
messageLog.push(logMessage);
}
}
function getLogs() {
return messageLog;
}
function clearLogs() {
messageLog = [];
}
function isChrome(browser) {
return browser.family === 'chrome' || ['chrome', 'chromium', 'canary'].includes(browser.name) || (browser.family === 'chromium' && browser.name !== 'electron')
}
function ensureRdpPort(args) {
let port
const existing = args.find(arg => arg.slice(0, 23) === '--remote-debugging-port')
if (existing) {
port = Number(existing.split('=')[1]);
debugLog('Use existing port ' + port)
return port
}
port = 40000 + Math.round(Math.random() * 25000)
debugLog('Use custom port ' + port)
args.push(`--remote-debugging-port=${port}`)
return port
}
function tryConnect() {
debugLog('Attempting to connect to Chrome Debugging Protocol on port ' + remoteDebugPort)
if (typeof remoteDebugPort !== 'number') return
if (CDPInstance != null) return
CDPInstance = new CDP({ port: remoteDebugPort })
.then((cdp) => {
debugLog('Connected to Chrome Debugging Protocol')
/** captures logs from the browser */
cdp.Log.enable()
cdp.Log.entryAdded(logEntry)
/** captures logs from console.X calls */
cdp.Runtime.enable()
cdp.Runtime.consoleAPICalled(logConsole)
cdp.on('disconnect', () => {
debugLog('Chrome Debugging Protocol disconnected')
CDPInstance = undefined;
})
})
.catch(() => {
CDPInstance = undefined;
setTimeout(tryConnect, 100)
})
}
function browserLaunchHandler(browser = {}, launchOptions) {
const args = launchOptions.args || launchOptions
if (!isChrome(browser)) {
return debugLog(`Warning: An unsupported browser family was used, output will not be logged to console: ${browser.family}`)
}
remoteDebugPort = ensureRdpPort(args)
tryConnect()
}
module.exports = {
_ensureRdpPort: ensureRdpPort,
install,
browserLaunchHandler,
getLogs,
clearLogs
}
To those who landed here hoping to find a working plugin for cypress@10 - this is the plugin you're looking for: https://github.com/archfz/cypress-terminal-report
Hello 👋 I'm writing on behalf of the Cypress DX team. We wanted to notify you that some changes may need to be made to this plugin to ensure that it works in Cypress 10.
For more information, here is our official plugin update guide.