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

Unified Handler Tests #2020

Merged
merged 11 commits into from
Sep 28, 2024
1 change: 1 addition & 0 deletions .mocharc.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
allow-uncaught: true
exclude:
- test/helpers/scripts/*.js
exit: true
Expand Down
101 changes: 101 additions & 0 deletions test/helpers/handler-tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
const assume = require('assume');

const helpers = require('.');
const winston = require('../../lib/winston');

module.exports = function ({ helper, listener, name, setup, toggleSetting, trigger }) {
describe('basics', function () {
var handler;

beforeEach(function () {
handler = helpers[helper]();
});

it('has expected methods', function () {
assume(handler.handle).is.a('function');
assume(handler.unhandle).is.a('function');
assume(handler.getAllInfo).is.a('function');
assume(handler.getProcessInfo).is.a('function');
assume(handler.getOsInfo).is.a('function');
assume(handler.getTrace).is.a('function');
});

it(`new ${name}()`, function () {
assume(function () {
// eslint-disable-next-line no-new
new winston[name]();
}).throws(/Logger is required/);
});

it(`new ${name}(logger)`, function () {
var logger = winston.createLogger();
var handler_ = new winston[name](logger);
assume(handler_.logger).equals(logger);
});

it('.getProcessInfo()', function () {
helpers.assertProcessInfo(handler.getProcessInfo());
});

it('.getOsInfo()', function () {
helpers.assertOsInfo(handler.getOsInfo());
});

it('.getTrace(new Error)', function () {
helpers.assertTrace(handler.getTrace(new Error()));
});

it('.getTrace()', function () {
helpers.assertTrace(handler.getTrace());
});

it('.getAllInfo(undefined)', function () {
// eslint-disable-next-line no-undefined
handler.getAllInfo(undefined);
});
});

describe('when error case is triggered', function () {
beforeEach(function () {
this.listeners = helpers[setup]();
});

afterEach(function () {
this.listeners.restore();
});

it('.handle()', function (done) {
var msg = new Date().toString();
var writeable = helpers.writeable(function (info) {
assume(info).is.an('object');
assume(info.error).is.an('error');
assume(info.error.message).equals(msg);
assume(info.message).includes(`${listener}: ${msg}`);
assume(info.stack).is.a('string');
assume(info.process).is.an('object');
assume(info.os).is.an('object');
assume(info.trace).is.an('array');

done();
});

var transport = new winston.transports.Stream({ stream: writeable });
var handler = helpers[helper]({
exitOnError: false,
transports: [transport]
});

assume(handler.catcher).is.a('undefined');

transport[toggleSetting] = true;
handler.handle();

assume(handler.catcher).is.a('function');
assume(process.listeners(listener)).deep.equals([
handler.catcher
]);

trigger(msg);
});
});
};
8 changes: 2 additions & 6 deletions test/helpers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@

const assume = require('assume'),
fs = require('fs'),
path = require('path'),
through = require('through2'),
spawn = require('child_process').spawn,
stream = require('stream'),
util = require('util'),
winston = require('../../lib/winston'),
mockTransport = require('./mocks/mock-transport');

Expand Down Expand Up @@ -100,7 +98,7 @@ helpers.clearExceptions = function () {
*/
helpers.clearRejections = function () {
var listeners = process.listeners('unhandledRejection');
process.removeAllListeners('unhandledRejections');
process.removeAllListeners('unhandledRejection');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the real problem with the tests.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh no 😢


return {
restore: function () {
Expand All @@ -125,9 +123,7 @@ helpers.throw = function (msg) {
* @param {String} msg Error mesage to use
*/
helpers.reject = function (msg) {
return new Promise((resolve, reject) => {
reject(msg);
});
return Promise.reject(msg);
};

/**
Expand Down
119 changes: 10 additions & 109 deletions test/unit/winston/exception-handler.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,117 +6,18 @@
*
*/

const stream = require('stream');
const assume = require('assume');
const mocha = require('mocha');
const winston = require('../../../lib/winston');
const baseHandlerTests = require('../../helpers/handler-tests');
const helpers = require('../../helpers');

//
// This is an awful and fragile hack that
// needs to be changed ASAP.
// https://github.com/mochajs/mocha/issues/1985
//
var _runTest = mocha.Runner.prototype.runTest;
mocha.Runner.prototype.runTest = function () {
this.allowUncaught = true;
_runTest.apply(this, arguments);
};

describe('ExceptionHandler', function () {
this.timeout(5000);

it('has expected methods', function () {
var handler = helpers.exceptionHandler();
assume(handler.handle).is.a('function');
assume(handler.unhandle).is.a('function');
assume(handler.getAllInfo).is.a('function');
assume(handler.getProcessInfo).is.a('function');
assume(handler.getOsInfo).is.a('function');
assume(handler.getTrace).is.a('function');
});

it('new ExceptionHandler()', function () {
assume(function () {
new winston.ExceptionHandler();
}).throws(/Logger is required/);
});

it('new ExceptionHandler(logger)', function () {
var logger = winston.createLogger();
var handler = new winston.ExceptionHandler(logger);
assume(handler.logger).equals(logger);
});

it('.getProcessInfo()', function () {
var handler = helpers.exceptionHandler();
helpers.assertProcessInfo(handler.getProcessInfo());
});

it('.getOsInfo()', function () {
var handler = helpers.exceptionHandler();
helpers.assertOsInfo(handler.getOsInfo());
});

it('.getTrace(new Error)', function () {
var handler = helpers.exceptionHandler();
helpers.assertTrace(handler.getTrace(new Error()));
});

it('.getTrace()', function () {
var handler = helpers.exceptionHandler();
helpers.assertTrace(handler.getTrace());
});

it('.handle()', function (done) {
var existing = helpers.clearExceptions();
var writeable = new stream.Writable({
objectMode: true,
write: function (info) {
assume(info).is.an('object');
assume(info.error).is.an('error');
assume(info.error.message).equals('wtf this error');
assume(info.message).includes('uncaughtException: wtf this error');
assume(info.stack).is.a('string');
assume(info.process).is.an('object');
assume(info.os).is.an('object');
assume(info.trace).is.an('array');

existing.restore();
done();
}
});

var transport = new winston.transports.Stream({ stream: writeable });
var handler = helpers.exceptionHandler({
exitOnError: false,
transports: [transport]
});

assume(handler.catcher).equals(undefined);

transport.handleExceptions = true;
handler.handle();

assume(handler.catcher).is.a('function');
assume(process.listeners('uncaughtException')).deep.equals([
handler.catcher
]);

helpers.throw('wtf this error');
});

it('.getAllInfo(undefined)', function () {
var handler = helpers.exceptionHandler();
// eslint-disable-next-line no-undefined
handler.getAllInfo(undefined);
});

after(function () {
//
// Restore normal `runTest` functionality
// so that we only affect the current suite.
//
mocha.Runner.prototype.runTest = _runTest;
this.timeout(100);

baseHandlerTests({
name: 'ExceptionHandler',
helper: 'exceptionHandler',
setup: 'clearExceptions',
listener: 'uncaughtException',
toggleSetting: 'handleExceptions',
trigger: msg => helpers.throw(msg)
});
});
121 changes: 10 additions & 111 deletions test/unit/winston/rejection-handler.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,119 +6,18 @@
*
*/

const stream = require('stream');
const assume = require('assume');
const mocha = require('mocha');
const winston = require('../../../lib/winston');
const baseHandlerTests = require('../../helpers/handler-tests');
const helpers = require('../../helpers');

//
// This is an awful and fragile hack that
// needs to be changed ASAP.
// https://github.com/mochajs/mocha/issues/1985
//
var _runTest = mocha.Runner.prototype.runTest;
mocha.Runner.prototype.runTest = function () {
this.allowUncaught = true;
_runTest.apply(this, arguments);
};

describe('UnhandledRejectionHandler', function () {
this.timeout(5000);

it('has expected methods', function () {
var handler = helpers.rejectionHandler();
assume(handler.handle).is.a('function');
assume(handler.unhandle).is.a('function');
assume(handler.getAllInfo).is.a('function');
assume(handler.getProcessInfo).is.a('function');
assume(handler.getOsInfo).is.a('function');
assume(handler.getTrace).is.a('function');
});

it('new RejectionHandler()', function () {
assume(function () {
new winston.RejectionHandler();
}).throws(/Logger is required/);
});

it('new RejectionHandler(logger)', function () {
var logger = winston.createLogger();
var handler = new winston.RejectionHandler(logger);
assume(handler.logger).equals(logger);
});

it('.getProcessInfo()', function () {
var handler = helpers.rejectionHandler();
helpers.assertProcessInfo(handler.getProcessInfo());
});

it('.getOsInfo()', function () {
var handler = helpers.rejectionHandler();
helpers.assertOsInfo(handler.getOsInfo());
});

it('.getTrace(new Error)', function () {
var handler = helpers.rejectionHandler();
helpers.assertTrace(handler.getTrace(new Error()));
});

it('.getTrace()', function () {
var handler = helpers.rejectionHandler();
helpers.assertTrace(handler.getTrace());
});

it('.handle()', function (done) {
process.removeAllListeners('unhandledRejection');
var existing = helpers.clearRejections();
var writeable = new stream.Writable({
objectMode: true,
write: function (info) {
assume(info).is.an('object');
assume(info.error).is.an('error');
assume(info.rejection).is.true();
assume(info.error.message).equals('wtf this rejection');
assume(info.message).includes('unhandledRejection: wtf this rejection');
assume(info.stack).is.a('string');
assume(info.process).is.an('object');
assume(info.os).is.an('object');
assume(info.trace).is.an('array');

existing.restore();
done();
}
});

var transport = new winston.transports.Stream({ stream: writeable });
var handler = helpers.rejectionHandler({
exitOnError: false,
transports: [transport]
});

assume(handler.catcher).equals(undefined);

transport.handleRejections = true;
handler.handle();

assume(handler.catcher).is.a('function');
assume(process.listeners('unhandledRejection')).deep.equals([
handler.catcher
]);

helpers.reject(new Error('wtf this rejection'));
});

it('.getAllInfo(undefined)', function () {
var handler = helpers.rejectionHandler();
// eslint-disable-next-line no-undefined
handler.getAllInfo(undefined);
});

after(function () {
//
// Restore normal `runTest` functionality
// so that we only affect the current suite.
//
mocha.Runner.prototype.runTest = _runTest;
this.timeout(100);

baseHandlerTests({
name: 'RejectionHandler',
helper: 'rejectionHandler',
setup: 'clearRejections',
listener: 'unhandledRejection',
toggleSetting: 'handleRejections',
trigger: msg => helpers.reject(new Error(msg))
});
});
Loading