Print to process.stdout.write with mocha - node.js

I am writing a logging module for nodejs. I am using process.stdout.write to output my data, mostly to avoid the trailing new line that comes with console.log. However, the disadvantage to this is that mocha appears to write to this as well, so that my logging application displays no output. Is there anything I can do to avoid or get around this behavior?
Update: Whether or not process.stdout.write is displayed depends on the mocha reporter.
Edit:
Here is some code to reproduce what I am seeing:
//module.js
exports.log = function(message, printmethod) {
if(printmethod = 0)
console.log(message);
}
if(printmethod = 1) {
process.stdout.write(message);
}
}
//Mocha test:
module = require('module');
var message = "testing";
describe("Testing Output", function () {
it("Prints to console.log", function (done) {
//This will show up in mocha output
module.log(message, 0);
done();
})
it("Prints to stdout", function (done) {
//This won't show up in mocha output
module.log(message, 1);
done();
})
})

Related

How can I stop Jest wrapping `console.log` in test output?

I'm making a Jest test with request
describe("GET /user ", () => {
test("It should respond with a array of users", done => {
return request(url, (err, res, body) => {
if (err) {
console.log(err)
} else {
console.log("GET on " + url);
body = JSON.parse(body);
expect(body.length).toBeGreaterThan(0);
done();
}
})
})
});
and it's weird because in the terminal, jest is showing console.log line as part of the output:
...test output...
console.log test/modules/user.test.js:18
GET on https://xpto/api/user
...more test output...
I need to hide the line:
console.log test/modules/user.test.js:18
How to hide console.log line in Jest output?
You can replace Jest's console implementation with the "normal" console like this:
const jestConsole = console;
beforeEach(() => {
global.console = require('console');
});
afterEach(() => {
global.console = jestConsole;
});
If it's a test you've written, why do you even need to log the error? You can rely on jest assertions for that.
If you have no other solution, you can stub out the console.log function like so:
const log = console.log;
console.log = () => {};
/** Test logic goes here **/
console.log = log; // Return things to normal so other tests aren't affected.
You can use jest.spyOn to mock the console methods:
const spy = jest.spyOn(console,'warn').mockReturnValue()
// after you are done with the test, restore the console
spy.mockRestore()
You can create a utility function to mock the console:
function mockConsole(method = 'warn', value){
return jest.spyOn(console,method).mockReturnValue(value).mockRestore
}
const restore = mockConsole() //mock it
// later when you are done
restore() // unmock it
Also, you can combine above code answers with jest.beforeEach to automatically restore the console:
beforeEach(()=>{
// beware that this will restore all mocks, not just the console mock
jest.restoreAllMocks()
})
You need to create your own log function with process.stdout.write or use it instead of console.log because jest is spying on all console functions.
While ago I have been trying to bring to Typescript one utility that I really like in Scala; GivenWhenThen annotations in tests and I encountered the same problem as you. I don't understand why jest prints these "consol.log + line", it doesn't make sense because you can easily find them with Crt + Find and there is no option to switch them off with --silent and --verbose=false options (of course silent will work but it will remove all log so what is the point).
Finally, I came up with:
const colors = require('colors');
const testLog = (str : string) => process.stdout.write(str)
export const Given = (givenMsg: string) => testLog(`\n+ Given ${givenMsg}\n`)
export const When = (whenMsg: string) => testLog(`+ When ${whenMsg}\n`)
export const Then = (thenMsg: string) => testLog(`+ Then ${thenMsg}\n`)
export const And = (andMsg: string) => testLog(`- And ${andMsg}\n`)
export const testCase = (description: string, testFunction: Function) => it (description, () => {
testLog(colors.yellow(`\n\nTest: ${description}\n`))
testFunction()
testLog('\n')
})
Looked like this:
given when then typescript
You could try running jest with the --silent argument.
In package.json, use two scripts:
"scripts": {
"test": "jest --silent",
"testVerbose": "jest"
},

How to test promise rejection with Mocha and Chai in Node?

I am trying to test my services and dao using Mocha and Chai. But, in Istanbul coverage, I am getting the 'reject' lines as red. Here is the code for a sample testing method.
describe('findAllCategories()', function() {
it('should return all categories', function() {
var stub = sinon.stub(categoryDao, 'findAllCategories');
stub.callsFake(() => {
return Promise.resolve(cat);
});
categoryService.findAllCategories().then(response => {
assert.length(response, 1);
}).catch(isError)
.then((err) => {
console.log(err);
assert.isDefined(err);
});
})
});
Now, when I'm logging the error, it is showing "TypeError: assert.length is not a function".
Any way out?
The assert-library does not have a function length, but instead you can use lengthOf() (see https://www.chaijs.com/api/assert/ for more information):
assert.lengthOf(response, 1);

mocha/chai return undefined

I have a working node script and am now trying to learn mocha/chai to add some unit tests.
//Module Code
var path = require('path');
var recursive = require('recursive-readdir');
function findData(folderPath) {
recursive(folderPath, function (err, files) {
return files;
});
};
module.exports.findData = findData;
My mocha test code:
var expect = require('chai').expect;
describe('checkData', function () {
var findData = require('../custom_modules/findData').findData;
var path;
before (function () {
path = '/Data'
});
it('should have 53 files in array', function () {
expect(findData(path)).to.have.lengthOf(53);
})
});
However, it always fails because the return seems to be undefined. So i stripped my module code back to test a return true and that worked.
So it must the the asynchronous nature of the recursive module so I then tried add in callbacks to my module code:
var path = require('path');
var recursive = require('recursive-readdir');
function findData(folderPath, cb) {
recursive(folderPath, function (err, files) {
cb(null, files);
});
};
module.exports.findData = findData;
But that didn't work either.
The weird thing is if I run node index.js i get the list of files.
Can anyone explain to me how this code can work normally but when I try to use mocha/chai to test I get undefined?
Thanks
EDITED:
So based on what #Louis said in the comments I have added a callback to the function.
describe('checkData', function () {
var findData = require('../custom_modules/findData').findData;
var path;
var files;
before (function () {
path = '/Users/tjmartin/Documents/OSData/OpenNames/Data'
});
it('should have 53 files in array', function () {
expect(findData(path, function(results) {
files = results;
})).to.have.lengthOf(53);
})
});
But this still returns an undefined.
First up, I would log the err result in your findData implementation. Even if only during development, so you can easily see if any errors are reported (you may be doing this already, just wanted to mention it).
As you have spotted, one of the main causes of problems for you is that the callback is asynchronous. So you can't simply return it from your findData method as in your original example.
Next, I wouldn't hard-code the path as you have in the before function. Instead use a local path, so that the test can be run as part of your CI (if you ever have one) or even so you can grab it on another machine and have it work there.
before(function() {
path = './tests/TestData';
});
In your revised example, although you are using a callback you are testing the return result still. You need to alter your test to use the result of the callback.
it('should have 53 files in array', function(done) {
findData(path, function(results) {
expect(results).to.have.lengthOf(53);
done();
});
});

How to unit test console output with mocha on nodejs?

Take into account the following example Javascript code below:
function privateFunction (time) {
if (time < 12) { console.log('Good morning'); }
if (time >= 12 && time <19) { console.log('Good afternoon'); }
else { console.log('Good night!'); }
};
How should I unit test that on nodejs using mocha (and possibly sinonjs), noticing that this is a private function called inside a module? I need to pass in the argument and check if the function is logging the right thing to the console.
Can I do the same with console.warn and console.error?
I prefer mocha-sinon over "plain" sinon because it integrates nicely with Mocha.
Example:
var expect = require('chai').expect;
require('mocha-sinon');
// Function to test, can also be in another file and as long as it's
// being called through some public interface it should be testable.
// If it's not in any way exposed/exported, testing will be problematic.
function privateFunction (time) {
if (time < 12) { console.log('Good morning'); }
if (time >= 12 && time <19) { console.log('Good afternoon'); }
else { console.log('Good night!'); }
}
describe('privateFunction()', function() {
beforeEach(function() {
this.sinon.stub(console, 'log');
});
it('should log "Good morning" for hours < 12', function() {
privateFunction(5);
expect( console.log.calledOnce ).to.be.true;
expect( console.log.calledWith('Good morning') ).to.be.true;
});
it('should log "Good afternoon" for hours >= 12 and < 19', function() {
privateFunction(15);
expect( console.log.calledOnce ).to.be.true;
expect( console.log.calledWith('Good afternoon') ).to.be.true;
});
it('should log "Good night!" for hours >= 19', function() {
privateFunction(20);
expect( console.log.calledOnce ).to.be.true;
expect( console.log.calledWith('Good night!') ).to.be.true;
});
});
One potential issue: some Mocha reporters use console.log as well, so the tests that stub it may not yield any output.
There's a workaround, but it's not ideal either because it will intersperse Mocha output with the output from privateFunction(). If that's not a problem, replace beforeEach() with this:
beforeEach(function() {
var log = console.log;
this.sinon.stub(console, 'log', function() {
return log.apply(log, arguments);
});
});
ignoring the fact that it's a private function, i would take a couple of steps; refactor my code for better separation of concerns, and utilise this separation with test doubles.
take all the side effects outside to their own modules (the side effect here is writing to the console):
out.js
function log (message) {
console.log(message);
};
module.exports = {log};
app.js
const {log} = require('out');
function greeter (time) {
if (time < 12) {
log('Good morning');
}
if (time >= 12 && time < 19) {
log('Good afternoon');
} else {
log('Good night!');
}
};
module.exports = {greeter};
use some module proxy/spy, like proxyquire to replace the whole out writer when testing:
app.spec.js
describe('output writers', function(){
const fakeOut = {
log: sinon.spy(),
};
const app = proxyquire('./app', {
'out': fakeOut
});
it('should log to the fake out', function(){
app.greeter(15);
assert(fakeOut.log.calledOnce);
});
});
If your purpose is solely to test console output, I would suggest instead of stubs / spies etc on method calls, to use something like:
test-console
monitor stdout/stderr instead, you can use ideas from this gist

'then' function is not never getting called by Mocha for assertion checking

I have written the following test case in Mocha, where the my code uses Q module.
var expect = require("chai").expect;
var utils = require("../Utils.js");
var utils1 = require("../a.js");
var sinon = require('sinon');
var request = require('requestretry');
var querySys = require('../b.js');
var Q = require("q");
describe("Sample", function () {
var results;
describe("#get()", function () {
before(function (done) {
done();
});
it("equal", function () {
var deferred = Q.defer();
var responseData = {};
responseData.code = 200;
responseData.data = [{a:1,b:2}];
deferred.resolve(responseData);
//querySys1 method uses Q promises. That is how I stubbed the response.
sinon.stub(querySys, 'querySys1').returns(deferred.promise);
//get function internally calls querySys1. Hence I have stubbed that.
results = utils1.get(specification);
results.then(function (data) {
//Here I do see data coming as {in:1, out:1}. But still the test case is passing when compare it with {}.
console.log(data);
//Ideally, it should have failed. But it is passing.
expect(data).to.be.equal({});
});
});
after(function (done) {
done();
})
});
});
So, if you see, I am trying to do assertion check in results.then part. I have printed the response, which I am receiving. That is coming as expected. But I am intentionally trying to match with wrong value, but test case is still passing.
Since your test does not include a callback, execution runs through the main block and declares the test as passing without waiting for the result of the then function. You need to let mocha know to wait for the callback:
it("equal", function (done) {
...
results.then(function (data) {
console.log(data);
expect(data).to.be.equal({});
return done();
});
});
When I changed results.then to results.done, test started failing as expected. Can someone say whether this is the right approach.

Resources