Home > Back-end >  extracting mocked function for easier mocking of function behavior with jest
extracting mocked function for easier mocking of function behavior with jest

Time:10-15

I'm using jest with nodejs and sequelize for my models. For my testing, I wanted to mock the returned value of findAll to cover test scenarios. Sorry if this is a very newbie question but I'm at dead-end on this one.

init-models.js

module.exports = function initModels(sequelize) {
  //model relationship code here
  ...
  ...
  //end of model relationship code

  return {
    records,
    anotherModel,
    alsoAnotherModel
  };
};

repository.js

const sequelize = require('../sequelize');
const initModels = require('../model/init-models');

let {
  records,
  anotherModel,
  alsoAnotherModel
} = initModels(sequelize);

const fetchRecords = async () => {
  console.info('Fetching records...');
  return await records.findAll({sequelize parameters here});
}

repository.test.js This will work but needs the flexibility to mock findAll() return value/or throw Error

const repository = require('../../../src/db/repository/repository');
const initModels = require('../../../src/db/model/init-models');

jest.mock('../../../src/db/model/init-models', () => {
    return function() { 
        return {
            records: {
                findAll: jest.fn().mockImplementation(() => [1,2,3])
            }
            //the rest of the code for other models
        }
    }
});

describe('fetchRecords', () => {
    beforeEach(()=> {
    });

    test('should return correct number of records', async () => {
        const result = await repository.fetchRecords();
        expect(result.size).toStrictEqual(3);        //test passed
    });
})

To allow mocking of results of findAll, I've tried extracting it so I can change the result per test scenario, but it was not working. What did I missed?

const mockRecordsFindAll = jest.fn();

jest.mock('../../../src/db/model/init-models', () => {
    return function() { 
        return {
            records: {
                findAll: () => mockRecordsFindAll
            }
            //the rest of the code for other models
        }
    }
});

describe('fetchRecords', () => {
    beforeEach(()=> {
        mockRecordsFindAll.mockReset()
    });

    test('should return correct number of records', async () => {
        mockRecordsFindAll.mockImplementation(() => [1,2,3]); //should expect length 3
        const result = await repository.fetchRecords();
        expect(result.size).toStrictEqual(3);            //fails, findAll was not mocked
    });
})

CodePudding user response:

The issue is mockRecordsFindAll is being returned instead of executed. As @Gid machined just returning mockRecordsFindAll causes initialization issues (due to hoisting).

The solution for this case is using the decorator pattern to allow mockRecordsFindAll to be initialized afterward.

const mockRecordsFindAll = jest.fn();

jest.mock('../../../src/db/model/init-models', () => {
    return function() { 
        return {
            records: {
                findAll: function () { 
                   return mockRecordsFindAll.call(this, arguments); 
                }
            }
        }
    }
});

describe('fetchRecords', () => {
    ...
})
  • Related