cypress-log-to-output
A Cypress plugin that pipes browser console logs and Chrome DevTools log entries into your terminal's stdout during test runs.
Repository Health
Technical Analysis
cypress-log-to-output is a small Cypress plugin that closes a long-standing gap in headless test debugging: browser console output that normally disappears when Cypress runs in CI. It attaches to the Chrome DevTools Protocol (CDP) via chrome-remote-interface, listens for Log.entryAdded and Runtime.consoleAPICalled events, and re-prints them — with severity-based coloring via chalk — directly into the terminal running cypress run or cypress open.
The plugin registers itself on the before:browser:launch event, so it needs no changes to test specs. It works with any Chromium-family browser (Chrome, Chromium, Canary) that Cypress launches, ensuring a --remote-debugging-port is set so it can connect. Electron, Cypress’s default bundled browser, is explicitly unsupported since Electron doesn’t expose the same CDP log/console surface in the way this plugin expects.
Beyond straight passthrough, it supports an optional filter callback so teams can restrict output to just error-level events, and an optional recordLogs mode that buffers messages in memory for later retrieval via getLogs()/clearLogs() — useful for asserting on console output from within a test itself rather than only reading it from CI logs.
What You Get
- Automatic streaming of all browser
console.*calls and Chrome DevToolsLog.entryAddedentries into your terminal duringcypress run/cypress open - Severity-colored output (verbose/info/warning/error) via
chalk, with icons and ISO timestamps prefixed to each line - An optional event filter callback so you can restrict output to just errors, or apply any custom matching logic on the raw CDP event
- An optional
recordLogsbuffering mode withgetLogs()/clearLogs()exports, letting a test assert on captured console output instead of only reading CI logs - A
DEBUG=-cypress-log-to-outputescape hatch to silence the plugin’s own[cypress-log-to-output]status lines
Common Use Cases
- Debugging flaky or failing CI test runs where a browser-side
console.errorexplains the failure but is normally invisible in headless mode - Surfacing uncaught JS exceptions and stack traces from the app under test directly next to the Cypress command log in CI output
- Filtering noisy console output down to just error-level events for a cleaner CI log
- Asserting inside a spec that a specific console message was (or wasn’t) emitted, using
recordLogs+getLogs()
Under The Hood
Architecture
The package is a single flat module (src/log-to-output.js) exporting install, browserLaunchHandler, getLogs, and clearLogs, with no internal layering — filter state, recording state, and the message buffer all live as module-scoped variables shared across calls. install() registers a before:browser:launch hook; when Cypress launches the browser, browserLaunchHandler mutates the launch args to guarantee a --remote-debugging-port, then retries a CDP connection every 100ms until Chrome’s debugger becomes reachable, at which point it subscribes to Log.entryAdded and Runtime.consoleAPICalled. The data flow is linear: CDP event to formatter (logEntry/logConsole) to console.log, with an optional buffered copy. Because the filter and recorder are global module state rather than per-instance, attaching to more than one browser session concurrently would require reworking the core abstraction.
Tech Stack
Runtime dependencies are minimal and pinned loosely: chrome-remote-interface ^0.27.1 for the CDP client and chalk ^2.4.2 for terminal coloring; devDependencies are mocha ^6.2.1 and cypress ^3.2.0. There’s no TypeScript, no bundler, and no build step — package.json’s main points straight at the plain CommonJS source file, and only src/ is published. Tests run via mocha src/*spec.js; no CI workflow file is present in the repo.
Code Quality
Only one spec file exists (src/log-to-output-spec.js), covering exactly one pure helper (_ensureRdpPort) with two assertion-based cases; the CDP connection logic, event formatting, and filtering paths have no test coverage. Error handling is thin — the CDP connection retry loop silently swallows every failure (.catch(() => setTimeout(tryConnect, 100))) with no give-up condition, so a browser that never opens a debug port retries indefinitely. No linter/formatter config or type annotations are present; naming is plain and consistent camelCase throughout.
What Makes It Unique
Its specific technical choice — talking directly to Chrome over the DevTools Protocol’s Log and Runtime domains rather than trying to intercept console output through Cypress’s own internal event bus — is what makes browser-to-terminal log forwarding possible at all, since Cypress had no native cross-process console-surfacing mechanism at the time. It’s a solid, narrow fix for a real gap rather than a broad architectural innovation; comparable CDP-log-forwarding plugins exist for other headless test runners, so the approach is standard practice within its niche.