Manual Reference Source Test

test/middleware/Database.spec.js

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

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

/** @test {Database} */
describe('Database', () => {
  /**
   * The stub for `process.env`.
   * @type {Object}
   */
  let stub: Object

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

  /**
   * The database manager to connect to mongodb.
   * @type {Database}
   */
  let database: Database

  /**
   * Hook for setting up the Database tests.
   * @type {Function}
   */
  before(() => {
    const {
      MONGO_PORT_27017_TCP_ADDR,
      NODE_ENV,
      PATH
    } = process.env
    stub = sinon.stub(process, 'env')
    stub.value({
      MONGO_PORT_27017_TCP_ADDR,
      NODE_ENV,
      PATH
    })

    logDir = join(...[
      __dirname,
      '..',
      '..',
      'tmp'
    ])
    mkdirp.sync(logDir)

    database = new Database(PopApi, {
      database: name,
      username: '',
      password: ''
    })
  })

  /** @test {Database#constructor} */
  it('should test the use the environment variables to connect', () => {
    const stub = process.env.MONGO_PORT_27017_TCP_ADDR
    process.env.MONGO_PORT_27017_TCP_ADDR = 'localhost'
    new Database(PopApi, { // eslint-disable-line no-new
      database: name
    })

    process.env.MONGO_PORT_27017_TCP_ADDR = null
    new Database(PopApi, { // eslint-disable-line no-new
      database: name
    })
    process.env.MONGO_PORT_27017_TCP_ADDR = stub

    try {
      new Database(PopApi, {}) // eslint-disable-line no-new
      expect(true).to.be.false
    } catch (err) {
      expect(err).to.be.an('Error')
      expect(err.message).to.equal(
        '\'database\' is a required option for the Database middleware!'
      )
    }
  })

  /** @test {Database#constructor} */
  it('should check the attributes of the Database', () => {
    const temp = process.env.MONGO_PORT_27017_TCP_ADDR
    process.env.MONGO_PORT_27017_TCP_ADDR = null
    expect(database.hosts).to.exist
    expect(database.hosts).to.be.an('array')
    process.env.MONGO_PORT_27017_TCP_ADDR = temp

    expect(database.database).to.exist
    expect(database.database).to.be.a('string')
    expect(database.dbPort).to.exist
    expect(database.dbPort).to.be.a('number')
    expect(database.username).to.exist
    expect(database.username).to.be.a('string')
    expect(database.password).to.exist
    expect(database.password).to.be.a('string')
  })

  /** @test {Database#constructor} */
  it('should fail to create a new Database object', () => {
    process.env.NODE_ENV = null
    expect(mongoose.connection.readyState).to.be.a('number')
    expect(mongoose.connection.readyState).to.equal(0)

    try {
      new Database(PopApi, { // eslint-disable-line no-new
        database: name
      })
      process.env.NODE_ENV = 'test'
    } catch (err) {
      process.env.NODE_ENV = 'test'
      expect(err).to.be.an('Error')
    }
  })

  /**
   * Test the changing connection state.
   * @param {!Function} method - Method to change to connection state.
   * @param {!number} before - The connection state it is before executing the
   * method to change it.
   * @param {!number} after - The connection state it is after executing the
   * method to change it.
   * @param {Function} done - The method executed when the test is done.
   * @returns {undefined}
   */
  function testConnection(
    method: Function,
    before: number,
    after: number,
    done: Function
  ): void {
    expect(mongoose.connection.readyState).to.be.a('number')
    expect(mongoose.connection.readyState).to.equal(before)

    method().then(() => {
      expect(mongoose.connection.readyState).to.be.a('number')
      expect(mongoose.connection.readyState).to.equal(after)

      done()
    }).catch(done)
  }

  /** @test {Database#connect} */
  it('should connect to MongoDB', done => {
    testConnection(database.connect.bind(database), 0, 1, done)
  })

  /** @test {Database#disconnect} */
  it('should disconnect from MongoDB', done => {
    testConnection(database.disconnect.bind(database), 1, 0, done)
  })

  /** @test {Database#connect} */
  it('should fail to authenticate with MongoDB', done => {
    expect(mongoose.connection.readyState).to.be.a('number')
    expect(mongoose.connection.readyState).to.equal(0)

    const database = new Database(PopApi, {
      database: name,
      username: 'fault',
      password: 'faulty'
    })

    database.connect()
      .then(done)
      .catch(err => {
        expect(err.name).to.equal('MongoError')
        mongoose.connection.onClose(true)

        done()
      })
  })

  /** @test {Database#exportFile} */
  it('should export a file', done => {
    const collection = 'example'
    const outputFile = join(...[
      logDir,
      `${collection}s.json`
    ])

    database.exportFile(collection, outputFile).then(res => {
      expect(res).to.be.undefined
      done()
    }).catch(done)
  })

  /** @test {Database#importFile} */
  it('should import a file', done => {
    const file = './examples/exampleModel1.json'

    database.importFile('example', file).then(res => {
      expect(res).to.be.undefined
      done()
    }).catch(done)
  })

  /** @test {Database#importFile} */
  it('should not find the file to import', done => {
    database.importFile('example', '/data/example.json')
      .then(done)
      .catch(err => {
        expect(err).to.be.an('Error')
        done()
      })
  })

  /**
   * Hook for tearing down the Database tests.
   * @type {Function}
   */
  after(done => {
    stub.restore()
    database.disconnect()
      .then(() => del([logDir]))
      .then(() => done())
      .catch(done)
  })
})