Manual Reference Source Test

test/middleware/Logger.spec.js

// Import the necessary modules.
// @flow
/* eslint-disable no-unused-expressions */
import del from 'del'
import mkdirp from 'mkdirp'
import sinon from 'sinon'
import winston from 'winston'
import { expect } from 'chai'
import { join } from 'path'

import {
  Logger,
  PopApi
} from '../../src'
import { name } from '../../package'

/** @test {Logger} */
describe('Logger', () => {
  /**
   * The logger instance to test.
   * @type {Logger}
   */
  let logger: Logger

  /**
   * The directory where the logs are saved.
   * @type {string}
   */
  let logDir: string

  /**
   * Hook for setting up the Logger tests.
   * @type {Function}
   */
  before(() => {
    logDir = join(...[
      __dirname,
      '..',
      '..',
      'tmp'
    ])
    mkdirp.sync(logDir)

    logger = new Logger(PopApi, {
      name,
      logDir,
      pretty: false,
      quiet: true
    })
  })

  /** @test {Logger#constructor} */
  it('should create an ExpressWinston instance', () => {
    const processStub = sinon.stub(process.env, 'NODE_ENV')
    processStub.value('development')
    const padStartStub = sinon.stub(String.prototype, 'padStart')
    padStartStub.value(undefined)

    const logger = new Logger(PopApi, {
      name,
      logDir,
      pretty: true,
      quiet: false
    })
    expect(logger).to.be.an('object')

    try {
      new Logger(PopApi, {}) // eslint-disable-line no-new
      expect(true).to.be.false
    } catch (err) {
      expect(err).to.be.an('Error')
      expect(err.message).to.equal(
        '\'name\' and \'logDir\' are required options for the Logger middleware!'
      )
    }

    processStub.restore()
    padStartStub.restore()
  })

  /** @test {Logger#constructor} */
  it('should check the attributes of the Logger', () => {
    expect(logger.levels).to.exist
    expect(logger.levels).to.be.an('object')
    expect(logger.name).to.exist
    expect(logger.name).to.be.a('string')
    expect(logger.logDir).to.exist
    expect(logger.logDir).to.be.a('string')
  })

  /** @test {Logger#getLevelColor} */
  it('should test if the correct logger colors are returned', () => {
    const error = logger.getLevelColor('error')
    expect(error).to.equal('\x1b[31m')
    const warn = logger.getLevelColor('warn')
    expect(warn).to.equal('\x1b[33m')
    const info = logger.getLevelColor('info')
    expect(info).to.equal('\x1b[36m')
    const debug = logger.getLevelColor('debug')
    expect(debug).to.equal('\x1b[34m')
    const nothing = logger.getLevelColor(undefined)
    expect(nothing).to.equal('\x1b[36m')
  })

  /** @test {Logger#prettyPrintConsole} */
  it('should enrich the info object to pretty print the console', () => {
    let info = {
      level: 'info',
      message: 'This is a test message'
    }
    info = logger.prettyPrintConsole(info)

    expect(info.level).to.be.a('string')
    expect(info.message).to.be.a('string')
    expect(info.splat).to.be.an('array')
  })

  /** @test {Logger#_getMessage} */
  it('should get the message string from the info object', () => {
    expect(logger._getMessage({
      level: 'info',
      message: 'This is a test message'
    })).to.be.a('string')
  })

  /** @test {Logger#consoleFormatter} */
  it('should make the console formatter', () => {
    expect(logger.consoleFormatter()).to.be.an('object')
  })

  /** @test {Logger#fileFormatter} */
  it('should make the file formatter', () => {
    expect(logger.fileFormatter()).to.be.an('object')
  })

  /** @test {Logger#getConsoleTransport} */
  it('should get a configured winston console transport', () => {
    const transport = logger.getConsoleTransport()
    expect(transport).to.be.an('object')
  })

  /** @test {Logger#getFileTransport} */
  it('should get a configured winston file transport', () => {
    const transport = logger.getFileTransport(`${name}-app`)
    expect(transport).to.be.an('object')
    transport.close()
  })

  /** @test {Logger#createLoggerInstance} */
  it('should create a configured winston instance', () => {
    const logy = logger.createLoggerInstance('app')
    expect(logy).to.be.an('object')
  })

  /** @test {Logger#createLoggerInstance} */
  it('should create a configured winston instance', () => {
    const stub = process.env.TEMP_DIR
    process.env.TEMP_DIR = null

    const logy = logger.createLoggerInstance('app')
    expect(logy).to.be.an('object')

    process.env.TEMP_DIR = stub
  })

  /** @test {Logger#getHttpLoggerMessage} */
  it('should get the message to print for express-winston', () => {
    const message = logger.getHttpLoggerMessage({
      method: 'GET',
      url: 'http://mock.us'
    }, {
      statusCode: 418,
      responseTime: 420
    })
    expect(message).to.be.a('string')
  })

  /** @test {Logger#createHttpLogger} */
  it('should create a configured Http logger instance', () => {
    const logy = logger.createHttpLogger()
    expect(logy).to.be.a('function')
  })

  /** @test {Logger#createHttpLogger} */
  it('should create a configured Http logger instance with developer output', () => {
    const stub = sinon.stub(process.env, 'NODE_ENV')
    stub.value('development')

    const logy = logger.createHttpLogger()
    expect(logy).to.be.a('function')

    stub.restore()
  })

  /** @test {Logger#createLogger} */
  it('should create the global logger object', () => {
    let val = logger.createLogger(true, true)
    expect(val).to.be.an('object')

    val = logger.createLogger(false, false)
    expect(val).to.be.an('object')

    val = logger.createLogger(false, true)
    expect(val).to.be.an('object')
  })

  /** @test {Logger#getLogger} */
  it('should not create an instance of ExpressWinston or Winston', () => {
    expect(logger.getLogger()).to.be.undefined
    expect(logger.getLogger('FAULTY')).to.be.undefined
  })

  /**
   * Hook for tearing down the Logger tests.
   * @type {Function}
   */
  after(done => {
    winston.loggers.close()
    Logger.fileTransport = null

    del([logDir])
      .then(() => done())
      .catch(done)
  })
})