/* eslint-disable @typescript-eslint/no-explicit-any */ /* * Copyright (C) 2018, 2020 StApps * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation, version 3. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ import chai from 'chai'; import {expect} from 'chai'; import chaiAsPromised from 'chai-as-promised'; import chaiSpies from 'chai-spies'; import {Logger, AddLogLevel, Colorize} from '../src/index.js'; import {DummyTransport} from './dummy-transport.js'; import path from 'node:path'; import chalk from 'chalk'; chai.should(); chai.use(chaiSpies); chai.use(chaiAsPromised); chalk.level = 2; describe('Logger', function () { const sandbox = chai.spy.sandbox(); beforeEach(function () { Logger.setTransformations([new AddLogLevel()]); }); afterEach(function () { sandbox.restore(); }); it('should read default log level', async function () { expect((Logger as any).getLevel('LOG')).to.be.equal(31); expect((Logger as any).getLevel('EXIT')).to.be.equal(0); }); it('should error', async function () { const spy = sandbox.on(console, 'error', () => { // noop }); await Logger.error('Foobar'); expect(spy).to.have.been.called(); expect(spy.__spy.calls[0][0]).to.contain('[ERROR]'); expect(spy.__spy.calls[0][0]).to.contain('Foobar'); }); it('should error in productive environment', async function () { const spy = sandbox.on(console, 'error', () => { // noop }); const nodeEnvironment = process.env.NODE_ENV; process.env.NODE_ENV = 'production'; await Logger.error('Foobar').should.be.rejectedWith(Error); expect(spy).to.have.been.called.exactly(1); process.env.ALLOW_NO_TRANSPORT = 'true'; await Logger.error('Foobar').should.not.be.rejectedWith(Error); expect(spy).to.have.been.called.exactly(2); delete process.env.ALLOW_NO_TRANSPORT; Logger.setTransport(new DummyTransport()); await Logger.error('Foobar').should.not.be.rejectedWith(Error); expect(spy).to.have.been.called.exactly(3); Logger.setTransport(); process.env.NODE_ENV = nodeEnvironment; }); it('should error without output', async function () { const spy = sandbox.on(console, 'error', () => { // noop }); process.env.STAPPS_LOG_LEVEL = '0'; await Logger.error('Foobar'); delete process.env.STAPPS_LOG_LEVEL; expect(spy).not.to.have.been.called(); }); it('should error with Error', async function () { const spy = sandbox.on(console, 'error', () => { // noop }); // eslint-disable-next-line unicorn/error-message await Logger.error(new Error()); expect(spy).to.have.been.called(); expect(spy.__spy.calls[0][0]).to.contain('Error'); const directory = process.cwd().replaceAll(path.sep, path.posix.sep); expect(spy.__spy.calls[0][0]).to.contain(directory); }); it('should info', function () { const spy = sandbox.on(console, 'info', () => { // noop }); Logger.info('Foobar'); expect(spy).to.have.been.called(); expect(spy.__spy.calls[0][0]).to.contain('[INFO]'); expect(spy.__spy.calls[0][0]).to.contain('Foobar'); }); it('should exit', async function () { const infoSpy = sandbox.on(console, 'info', () => { // noop }); const logSpy = sandbox.on(console, 'log', () => { // noop }); const warnSpy = sandbox.on(console, 'warn', () => { // noop }); const errorSpy = sandbox.on(console, 'error', () => { // noop }); const processSpy = sandbox.on(process, 'exit', () => { // noop }); const exitLevel = process.env.STAPPS_EXIT_LEVEL; process.env.STAPPS_EXIT_LEVEL = '31'; Logger.info('Foobar'); Logger.log('Foobar'); Logger.warn('Foobar'); Logger.ok('Foobar'); await Logger.error('Foobar'); expect(infoSpy).to.have.been.called.once; expect(infoSpy.__spy.calls[0][0]).to.contain('[INFO]'); expect(infoSpy.__spy.calls[0][0]).to.contain('Foobar'); expect(logSpy).to.have.been.called.twice; expect(warnSpy).to.have.been.called.once; expect(warnSpy.__spy.calls[0][0]).to.contain('[WARN]'); expect(warnSpy.__spy.calls[0][0]).to.contain('Foobar'); expect(errorSpy).to.have.been.called.exactly(6); expect(processSpy).to.have.been.called.exactly(5); process.env.STAPPS_EXIT_LEVEL = exitLevel; }); it('should info without output', function () { const spy = sandbox.on(console, 'info', () => { // noop }); process.env.STAPPS_LOG_LEVEL = '0'; Logger.info('Foobar'); delete process.env.STAPPS_LOG_LEVEL; expect(spy).not.to.have.been.called; }); it('should be initialized', function () { Logger.setTransport(new DummyTransport()); expect(() => { Logger.initialized(); }).not.to.throw(); Logger.setTransport(); }); it('should be initialized in productive environment', function () { const nodeEnvironment = process.env.NODE_ENV; process.env.NODE_ENV = 'production'; Logger.setTransport(new DummyTransport()); expect(() => { Logger.initialized(); }).not.to.throw(); Logger.setTransport(); expect(() => { Logger.initialized(); }).to.throw(); const spy = sandbox.on(console, 'warn', () => { // noop }); process.env.ALLOW_NO_TRANSPORT = 'true'; expect(() => { Logger.initialized(); }).not.to.throw(); delete process.env.ALLOW_NO_TRANSPORT; expect(spy).to.have.been.called(); process.env.NODE_ENV = nodeEnvironment; }); it('should be compatible with log aggregation in productive environment', function () { Logger.setTransformations([new AddLogLevel(), new Colorize()]); const spy = sandbox.on(console, 'log', () => { // noop }); Logger.log('Foo\nbar'); expect(spy).to.have.been.called.once; expect(spy.__spy.calls[0][0]).to.equal('\u001B[37m[LOG] Foo\u001B[39m\n\u001B[37mbar\u001B[39m'); const nodeEnvironment = process.env.NODE_ENV; process.env.NODE_ENV = 'production'; process.env.ALLOW_NO_TRANSPORT = 'true'; Logger.setTransformations([new AddLogLevel(), new Colorize()]); Logger.log('Foo\nbar'); expect(spy).to.have.been.called.twice; expect(spy.__spy.calls[1][0]).to.equal('[LOG] Foo bar'); process.env.NODE_ENV = nodeEnvironment; delete process.env.ALLOW_NO_TRANSPORT; }); it('should log', function () { const spy = sandbox.on(console, 'log', () => { // noop }); Logger.log('Foobar'); expect(spy).to.have.been.called(); expect(spy.__spy.calls[0][0]).to.contain('[LOG]'); expect(spy.__spy.calls[0][0]).to.contain('Foobar'); }); it('should log without output', function () { const spy = sandbox.on(console, 'log', () => { // noop }); process.env.STAPPS_LOG_LEVEL = '0'; Logger.log('Foobar'); delete process.env.STAPPS_LOG_LEVEL; expect(spy).to.not.have.been.called(); }); it('should ok', function () { const spy = sandbox.on(console, 'log', () => { // noop }); Logger.ok('Foobar'); expect(spy).to.have.been.called(); expect(spy.__spy.calls[0][0]).to.contain('[OK]'); expect(spy.__spy.calls[0][0]).to.contain('Foobar'); }); it('should ok without output', function () { const spy = sandbox.on(console, 'log', () => { // noop }); process.env.STAPPS_LOG_LEVEL = '0'; Logger.ok('Foobar'); delete process.env.STAPPS_LOG_LEVEL; expect(spy).not.to.have.been.called(); }); it('should set transport', function () { expect(() => { Logger.setTransport(new DummyTransport()); Logger.setTransport(); }).not.to.throw(); }); it('should stringify', function () { const spy = sandbox.on(console, 'log', () => { // noop }); Logger.log('foo', 'bar'); expect(spy).to.have.been.called(); expect(spy.__spy.calls[0][0]).to.contain('foo'); expect(spy.__spy.calls[0][0]).to.contain('bar'); }); it('should stringify object', function () { const spy = sandbox.on(console, 'log', () => { // noop }); Logger.log({ foo: 'bar', }); expect(spy).to.have.been.called(); expect(spy.__spy.calls[0][0]).to.contain('foo'); expect(spy.__spy.calls[0][0]).to.contain('bar'); }); it('should warn', function () { const spy = sandbox.on(console, 'warn', () => { // noop }); Logger.warn('Foobar'); expect(spy).to.have.been.called(); expect(spy.__spy.calls[0][0]).to.contain('[WARN]'); expect(spy.__spy.calls[0][0]).to.contain('Foobar'); }); it('should warn without output', function () { const spy = sandbox.on(console, 'warn', () => { // noop }); process.env.STAPPS_LOG_LEVEL = '0'; Logger.warn('Foobar'); delete process.env.STAPPS_LOG_LEVEL; expect(spy).not.to.have.been.called(); }); it('should log level exclusiveness', function () { const warnSpy = sandbox.on(console, 'warn', () => { // noop WARN }); const infoSpy = sandbox.on(console, 'info', () => { // noop INFO }); const okSpy = sandbox.on(console, 'log', () => { // noop OK }); // only warn and info = warn + info = 4 + 1 = 5 process.env.STAPPS_LOG_LEVEL = '5'; Logger.warn('Foo'); Logger.info('Bar'); Logger.ok('Baz'); expect(warnSpy).to.have.been.called(); expect(warnSpy.__spy.calls[0][0]).to.contain('[WARN]'); expect(warnSpy.__spy.calls[0][0]).to.contain('Foo'); expect(infoSpy).to.have.been.called(); expect(infoSpy.__spy.calls[0][0]).to.contain('[INFO]'); expect(infoSpy.__spy.calls[0][0]).to.contain('Bar'); expect(okSpy).to.not.have.been.called(); delete process.env.STAPPS_LOG_LEVEL; }); it('should getExitLevel', function () { const savedProcess = process; // @ts-expect-error ignore process = undefined; (global as any).window = { STAPPS_EXIT_LEVEL: 0, }; const stub = sandbox.on(console, 'info', () => { // noop }); Logger.info('Foobar'); process = savedProcess; delete (global as any).window; expect(stub).not.to.have.been.called(); }); it('should getLogLevel', function () { const savedProcess = process; // @ts-expect-error ignore process = undefined; (global as any).window = { STAPPS_LOG_LEVEL: 0, }; const stub = sandbox.on(console, 'info', () => { // noop }); Logger.info('Foobar'); process = savedProcess; delete (global as any).window; expect(stub).not.to.have.been.called(); }); it('should output without transformations', function () { Logger.setTransformations([]); const stub = sandbox.on(console, 'log', () => { // noop }); const applyTransformationsSpy = sandbox.on(new Logger(), 'applyTransformations'); Logger.log('Foobar'); expect(stub).to.have.been.called.with('Foobar'); expect(applyTransformationsSpy).not.to.have.been.called; }); });