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

Suppress console.log output from tests that succeed #1998

Closed
justinmchase opened this issue Dec 7, 2015 · 15 comments
Closed

Suppress console.log output from tests that succeed #1998

justinmchase opened this issue Dec 7, 2015 · 15 comments

Comments

@justinmchase
Copy link

I do not want to see debug output from tests that succeed but would like to see it for tests that fail. Is there a way to achieve this currently?

I have seen some recommendations to only conditionally log based on environment variables in responses to similar questions but I would like to see the debug information if the test fails which is slightly different. It seems like that would be a mocha level or reporter level feature, not something the code under test could control.

@dasilvacontin
Copy link
Contributor

@justinmchase Only via plugins, if any exist. No place for this in mocha's core, imo.

Proxying console.log feels error prone. As a first thought, safest bet feels like creating a log utility that stores the calls' argument arrays to later log them on test 'fail' (via hooking into mocha).

@justinmchase
Copy link
Author

Thanks for the reply! That sounds totally reasonable.

Do you have an example of hooking into the mocha fail event that I could reference? I am having trouble figuring out where to begin.

@motiz88
Copy link

motiz88 commented Aug 3, 2016

This is an old issue, but I found this StackOverflow answer useful. Inspecting this.currentTest.state in an afterEach handler on the root suite looks like a good way to intercept all test failures.

// On the root suite - so outside any describe() block
afterEach(function() {
  if (this.currentTest.state === 'failed') {
    // a test just failed
  }
  if (this.currentTest.state !== 'passed') {
    // a test, before(), or beforeEach() hook just failed
  }
});

@danielstjules
Copy link
Contributor

There's been a pretty long thread about this in the past. A possible workaround was proposed here: #1582 (comment)

@ORESoftware
Copy link

there should be a flag --errors-only, which would mean the only Mocha output would be for failing tests, but not sure if it exists.

@justinmchase
Copy link
Author

justinmchase commented Oct 26, 2016

The solution I've come up with since is to use the debug package and to use that in all of your code. Then you can send a command line flag to turn on console logging in tests as desired.

var debug = require('debug')
var log = debug('myapp')

log('useful debugging output')

Then when run:

$ mocha # no console output from app

or

$ DEBUG=myapp mocha # prints out console output from app

Combine this with the --grep argument to get console out put from only one test specifically.

@AdrienHorgnies
Copy link

@justinmchase Not sure to quite understand.
I'm developing a console app which logs things. I don't want these logs to happen during tests because it could potentially render mocha output unreadable. How does your solution apply to this ?

@justinmchase
Copy link
Author

justinmchase commented Aug 3, 2017

For a lot of apps, console logging is only for developer debugging, like for a webserver maybe. In those cases just using the debug library works great.

If your app is itself an actual console application, which intentionally emits console output as a feature then you'll probably need another layer of abstraction. One other thing i have done since this issue was originally opened, which I thought worked well is to separate the logic of the application from the console front end part of the application. Sort of treat it like your code may have multiple front ends and then treat your tests as a 2nd front-end.

Or in other words, do not actually do any console logging inside of your application but instead emit events which the front end can handle. In the case of the console front-end, it will result in writes to standard out. In the case of unit tests it will result in passing/failing assertions.

For example:

// console.js
import { App } from './app'

const app = new App()
app.on('started', () => console.log('application started...')
app.on('done', () => console.log('application done.')
app.run()
// app.spec.js
import { App } from './app'
import sinon from 'sinon'
import { expect } from 'chai'

it('runs successfully', (done) => {
  const started = sinon.stub()
  const app = new App()
  app.on('started', started)
  app.on('done', () => {
    expect(started.called).to.be.true
    done()
  })
  app.start()
})

The point is that the code in App does not actually call console.log anywhere. Instead it is emitting events or messages or whatever pattern you want to use, irrespective of how those events are displayed to the end user or interpreted by the front-end.

@ORESoftware
Copy link

ORESoftware commented Aug 3, 2017

my only advice would be to use a logging module like bunyan instead of console.log and filter out the output that is above level error

mocha test | bunyan -l error

@AdrienHorgnies
Copy link

AdrienHorgnies commented Aug 3, 2017

@justinmchase I really like this idea of a console front end... It looks kind of obvious when you think of it.
My current solution is to mock console.log with https://github.com/sinonjs/sinon, make expectations about what it should log and then call the original console.log through for what is not expected. You can see such an example here.

Your solution is much cleaner... Well, my logging activity is tested now.

@sladec
Copy link

sladec commented Nov 18, 2017

I can't believe this is not a "thing", I am new to using TDD and one of the first things that annoys me is on
test failure I end up inserting console.log's in tests to check object states etc, then when all fixed I am back removing all log's as it pushes results output out of view of console window.
I would love something like onTestFail( console.log(....) );

@ViggoV
Copy link

ViggoV commented Dec 5, 2018

I agree. During development I will often console.log complex objects, for example React props from HOC components like Apollo. This works great in browser were the object can be collapsed and expanded, but just one of those during tests can render the output next to useless.

Like @sladec I'm confused as to how this is not a common problem with a built-in solution, but that is the case with many issues I've hit upon adopting Mocha and TDD.

In any case another workaround if you use Webpack might be to suppress console.log in your test config. A quick search suggests using UglifyJSPlugin or something like webpack-strip. I haven't tested it though..

@justinmchase
Copy link
Author

justinmchase commented Dec 5, 2018

Again, @ViggoV I think what you should do is use the debug library instead of console.log directly for in app debugging. Then to emit actually to the console in your app, handle events in a front-end component which logs to the console.

For example:

import debug from 'debug'

const log = debug('server');

export function server () {
  // ...
  log('server started...')
}

Now when you run this locally or in a test nothing will be written to stdout by default. To enable this debug output to be written to stdout you would enable it with an environment variable.

For example:

$ npm test              # <> is emitted
$ DEBUG=server npm test # <server started...> is emitted

@gsimon75
Copy link

gsimon75 commented Sep 7, 2020

Unfortunately if when some prerequisite package contains 'console.log' calls, we have very few control over it at that level.

For example, oas3-tools 2.0.2 contains page-long dumps from here:
./node_modules/oas3-tools/dist/middleware/swagger.router.js:36:
console.log("handlerCache[handlerId]: "); console.log(handlerCache[handlerId]);

As I can't pause our processes for months until a fix for that would make it to the official packages, (and this is just one such package among several,) all I can do now is to suppress these messages on the test-suite level.

Now, I'll need one of the hacks/workarounds, which will make the testcases more complex: As I don't intend to copy it into each and every testcase file, I'll need to compartmentalize it into some module and refer that from the testcase files, and so on.

I think I'm not alone with this issue, and now each of us is reinventing the same wheels, reimplementing the same workarounds, so if there is popularity survey for having that as a built-in framework feaure, you definitely have my vote for it.

Meanwhile, here is my loghack module, and a small loghack test for it. (It should handle nested invocations as well, though I haven't tested that yet.)

@AleG94
Copy link

AleG94 commented Nov 19, 2020

I wrote my own module to solve the same exact issue with minimal effort so I'll leave a link if anyone is interested.

https://www.npmjs.com/package/mocha-suppress-logs

Here's some example code that will hide logs of tests that succeed and show only the ones of tests that failed:

const suppressLogs = require('mocha-suppress-logs');
 
describe('Something', () => {
  suppressLogs();
 
  it('should do something', () => {
    // test code
  });
});

You can also do so globally over the entire test suite.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants