RKBuiltMyRothod
RKBuiltMyRothod

Reputation: 101

Change jest mock on class for single test

I have an issue where I want to change what a class method returns for a single test while testing a different module. I have the following:

testingModule.test.js

const { testingModuleMethod } = require('../testingModule')

jest.mock('../helperClass', () =>
    jest.fn().mockImplementation(() => ({
        helperClassMethod: jest.fn()
    }))
);

describe('testingModule.js', () => {

    describe('testingModuleMethod', () => {
        describe('when errors', () => {
            const consoleSpy = jest.spyOn(console, 'error');
    
            // SOMETHING NEEDS TO GO HERE TO CHANGE THE jest.mock ON LINE 3

            await expect(testingModuleMethod(data)).rejects.toThrow('Error');
            expect(consoleSpy).toHaveBeenCalled();

            consoleSpy.mockRestore();
        });
    });
});

testingModule.js

const HelperClass = require('./helperClass');

const testingModuleMethod = async (data, callback) => {
    try {
        const objectToEvaluate = data.object;

        const helperClassInstance = new HelperClass();

        await helperClassInstance.helperClassMethod(objectToEvaluate);
        log('info', "Success!");
        callback(null, {});
    } catch(error) {
        log('error', 'Something went wrong')
    }
};

No matter what I put in there I either get an error with the code (undefined) or it just ignores it and resolves due to the mock at the start. I have tried adding a spy as well as importing the class and using the prototype override.

I'm using node and "jest": "^27.0.6"

Upvotes: 4

Views: 4877

Answers (1)

RKBuiltMyRothod
RKBuiltMyRothod

Reputation: 101

I have managed to answer this by doing the following:

Firstly I discovered that to mock a class like that I have to add a jest function into the mock like so:

    describe('testingModuleMethod', () => {
        describe('when errors', () => {
            const consoleSpy = jest.spyOn(console, 'error');
    
            HelperClass.mockImplementation(() => ({
                    helperClassMethod: jest.fn(() => { throw new Error('Error') })
                }));

            await expect(testingModuleMethod(data)).rejects.toThrow('Error');
            expect(consoleSpy).toHaveBeenCalled();

            consoleSpy.mockRestore();
        });
    });

This also had a knock on effect to the rest of the tests though so I added a beforeEach at the start that looks like:

        HelperClass.mockImplementation(
            jest.fn().mockImplementation(() => ({
                helperClassMethod: jest.fn()
            }))
        );

Finally I needed to require the class. The overall test looks like this now and works:

const { testingModuleMethod } = require('../testingModule');
const HelperClass = require('./helperClass');

jest.mock('../helperClass', () =>
    jest.fn().mockImplementation(() => ({
        helperClassMethod: jest.fn()
    }))
);

describe('testingModule.js', () => {

    beforeEach(() => {
        HelperClass.mockImplementation(
            jest.fn().mockImplementation(() => ({
                helperClassMethod: jest.fn()
            }))
        );
    });

    describe('testingModuleMethod', () => {
        describe('when errors', () => {
            const consoleSpy = jest.spyOn(console, 'error');
    
            HelperClass.mockImplementation(() => ({
                    helperClassMethod: jest.fn(() => { throw new Error('Error') })
                }));

            await expect(testingModuleMethod(data)).rejects.toThrow('Error');
            expect(consoleSpy).toHaveBeenCalled();

            consoleSpy.mockRestore();
        });
    });
});

Upvotes: 2

Related Questions