Home > Back-end >  Mock sequelizeORM chained function in jest js
Mock sequelizeORM chained function in jest js

Time:12-06

I'm not able to mock chained function of sequelize. In following example I can mock Query 1, but not Query 2

something.service.ts

// Query 1
await this.table2.findAll<table2>({
  attributes: [
    'field1'
  ],
  where: {
    id: someId
   },
});


// Query 2
// returns []
let bill1: any = await this.table2.sequelize.query(`
     SELECT
       aa.field1,
       bg.field2
     FROM
       table1 aa,
       table2 bg
     WHERE
       bg.id = '${billId}'
     AND 
       aa.id = bg.aggr_id;
`);

something.service.spec.ts

beforeEach(async () => {
    const module = await Test.createTestingModule({
      providers: [
        {
          provide: getModelToken(table2),
          useValue: {
            // mock successful for query 1
            findAll: jest.fn(() => [{}]),
            
            // mock fails for query 2
            sequelize: jest.fn().mockReturnValue([]),
            query: jest.fn().mockReturnValue([]),
            'sequelize.query': jest.fn().mockReturnValue([]),
          },
        }
      ],
    }).compile();

With this code I'm receiving (for Query 2)

TypeError: this.table2.sequelize.query is not a function

I tried with following code, no luck

sequelize: jest.fn().mockReturnValue([]),
query: jest.fn().mockReturnValue([]),
'sequelize.query': jest.fn().mockReturnValue([]),
sequelize: jest.fn().mockReturnValue({
                query: jest.fn(() => [])
            })

CodePudding user response:

You can utilize jest.fn().mockReturnThis() to mock the chained function in jest. I have tested this on mocking the TypeORM repository, something like this:

repository.mock.ts

export const mockedRepository = {
  find: jest.fn(),
  createQueryBuilder: jest.fn(() => ({ // createQueryBuilder contains several chaining methods
    innerJoinAndSelect: jest.fn().mockReturnThis(),
    getMany: jest.fn(),
  })),
};

Somewhere in your service for example:

test.service.ts

//
async findAll(){
  return await this.repository
      .createQueryBuilder('tableName')
      .innerJoinAndSelect('tableName.relation','relation' )
      .getMany();
}
//

And finally the unit test spec:

test.service.spec.ts

const module = await Test.createTestingModule({
      providers: [
        TestService,
        {
          provide: getRepositoryToken(Test),
          useValue: mockedRepository,
        }
      ],
    }).compile();

    testService =
      module.get<TestService>(TestService);
    testRepository = module.get<Repository<Test>>(
      getRepositoryToken(Test),
    );
});

describe('when findAll is called', () => {
  beforeEach(() => {
    mockedRepository.createQueryBuilder.getMany.mockResolvedValue([]);
  });

  it('should call innerJoinAndSelect method once', async () => {
      await testService.findAll();

      expect(mockedRepository.createQueryBuilder.innerJoinAndSelect).toHaveBeenCalledTimes(1);
  });

  it('should return an empty array', async () => {
      expect(await testService.findAll()).toBe([]);
  });
});

This is not a real working example but I hope you get the idea.

CodePudding user response:

Issue was with the problem statement itself, this.table.sequelize is an object NOT a function to be chained, following solution worked to mock it.

sequelize: { query: jest.fn(() => []) }

To mock chained functions Farista's solution works.

  • Related