MadsRC
MadsRC

Reputation: 197

Stubbing pg-promise using sinon and mocha

Suppose I have a the following module, as database.js

const initOptions = {}
const pgp = require('pg-promise')(initOptions)
const config = require('../../config')

const db = pgp({
  host: config.database.host,
  port: config.database.port,
  database: config.database.database,
  user: config.database.user,
  password: config.database.password
})

module.exports = db

And the following module as create.js

const db = require('./database')

function create (name) {
  return new Promise((resolve, reject) => {
      db.func('create', name)
      .then(data => {
        return resolve(data)
      })
      .catch(err => {
        return reject(err)
      })
  })
}

module.exports = create

I'm trying to run a unit test on create.js that will test that db.func is called with 'create' as first argument and 'name' as the second, but without actually needing to set up a database connection (So tests can run offline).

From what I can gather, this is what libraries like sinon.JS can be used for, so I tried creating a test and stubbed the db object.

const chai = require('chai')
const chaiAsPromised = require('chai-as-promised')

chai.use(chaiAsPromised)

const sinon = require('sinon')

const expect = chai.expect

const create = require('./create.js')

describe('Test Module', () => {
  it('should test stuff', () => {
    const db = require('./database')
    const dbStub = sinon.stub(db, 'func').callsFake(Promise.resolve(null))
    expect(create('test').then).to.be.a('Function')
  })
})

However, it fails with

TypeError: Cannot redefine property: func

Most likely due to my limited exposure to sinon...

How do I go about stubbing (or maybe I need to mock?) the db function so that I can test it an ensure db.func was called?

Upvotes: 4

Views: 1387

Answers (1)

MinusFour
MinusFour

Reputation: 14423

You can make the properties configurable by disabling locks with the no noLocking option in Initialization Options. This allows sinon to replace the properties:

const initOptions = { noLocking : true };

On a related note:

Your create function is creating an unnecessary promise wrapper, which is a promise anti-pattern. You should just return the result from db.func, which is a promise already:

function create(name) {
      return db.func('create', name);
}

Also callsFake takes a function and you are giving it a promise. Use returns instead:

const dbStub = sinon.stub(db, 'func').returns(Promise.resolve(null))

I'm having trouble setting the noLocking option. The docs state it can be set after initialization, however if I set it with db.$config.options.noLocking = true, the same error occurs. However, if I set it in the database.js init options it works fine.

From the author of pg-promise...

It is because at that point the noLocking can only affect tasks and transactions. And since the db level of the protocol is initiated only once, setting noLocking after the library's initialization doesn't effect it.

I have just updated the documentation to clarify it: This option is dynamic (can be set before or after initialization). However, changing it after the library's initialization will not affect Database objects that have already been created.

Upvotes: 3

Related Questions