Home > Software design >  Mock return value of method on mocked ES6 class
Mock return value of method on mocked ES6 class

Time:11-09

I'm struggling with mocking a method when mocking an ES6 class, using MockedClass of the jest library.

Example:

export default class CalculatorService {
  constructor() {
    // setup stuff
  }

  public add(num1: number, num2: number): number {
    return num1   num2;
  }
}

The following works as expected:

import CalculatorService from 'services/calculatorService';
jest.mock('services/calculatorService');
const MockedCalculatorService = CalculatorService as jest.MockedClass<typeof CalculatorService>;

describe('Tests', () => {

    test('Test flow with Calculator service', () => {
        // Arrange

        // Act
        implementation(1,2); // Where CalculatorService is used

        // Assert
        const mockServiceInstance = MockedService.mock.instances[0];
        expect(mockServiceInstance.add).toHaveBeenCalledWith(1,2);
    });
}

But say I wanted to mock add to always return 5, no matter the input.

With jest.Mocked it's done like: MockedService.add.mockReturnValue(5) if I understand it correctly here. But how do I solve it when I've mocked a class?

EDIT: Ismail gave the option to mock the whole implementation in the jest.mock() invocation. However, in this case, ideally, I'd like to mock the implementation/return value for each test.

CodePudding user response:

Here is a rough idea how I have mocked classes

import { mocked } from 'ts-jest/utils';
import { CalculatorService } from 'services/calculatorService';

jest.mock('services/calculatorService', () => {
  return {
    CalculatorService: jest.fn().mockImplementation(() => {
      return {
        add: () => {},
      };
    })
  };
});

describe('Tests', () => {
  const MockedCalculatorService = mocked(CalculatorService, true);

  beforeEach(() => {
   MockedCalculatorService.mockClear();
  });

  it('Test flow with Calculator service', () => {
    const impementingClass = new ImplementingClass();
    expect(MockedCalculatorService).toHaveBeenCalledTimes(1);

    impementingClass.implimentation(1,2);
    expect(MockedCalculatorService.add).toHaveBeenCalledWith(1,2)
  });

}

Note - using npm i ts-jest

CodePudding user response:

The following worked, by using jest.spyOn. Not well documented though, so I leave it here for future reference.

describe('Tests', () => {

    test('Test flow with Calculator service', () => {
        // Arrange
        jest.spyOn(MockedCalculatorService.prototype,'add').mockReturnValue(5);

        // Act
        implementation(1,2); // Where CalculatorService is used

        // Assert
        const mockServiceInstance = MockedService.mock.instances[0];
        expect(mockServiceInstance.add).toHaveBeenCalledWith(1,2);
        expect(mockServiceInstance.add).toHaveReturnedWith(5);
}

In my real case, it was an async function that I mocked, and then the following was necessary:

jest.spyOn(MockedCalculatorService.prototype,'add').mockResolvedValue(5);
expect(mockServiceInstance.getRelationsByNobbNrsAsync).toHaveReturnedWith(
    new Promise(() => 5)
);
  • Related