skip to Main Content

Scenario

I have the following type of function that I wish to test. This function has

File to be tested

export const doSomething = () => {

    sequelize.transaction(async t => {
        customModel.upsert(dataObject, { transaction : t })
        
        otherCustomModel.upsert(otherDataObject, { transaction : t })
    })
    
}

Here customModel and otherCustomModel are valid models written using sequelize.define in their respective files.

Here sequelize is the following thing

import Sequelize from 'sequelize';

const connectionParams = {
// assume valid config is present
}

const sequelize = new Sequelize(connectionParams);

(async () => {
    try {
        await sequelize.authenticate();
        console.log('Sequelize authenticated successfully');
    } catch (error) {
        console.log(`Unable to connect to the database: ${error}`);
    }
})();

export default sequelize;

Requirements

I wish to write a testcase with the following checks:

  1. Test that the following functions are called once.

    • transaction
    • customModel.upsert
    • otherCustomModel.upsert
  2. The entire function executes

How can I go ahead and mock a sequelize transaction using jest for such functions?


My Test

test("text", () => {
    
    // mocks
    sequelize.transaction = jest.fn()
    customModel.upsert = jest.fn()
    otherCustomModel.upsert = jest.fn()
 

    doSomething()

    // assertions
    expect(sequelize.transaction).toBeCalled();
    expect(customModel.upsert).toBeCalled();
    expect(otherCustomModel.upsert).toBeCalled();

})

Error Faced

expect(jest.fn()).toBeCalled()

    Expected number of calls: >= 1
    Received number of calls:    0

62 |        expect(sequelize.transaction).toBeCalled();

Versions

S No. Dependency Version
1 sequelize ^6.19.1
2 jest ^27.5.1

P.S. : Any other suggestions to enhance my test case are welcomed!

2

Answers


  1. You should be able to do it e.g. like this:

    const sequelize = require('sequelize');
    const customModel = require('<your module>');
    const otherCustomModel = require('<your module>');
    
    jest.mock('sequelize', () => ({
        transaction: jest.fn(() => jest.fn()),
    }));
    jest.spyOn(customModel, 'upsert');
    jest.spyOn(otherCustomModel, 'upsert');
    

    And in you test case:

    sequelize.transaction.mockImplementation(() => jest.fn());
    otherCustomModel.upsert.mockImplementation(() => jest.fn());
    customModel.upsert.mockImplementation(() => jest.fn());
    

    and after that you can do your assertions e.g.:

    expect(sequelize.transaction).toBeCalled();
    
    Login or Signup to reply.
  2. I would write it something like this

    describe('doSomething', () => {
      beforeAll(() => {
        doSomething()
      })
    
      it('should call transaction with a callback', () => {
        expect(sequalize.transaction).toHaveBeenCalledWith(
          expect.any(Function)
        )
      })
    
      describe('the transaction', () => {
        let mockTransaction = { prop: 'dummy transaction object' }
        
        beforeAll(() => {
          const transactionCallback = sequalize.transaction.mock.calls[0][0]
          transactionCallback(mockTransaction)
          // presuming you're NOT using jest.spyOn on sequalize.transaction
          // you have to call the callback passed to it
        })
    
        it('should have called customModel.upsert', () => {
          const dataObject = expect.objectContaining({
            // ...expected properties
          })
          expect(customModel.upsert).toHaveBeenCalledWith(
            dataObject, { transaction : mockTransaction }
          );
        })
    
        it.todo('should have called otherCustomModel.upsert ... same as above')
      })
    })
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search