I am writing a logging framework in Nodejs using winston logger. Now I have to write unit test to test my class using jest.
Below is my LoggerClass:
'use strict';
const { createLogger, format, transports } = require('winston');
const fs = require('fs');
const env = process.env.NODE_ENV || 'development';
const logger = createLogger({
level: env === 'development' ? 'debug' : 'info',
format: format.combine(
format.timestamp({
format: 'YYYY-MM-DD HH:mm:ss'
}),
format.printf(info => `${info.timestamp} ${info.level}: ${info.message}`)),
transports: [
new transports.Console({
level: 'info',
format: format.combine(
format.printf(
info => `${info.level}: ${info.message}`
)
)
}),
new transports.File({ filename })
]
});
module.exports = logger;
I have written the test as:
const logger = require('./WinstonLogger');
global.console = {
log: jest.fn(),
info: jest.fn(),
error: jest.fn(),
}
describe('Tests my console.log', () => {
it('should console a message', () => {
logger.info('Hello world');
expect(global.console.log).toHaveBeenCalledWith(
'info: Hello world'
)
})
})
How can i modify my test?
Here is the unit test solution:
logger.js
:
'use strict';
const { createLogger, format, transports } = require('winston');
const env = process.env.NODE_ENV || 'development';
const filename = 'filename';
const logger = createLogger({
level: env === 'development' ? 'debug' : 'info',
format: format.combine(
format.timestamp({
format: 'YYYY-MM-DD HH:mm:ss',
}),
format.printf((info) => `${info.timestamp} ${info.level}: ${info.message}`),
),
transports: [
new transports.Console({
level: 'info',
format: format.combine(format.printf((info) => `${info.level}: ${info.message}`)),
}),
new transports.File({ filename }),
],
});
module.exports = logger;
logger.test.js
:
jest.mock('winston', () => {
const mFormat = {
combine: jest.fn(),
timestamp: jest.fn(),
printf: jest.fn(),
};
const mTransports = {
Console: jest.fn(),
File: jest.fn(),
};
const mLogger = {
info: jest.fn(),
};
return {
format: mFormat,
transports: mTransports,
createLogger: jest.fn(() => mLogger),
};
});
const { createLogger, format, transports } = require('winston');
describe('logger', () => {
afterEach(() => {
jest.resetAllMocks();
});
it('should pass', () => {
let templateFunctions = [];
format.printf.mockImplementation((templateFn) => {
templateFunctions.push(templateFn);
});
const logger = require('./logger');
logger.info('Hello world');
const info = {
timestamp: 123,
level: 'info',
message: 'haha',
};
const tFn1 = templateFunctions.shift();
expect(tFn1(info)).toBe(`${info.timestamp} ${info.level}: ${info.message}`);
const tFn2 = templateFunctions.shift();
expect(tFn2(info)).toBe(`${info.level}: ${info.message}`);
expect(format.combine).toBeCalledTimes(2);
expect(format.timestamp).toBeCalledWith({ format: 'YYYY-MM-DD HH:mm:ss' });
expect(format.printf).toBeCalledWith(expect.any(Function));
expect(transports.Console).toBeCalledTimes(1);
expect(transports.File).toBeCalledWith({ filename: 'filename' });
expect(createLogger).toBeCalledTimes(1);
});
});
Unit test result with coverage report:
PASS src/stackoverflow/59388359/logger.test.js (10.484s)
logger
✓ should pass (10ms)
-----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
-----------|----------|----------|----------|----------|-------------------|
All files | 100 | 50 | 100 | 100 | |
logger.js | 100 | 50 | 100 | 100 | 5,9 |
-----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 11.789s
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59388359