node.jsexpresssinonknex.jssinon-chai

Can't mock/stub knex methods


On my code I have something like:

const getItem = async (itemId) => {
  const item = await knex('item').where('id', itemId).first();

  console.log(item);
};

And on my test file:

sinon.stub(knex, 'first').resolves({ id: 1 });

knex is imported as const knex = require('Knex')(config).

I feel like knex('table_name') creates a different instance and methods are not being mocked.

UPDATE stub only works like this:

const knexStub = sinon.stub(knex, 'from').callsFake(() => ({
      where: () => ({
        first: () => null
      }),
      insert: () => sinon.fake()
    }));

then in my function like:

const getItem = async (itemId) => {
  const item = await knex.from('item').where('id', itemId).first();

  console.log(item);
};

I like it better as knex('table_name') but it looks like it's not possible.


Solution

  • sinon doesn't support to stub standalone function, we need to use proxyquire package.

    getItem.js:

    const knex = require("knex")({
      client: "mysql",
      connection: {
        host: "127.0.0.1",
        port: 3306,
        user: "your_database_user",
        password: "your_database_password",
        database: "myapp_test",
      },
    });
    
    const getItem = async (itemId) => {
      return knex("item")
        .where("id", itemId)
        .first();
    };
    
    module.exports = getItem;
    

    getItem.test.js:

    const proxyquire = require("proxyquire");
    const sinon = require("sinon");
    
    describe("77622992", () => {
      it("should pass", async () => {
        const knexClient = sinon.stub().returns({
          where: sinon.stub().returnsThis(),
          first: sinon.stub().resolves({ id: 1 }),
        });
        const knexStub = sinon.stub().returns(knexClient);
        const getItem = proxyquire("./getItem", {
          knex: knexStub,
        });
        const r = await getItem(1);
        sinon.assert.match(r, { id: 1 });
      });
    });