@brainbits/node-logger
Version:
Logger for node projects
244 lines (193 loc) • 8.09 kB
JavaScript
/* eslint-disable import/no-absolute-path, import/no-unresolved */
import fs from 'fs';
import loadConfiguration from './config';
// eslint-disable-next-line import/extensions
import formatter from '/some/root/testpackage/node_modules/@brainbits/node-node-logger-formatter-test';
// eslint-disable-next-line import/extensions
import Plugin from '/some/root/testpackage/node_modules/@brainbits/node-node-logger-sentry-plugin';
import packageJson from '/some/root/testpackage/package.json';
jest.mock('fs');
jest.mock(
'/some/root/testpackage/node_modules/@brainbits/node-node-logger-formatter-test',
() => ({ default: jest.fn() }),
{ virtual: true },
);
jest.mock(
'/some/root/testpackage/node_modules/@brainbits/node-node-logger-sentry-plugin',
() => ({ default: jest.fn() }),
{ virtual: true },
);
jest.mock('/some/root/testpackage/package.json', () => ({
name: 'testpackage',
nodeLogger: {
channel: 'test-channel',
levels: [
'error',
'info',
'debug',
],
outputs: {
error: 'stdout',
},
formatter: '@brainbits/node-node-logger-formatter-test',
},
}), { virtual: true });
describe('loadConfiguration', () => {
beforeEach(() => {
fs.existsSync.mockReturnValue(false);
jest.spyOn(process, 'cwd').mockReturnValue('/some/root/testpackage');
});
describe('validation', () => {
it('throws an error if formatter is missing', () => {
const expectedError = new Error('Invalid formatter: No formatter found in configuration');
expect(() => loadConfiguration()).toThrow(expectedError);
});
it('throws an error if levels are null', () => {
const expectedError = new Error('Invalid levels: No levels were configured');
expect(() => loadConfiguration({ formatter: jest.fn(), levels: null }))
.toThrow(expectedError);
});
it('throws an error if levels are an empty array', () => {
const expectedError = new Error('Invalid levels: No levels were configured');
expect(() => loadConfiguration({ formatter: jest.fn(), levels: [] }))
.toThrow(expectedError);
});
it('throws an error if no maxLevel is configured', () => {
const expectedError = new Error('Invalid maxLevel: null');
expect(() => loadConfiguration({ formatter: jest.fn(), maxLevel: null }))
.toThrow(expectedError);
});
it('throws an error if maxLevel is no valid level', () => {
const expectedError = new Error('Invalid maxLevel: foobar');
expect(() => loadConfiguration({ formatter: jest.fn(), maxLevel: 'foobar' }))
.toThrow(expectedError);
});
it('throws an error if no timerLevel is configured', () => {
const expectedError = new Error('Invalid timerLevel: null');
expect(() => loadConfiguration({ formatter: jest.fn(), timerLevel: null }))
.toThrow(expectedError);
});
it('throws an error if timerLevel is no valid level', () => {
const expectedError = new Error('Invalid timerLevel: foobar');
expect(() => loadConfiguration({ formatter: jest.fn(), timerLevel: 'foobar' }))
.toThrow(expectedError);
});
it('throws an error if no outputs were configured', () => {
const expectedError = new Error('Invalid outputs: Outputs can only be configured for existing log levels');
expect(() => loadConfiguration({ formatter: jest.fn(), outputs: null }))
.toThrow(expectedError);
});
it('throws an error if output was configured for invalid level', () => {
const expectedError = new Error('Invalid outputs: Outputs can only be configured for existing log levels');
expect(() => loadConfiguration({ formatter: jest.fn(), outputs: { foobar: 'stdout' } }))
.toThrow(expectedError);
});
it('throws an error if output is anything but stdout or stderr', () => {
const expectedError = new Error('Invalid outputs: Output must be stdout or stderr');
expect(() => loadConfiguration({ formatter: jest.fn(), outputs: { error: 'stdin' } }))
.toThrow(expectedError);
});
});
it('resolves to default configuration', () => {
const config = loadConfiguration({ formatter: jest.fn() });
expect(config).toMatchObject({
channel: 'unknown',
levels: [
'emergency',
'alert',
'critical',
'error',
'warning',
'notice',
'info',
'debug',
],
maxLevel: 'info',
outputs: {
emergency: 'stderr',
warning: 'stdout',
},
timerLevel: 'debug',
plugins: [],
});
});
describe('with package.json', () => {
beforeEach(() => {
fs.existsSync.mockReturnValue(true);
fs.statSync.mockReturnValue({ isFile: jest.fn().mockReturnValue(true) });
});
it('merges configuration with defaults', () => {
const config = loadConfiguration();
expect(config).toMatchObject({
channel: packageJson.nodeLogger.channel,
levels: packageJson.nodeLogger.levels,
maxLevel: 'info',
outputs: {
error: 'stdout',
},
timerLevel: 'debug',
plugins: [],
formatter: formatter.default,
});
});
it('uses package name as channel if none was set explicitly', () => {
delete packageJson.nodeLogger.channel;
const config = loadConfiguration();
expect(config).toMatchObject({
channel: packageJson.name,
});
});
it('prioritizes manual configuration over package.json', () => {
const config = loadConfiguration({ channel: 'foobar' });
expect(config).toMatchObject({
channel: 'foobar',
});
});
});
describe('with plugins', () => {
beforeEach(() => {
fs.existsSync.mockReturnValue(true);
});
it('instantiates plugins', () => {
const config = loadConfiguration({
formatter: jest.fn(),
plugins: ['@brainbits/node-node-logger-sentry-plugin'],
});
expect(config.plugins).toHaveLength(1);
expect(config.plugins[0]).toBeInstanceOf(Plugin.default);
});
});
describe('environment variables', () => {
it('are parsed correctly', () => {
process.env.MY_TEST = 'foobar';
const config = loadConfiguration({
formatter: jest.fn(),
channel: 'env(MY_TEST)',
});
delete process.env.MY_TEST;
expect(config.channel).toEqual('foobar');
});
it('use default value if given', () => {
const config = loadConfiguration({
formatter: jest.fn(),
channel: 'env(MY_TEST, baz)',
});
expect(config.channel).toEqual('baz');
});
it('throws error on missing variable', () => {
delete process.env.MY_TEST;
expect(() => loadConfiguration({
formatter: jest.fn(),
channel: 'env(MY_TEST)',
})).toThrow(/MY_TEST/);
});
it('allow empty strings as valid values', () => {
process.env.MY_TEST = '';
const config = loadConfiguration({
formatter: jest.fn(),
channel: 'env(MY_TEST)',
});
expect(config.channel).toEqual('');
});
});
});