If a test uses console.log
to print output, it doesn't show up when running from the Cypress Module API (cypress.run
).
I also tried cy.log
and this didn't work either.
Redirect console.log
to print to the node console?
3.1.4
Hey @fr0, could you give an example of the exact code you are running and where you wrote the code so I can see what you mean? Thanks!
I was having trouble with a case where my test was failing under electron (timing out) and working fine under chrome. I was trying to use console.log
to see how far it was getting, since it was running in headless mode. The timeout was in my setup code, so it was something like this:
function setup() {
cy.wrap(app.clearDatabase()).then(() => console.log('got to 1'));
cy.wrap(app.makeDatabase()).then(() => console.log('got to 2'));
}
beforeEach(() => {
setup();
cy.visit('/');
});
as a hacky partial workaround for debugging index.js setup and some other situations, you can throw an error instead of using console.log. Cypress will catch the error and render it within the test runner GUI, not on the console.
Eg, in index.js:
throw new Error('dotenv file location: : ' + JSON.stringify(process.env.DOTENV_FILE));
Allows me to deduce that the environment variable is not being set properly (as opposed to being set properly and later mutated or inaccessible within some specific context):
If support/index.js
remains a client-side resource, I feel like this could be accomplished via cy.log
outside of a running test sending an http request to a logging endpoint within cypress - if one exists, use that, else standing up a new one is fairly trivial.
However I think there's an alternative solution I'd prefer. Could I propose that processing /support/*
(including index.js
) in a node context is one way to solve this issue?
While the documentation indicates that /plugins
get processed in a node context, I don't see why /support
can't also be evaluated in a node context.
Indeed, at least one /support
file does appear to be evaluated in a node context: /support/commands.js
.
Hey Everyone! I found a solution to get console logs( log, warn, info, error ) from your app into cypress output!
My team has been having problems where our cypress tests run fine locally but inside of our continuous integration tool, it fails. Without our apps console.logs
we cannot really debug the issue coming from our app. This is my solution
I added this code to my support/index.js
file since this is the first file to get loaded in cypress.
Note: I tried to use in plugins file but for some reason, it wasn't working.
I added this functionality to cypress event window:before:load
because every time we use cy.visit()
we want to rewrite the console methods.
This will only be useful when calling cypress run
// store logs
let logs = '';
Cypress.on('window:before:load', (window) => {
// Get your apps iframe by id. Ours is called "Your App: 'cypress'". If yours is different
// just replace with your apps iframe id
const docIframe = window.parent.document.getElementById("Your App: 'cypress'");
// Get the window object inside of the iframe
const appWindow = docIframe.contentWindow;
// This is where I overwrite all of the console methods.
['log', 'info', 'error', 'warn', 'debug'].forEach((consoleProperty) => {
appWindow.console[consoleProperty] = function (...args) {
/*
* The args parameter will be all of the values passed as arguments to
* the console method. ( If your not using es6 then you can use `arguments`)
* Example:
* If your app uses does `console.log('argument1', 'arument2');`
* Then args will be `[ 'argument1', 'arument2' ]`
*/
// Save everything passed into a variable or any other solution
// you make to keep track of the logs
logs += args.join(' ') + '\n';
};
});
});
// Cypress doesn't have a each test event
// so I'm using mochas events to clear log state after every test.
Cypress.mocha.getRunner().on('test', () => {
// Every test reset your logs to be empty
// This will make sure only logs from that test suite will be logged if a error happens
logs = '';
});
// On a cypress fail. I add the console logs, from the start of test or after the last test fail to the
// current fail, to the end of the error.stack property.
Cypress.on('fail', (error) => {
error.stack += '\nConsole Logs:\n========================';
error.stack += logs;
// clear logs after fail so we dont see duplicate logs
logs = '';
// still need to throw the error so tests wont be marked as a pass
throw error;
});
Now in the terminal( local ) or in cypress dashboard in the output. you will see something like this. I made a error on purpose trying to get some random element
1) In a message we should be able to add an reaction to message from picker:
CypressError: Timed out retrying: Expected to find element: 'some-el', but never found it.
at Object.cypressErr (https://qa566.slack.com/__cypress/runner/cypress_runner.js:65283:11)
at Object.throwErr (https://qa566.slack.com/__cypress/runner/cypress_runner.js:65248:18)
at Object.throwErrByPath (https://qa566.slack.com/__cypress/runner/cypress_runner.js:65275:17)
at retry (https://qa566.slack.com/__cypress/runner/cypress_runner.js:58816:16)
at https://qa566.slack.com/__cypress/runner/cypress_runner.js:50924:18
at tryCatcher (https://qa566.slack.com/__cypress/runner/cypress_runner.js:127195:23)
at Promise._settlePromiseFromHandler (https://qa566.slack.com/__cypress/runner/cypress_runner.js:125213:31)
at Promise._settlePromise (https://qa566.slack.com/__cypress/runner/cypress_runner.js:125270:18)
at Promise._settlePromise0 (https://qa566.slack.com/__cypress/runner/cypress_runner.js:125315:10)
at Promise._settlePromises (https://qa566.slack.com/__cypress/runner/cypress_runner.js:125390:18)
at Async._drainQueue (https://qa566.slack.com/__cypress/runner/cypress_runner.js:122119:16)
at Async._drainQueues (https://qa566.slack.com/__cypress/runner/cypress_runner.js:122129:10)
at Async.drainQueues (https://qa566.slack.com/__cypress/runner/cypress_runner.js:122003:14)
at <anonymous>
Console Logs from your app for this test suite:
===============
< All logs will be put here>
Want to get cy.log
or console.log
in ci? you should be able to do this
console.log = function(...args){
// add args to our log variable like my first example
logs += args.join(' ') + '\n';
}
Cypress.Commands.overwrite('log', (origninalFn, ...args) => {
// add args to our log variable like my first example
logs += args.join(' ') + '\n';
originalFn(...args);
})
Awesome @marcellino-ornelas, you may want to consider making this into a Cypress plugin for others to more easily use.
@jennifer-shehane I tried initially to make this into a plugin but I couldn't get it to work. I also couldn't debug. I couldn't see any console logs or anything. also, I need to modify the actual window object and since plugins run in a node environment. I don't think this would work?
on('window:before:load', () => {
console.log(/*...*/) // didnt log anything for me
})
Hi, so here is our solution for the problem:
Cypress.on('window:before:load', (win) => {
Cypress.log({
name: 'console.log',
message: 'wrap on console.log',
});
// pass through cypress log so we can see log inside command execution order
win.console.log = (...args) => {
Cypress.log({
name: 'console.log',
message: args,
});
};
});
Cypress.on('log:added', (options) => {
if (options.instrument === 'command') {
// eslint-disable-next-line no-console
console.log(
`${(options.displayName || options.name || '').toUpperCase()} ${
options.message
}`,
);
}
});
You need to set env variable to see log in cypress heedless mode:
ELECTRON_ENABLE_LOGGING=1
You can put it in your support file.
There is also a plugin for Cypress written by @flotwig that logs console output to the terminal here: https://github.com/flotwig/cypress-log-to-output
I did it this way:
Overwrite log command to use task instead:
in commands/index
:
Cypress.Commands.overwrite('log', (subject, message) => cy.task('log', message));
Add task command to plugins:
in plugins/index
:
module.exports = on => {
on('task', {
log (message) {
console.log(message);
return null
}
});
};
It will put all cy.log()
messages to console output
I did it this way:
Overwrite log command to use task instead:
in commands/index:
Cypress.Commands.overwrite('log', (subject, message) => cy.task('log', message));
Add task command to plugins:
in plugins/index:
module.exports = on => { on('task', { log (message) { console.log(message); return null } }); };
It will put all cy.log() messages to console output
You're a lifesaver man this was driving me mad.
There really should be like a cy.nodeLog() or cy.log({options: 'node'}) or something: debugging CI is such a painful thing.
log (message) { console.log(message); return null }
I am using console.table instead of console.log and throw error for me saying console.table is not a function @anton-aurea
Based on previous comments and other npm packages that did not satisfy my needs I have combined togheter this package https://github.com/archfz/cypress-terminal-report . It logs cypress commands and console.warn+console.error to terminal in a pretty format.
@marcellino-ornelas you saved my a**, thanks for sharing
@anton-aurea awesome solution, thanks man!
but it logs the cy.log() before the name of the test, how it could be resolved ? to enable log the test name and then the cy.log() ?
@karem63 check out https://github.com/archfz/cypress-terminal-report
I did it this way:
Overwrite log command to use task instead:
in commands/index:
Cypress.Commands.overwrite('log', (subject, message) => cy.task('log', message));
Add task command to plugins:
in plugins/index:
module.exports = on => { on('task', { log (message) { console.log(message); return null } }); };
It will put all cy.log() messages to console output
That's great, but what I could really use is the ability for my plugin to log to the browser console.
@alexagranov7 console.log/console.error etc. work in the browser, what do you mean?
Most helpful comment
I did it this way:
Overwrite log command to use task instead:
in
commands/index
:Add task command to plugins:
in
plugins/index
:It will put all
cy.log()
messages to console output