Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to console.log output from test files to stdout when running via cypress run #3199

Open
fr0 opened this issue Jan 23, 2019 · 23 comments
Labels
existing workaround stage: proposal 💡 No work has been done of this issue type: feature New feature that does not currently exist

Comments

@fr0
Copy link

fr0 commented Jan 23, 2019

Current behavior:

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.

Desired behavior:

Redirect console.log to print to the node console?

Versions

3.1.4

@jennifer-shehane
Copy link
Member

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!

@jennifer-shehane jennifer-shehane added the stage: needs information Not enough info to reproduce the issue label Jan 24, 2019
@fr0
Copy link
Author

fr0 commented Jan 24, 2019

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('/');
});

@jennifer-shehane jennifer-shehane changed the title console.log output doesn't get printed when running from module API Ability to console.log output to node console (in support files or Module API) Feb 20, 2019
@cypress-bot cypress-bot bot added stage: proposal 💡 No work has been done of this issue and removed stage: needs information Not enough info to reproduce the issue labels Feb 20, 2019
@jennifer-shehane jennifer-shehane added the type: feature New feature that does not currently exist label Feb 20, 2019
@Vandivier
Copy link

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):

image

@Vandivier
Copy link

Vandivier commented Feb 21, 2019

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.

@marcellino-ornelas
Copy link

marcellino-ornelas commented Feb 23, 2019

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);
})

@jennifer-shehane
Copy link
Member

Awesome @marcellino-ornelas, you may want to consider making this into a Cypress plugin for others to more easily use.

@marcellino-ornelas
Copy link

marcellino-ornelas commented Mar 2, 2019

@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
})

@xhubbsaxo
Copy link

xhubbsaxo commented May 15, 2019

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
  1. This will allow to show command logs and source code logs in headless mode
  2. This will display command logs in browser console when using headed mode

You can put it in your support file.

@jennifer-shehane
Copy link
Member

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

@anton-aurea
Copy link

anton-aurea commented Sep 9, 2019

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

@MFStapert
Copy link

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.

aurelijusb added a commit to aurelijusb/kickstart that referenced this issue Nov 9, 2019
Overwriting log function, so logs would be visible in headless output
instead of Chromium browser: cypress-io/cypress#3199

Using Cypress environments parameters to be able to test on both:
GitHub Workflows (CI) and locally (outside of container).

Assuming locally cypress is installed globally (yarn global add cypress).
aurelijusb added a commit to aurelijusb/kickstart that referenced this issue Nov 10, 2019
So it would be clear, that all parts are working correctly,
leaving more time to Code review.

Adding screenshots and debugging intermediate results,
so it would be faster to evaluate and/or fix issues.

Using Cypress as one of Headless browser based test framework.
Cypress is running browser as a separate process,
so it was needed for custom debug function to see intermediate results
in GitHub actions as well.

Using e2e-tests.sh to reach docker network used by docker-compose.yml.

Initial idea was to use GitHub Checks Annotations,
but Cypress already formats output with colors.
So using just different indentation.

Video recording disabled to not abuse GitHub –
it already does tremendous job.

Using GitHub Action "if: always()" to store screenshots for both
successful builds and errors.

Documentation:
 * https://www.cypress.io/
 * cypress-io/cypress#3199
 * https://help.github.com/en/actions/automating-your-workflow-with-github-actions/development-tools-for-github-actions#set-a-warning-message-warning
 * https://help.github.com/en/actions/automating-your-workflow-with-github-actions/contexts-and-expression-syntax-for-github-actions#job-status-check-functions
aurelijusbanelis pushed a commit to aurelijusb/kickstart that referenced this issue Nov 13, 2019
So it would be clear, that all parts are working correctly,
leaving more time to Code review.

Adding screenshots and debugging intermediate results,
so it would be faster to evaluate and/or fix issues.

Using Cypress as one of Headless browser based test framework.
Cypress is running browser as a separate process,
so it was needed for custom debug function to see intermediate results
in GitHub actions as well.

Using e2e-tests.sh to reach docker network used by docker-compose.yml.

Initial idea was to use GitHub Checks Annotations,
but Cypress already formats output with colors.
So using just different indentation.

Video recording disabled to not abuse GitHub –
it already does tremendous job.

Using GitHub Action "if: always()" to store screenshots for both
successful builds and errors.

Documentation:
 * https://www.cypress.io/
 * cypress-io/cypress#3199
 * https://help.github.com/en/actions/automating-your-workflow-with-github-actions/development-tools-for-github-actions#set-a-warning-message-warning
 * https://help.github.com/en/actions/automating-your-workflow-with-github-actions/contexts-and-expression-syntax-for-github-actions#job-status-check-functions
aurelijusb added a commit to aurelijusb/kickstart that referenced this issue Nov 18, 2019
So it would be clear, that all parts are working correctly,
leaving more time to Code review.

Adding screenshots and debugging intermediate results,
so it would be faster to evaluate and/or fix issues.

Using Cypress as one of Headless browser based test framework.
Cypress is running browser as a separate process,
so it was needed for custom debug function to see intermediate results
in GitHub actions as well.

Using e2e-tests.sh to reach docker network used by docker-compose.yml.

Initial idea was to use GitHub Checks Annotations,
but Cypress already formats output with colors.
So using just different indentation.

Video recording disabled to not abuse GitHub –
it already does tremendous job.

Using GitHub Action "if: always()" to store screenshots for both
successful builds and errors.

Documentation:
 * https://www.cypress.io/
 * cypress-io/cypress#3199
 * https://help.github.com/en/actions/automating-your-workflow-with-github-actions/development-tools-for-github-actions#set-a-warning-message-warning
 * https://help.github.com/en/actions/automating-your-workflow-with-github-actions/contexts-and-expression-syntax-for-github-actions#job-status-check-functions
@dalipkumar703
Copy link

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

@archfz
Copy link

archfz commented Jan 21, 2020

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.

@ggcaponetto
Copy link

@marcellino-ornelas you saved my a**, thanks for sharing

mmbotelho pushed a commit to okTurtles/group-income that referenced this issue Mar 1, 2020
* Remove Member - connect modal to real data

* Start logic...

* Update proposals and implement 1st draft of member removal.

* RemoveMember modal - better layout

* Finish member removal - when isn't a proposal

* Add new icons

* Proposals - update remove member layout

* Try to make this thing work without breaking

* fix file path

* Address review (partially)

* tests - pseudo code

* Make this work even better

* Write tests to remove member

* Fix typos

* Solve Circular dependency problem

* Remove IS_CONSTRUCTOR - Closes #845

* Changes based on review

* Changes based on code review

* Address UI changes based on @mmbotelho review

* More changes based on last review

* Changes based on greg's review

* Improve cypress tests

* fix typos on comments

* Add app logs to Cypress output in case a test fails

cypress-io/cypress#3199 (comment)

* Force a test to fail to see if it works

* Make tests pass again

* Make Cypress logs more readable.

* Better error handling on proposal

* Adapt RULE_DISAGREEMENT threashold for remove member

* Byscotting proposal rule threshold
@karem63
Copy link

karem63 commented Apr 1, 2020

@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() ?

@archfz
Copy link

archfz commented Apr 1, 2020

@alexagranov7
Copy link

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.

@JakubKoralewski
Copy link

@alexagranov7 console.log/console.error etc. work in the browser, what do you mean?

@wdolek
Copy link

wdolek commented Feb 5, 2021

I'm using @archfz 's package cypress-terminal-report which helps a lot when logging within test case - great job!

However on our CI/CD runner (console output only; by console I mean ... console, not window.console), we are experiencing heavy delays between spec execution. What I wanted to do is to print out timestamp before and after spec so I can at least measure delays there. There's even article describing/measuring test time: Where Does the Test Spend Its Time?.

Problem here is that in order to hook on before/after events, I have to use global event handler Cypress.on('test:after:run', ...). Calling console.log here has no effect nor I can't reference cy (to use logging task). I'm already using cypress-terminal-report for printing log events onFail only, whereas I want to print timestamp always - which complicates usage even more.

Is there any way how to achieve this? (If not, I would dare to remove "existing workaround" tag from this issue, @jennifer-shehane)

@jennifer-shehane jennifer-shehane changed the title Ability to console.log output to node console (in support files or Module API) Ability to console.log output from test files to stdout when running via cypress run Feb 9, 2021
@anglichanen
Copy link

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

thank you very much @anton-aurea that's the best solution even after 2 years. That's really helpful and it's possible to see those logs in Docker as well.

@ShaktiMandal
Copy link

ShaktiMandal commented Jan 12, 2023

@anton-aurea @anglichanen 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

thank you very much @anton-aurea that's the best solution even after 2 years. That's really helpful and it's possible to see those logs in Docker as well.

Recently, I am trying to generate log in CI but unable to do so. Added this code, still does not work in CI. Please find below steps which I have followed. It would be great if you let me know whether this can be used in CI and also steps are right or not.

Added below line under support/index.js
Cypress.Commands.overwrite('log', (subject, message) => cy.task('log', message));

Created a index.js file inside plugins folder and pasted below code
export default on => {
on('task', {
log (message) {
console.log(message);
return null
}
});
Last step to add cy.log inside test file.

@kleinfreund
Copy link

The approach provided in #3199 (comment) doesn’t seem to work (anymore?).

I have the following setup:

// cypress/support/commands/index.ts
Cypress.Commands.overwrite('log', function (_subject, message) {
  cy.task('log', message)
})
// cypress/cypress.config.ts
import { defineConfig } from 'cypress'

export default defineConfig({
  e2e: {
    async setupNodeEvents(on, config) {
      on('task', {
        log(message) {
          console.log(message)
          return null
        },
      })

      return config
    },
  },
})

But a cy.log call in my test does absolutely bloody nothing.

I have to say this is immensely frustrating. How am I supposed to understand the failure state of my test without being able to log?

I should really just be able to write console.log statements and have it show up in whatever console my test spills output into.

@n0krashy
Copy link

n0krashy commented Jun 19, 2023

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

Thanks for the solution provided, this is a life safer!
For anyone struggling with Jetbrains Aqua for Cypress, add this to your cypress.config.ts:

export default defineConfig({
  e2e: {
    // Configure your E2E tests here
    specPattern: "cypress/e2e/**/*.{cy,spec}.{js,ts}",

    setupNodeEvents(on, config) {
      on('task', {
        log (message) {
          console.log(message);
          return null
        }
      });
    },
  },
})

And add this to your cypress/support/commands.ts file:

Cypress.Commands.overwrite('log', (subject, message) => cy.task('log', message));

and use cy.log

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
existing workaround stage: proposal 💡 No work has been done of this issue type: feature New feature that does not currently exist
Projects
None yet
Development

No branches or pull requests