diff --git a/client/cypress.config.js b/client/cypress.config.js index b48f42a28..324234b9d 100644 --- a/client/cypress.config.js +++ b/client/cypress.config.js @@ -1,11 +1,47 @@ +const path = require("path") const { defineConfig } = require("cypress") module.exports = defineConfig({ + env: { + ABS_CYPRESS_DEBUG_BROWSER: false + }, + e2e: { + setupNodeEvents(on, config) { + on('task', { + absCypressDebug(payload) { + const prefix = `[cypress:${payload.type}]` + const message = typeof payload.message === 'string' ? payload.message : JSON.stringify(payload.message) + const details = payload.details ? `\n${payload.details}` : '' + + // Surface browser-side failures in terminal output for focused debug runs. + console.error(`${prefix} ${message}${details}`) + return null + } + }) + + on('before:browser:launch', (browser, launchOptions) => { + if (!config.env.ABS_CYPRESS_DEBUG_BROWSER) { + return launchOptions + } + + if (browser.family === 'chromium') { + launchOptions.args.push('--auto-open-devtools-for-tabs') + launchOptions.args.push('--enable-logging=stderr') + launchOptions.args.push('--v=1') + } + + return launchOptions + }) + + return config + } + }, component: { devServer: { framework: "nuxt", bundler: "webpack" }, - specPattern: "cypress/tests/**/*.cy.js" + specPattern: "cypress/tests/**/*.cy.js", + supportFile: path.join(__dirname, 'cypress/support/component.js') } }) diff --git a/client/cypress/support/component.js b/client/cypress/support/component.js index a3dd58d95..ac78cb25f 100644 --- a/client/cypress/support/component.js +++ b/client/cypress/support/component.js @@ -25,6 +25,45 @@ import '../../plugins/init.client' import { mount } from 'cypress/vue2' +const shouldForwardBrowserDebug = () => Boolean(Cypress.env('ABS_CYPRESS_DEBUG_BROWSER')) + +const formatErrorDetails = (value) => { + if (!value) return '' + if (value.stack) return value.stack + if (typeof value === 'string') return value + + try { + return JSON.stringify(value, null, 2) + } catch { + return String(value) + } +} + +const forwardBrowserDebug = (type, message, details) => { + if (!shouldForwardBrowserDebug()) return + + cy.task('absCypressDebug', { + type, + message, + details: formatErrorDetails(details) + }, { log: false }) +} + +window.addEventListener('error', (event) => { + forwardBrowserDebug('window-error', event.message || 'Unhandled window error', event.error) +}) + +window.addEventListener('unhandledrejection', (event) => { + const reason = event.reason + const message = reason?.message || 'Unhandled promise rejection' + forwardBrowserDebug('unhandledrejection', message, reason) +}) + +Cypress.on('fail', (error, runnable) => { + forwardBrowserDebug('cypress-fail', `${runnable?.fullTitle?.() || 'Unknown test'} failed`, error) + throw error +}) + //Cypress.Commands.add('mount', mount) Cypress.Commands.add('mount', (component, options = {}) => { @@ -35,4 +74,4 @@ Cypress.Commands.add('mount', (component, options = {}) => { }) // Example use: -// cy.mount(MyComponent) \ No newline at end of file +// cy.mount(MyComponent)