Search code examples
node.jschaisinon

Mocking Knex with Sinon


I'm trying to write unit tests for my NodeJs app with chai and sinon, but having problems with mocking my knex query builder.

I instansiate Knex as database in my app.js file and then attach it to my context in my app.

The function I'd like to write my unit test for gets called by a graphQL query and database is passed as a parameter from the context. The query is then constructed in that function. I've created an short example below. (I'm using js not typescript)

module.exports = async ({ database, data }) => {
  const queryObject = database.table('nice')
    .withSchema('very')
    .select(['some_col_1', 'some_col_2', 'some_col_3']);
  
  if (data) {
    queryObject.where('some_col_1', data.something);
  }
  
  const foo = await queryObject 
    .catch((err) => {
      console.log(err)
    });

  //Do something with foo...
};

I've spent the whole day trying to get it to work, but I'm not having any luck. The closest I've came was getting an error saying queryObject is not a function.

The other examples have repositories setup, but I build the query in the function that needs a specific query.

Any help would be appreciated.


Solution

  • I've managed to solve my own problem using mock-knex Link to mock-knex

    This is all in my unit test. Imported the following:

    const knex = require('knex');
    const mod = require('mock-knex');
    const tracker = require('mock-knex').getTracker();
    

    Then I made the mock DB connection

    const db = knex({
      client: 'mssql',
      connection: {
        host: '127.0.0.1',
        user: 'mockKnex',
        password: 'mockKnex',
        database: 'mockKnex',
      },
    });
    

    Then implemented the before,after, beforeEach, afterEach functions.

    describe('Unit tests', () => {
      before((done) => {
        mod.mock(db);
        done();
      });
    
      after((done) => {
        mod.unmock(db);
        done();
      });
    
      beforeEach((done) => {
        tracker.install();
        done();
      });
    
      afterEach((done) => {
        tracker.uninstall();
        done();
      });
    });
    

    Finally in my test case I did the following

    it('Test 1', (done) => {
        tracker.on('query', (query) => {
          expect(query.method)
            .to
            .equal('select');
          query.response([
            {
              something1: 'A',
              something2: 'B',
              something3: 'C',
              something4: 'D',
              something5: 'E',
            },
          ]);
        });
    
        someFunction(
          {
            database: db,
            data: { something: '1' },
          },
        ).catch((res) => {
          assert.equal(res.message, 'Something');
          done();
        });
      });
    

    After this I was able to manupilate the select query by changing the array object of something1..5 to get the response I was looking for.