简体   繁体   中英

how to deal with jest mock function of a module and typescript type

I use ts-jest and jest to write my testing files with typescript.

I am confused how to typing the mock function of a module.

Here is my code:

./module.ts :

import {IObj} from '../interfaces';

const obj: IObj = {
  getMessage() {
    return `Her name is ${this.genName()}, age is ${this.getAge()}`;
  },

  genName() {
    return 'novaline';
  },

  getAge() {
    return 26;
  }
};

export default obj;

./module.test.ts :

import * as m from './module';

describe('mock function test suites', () => {

  it('t-1', () => {
    // I think the jest.Mock<string> type here is not correct.
    m.genName: jest.Mock<string> = jest.fn(() => 'emilie'); 
    expect(jest.isMockFunction(m.genName)).toBeTruthy();
    expect(m.genName()).toBe('emilie');
    expect(m.getMessage()).toEqual('Her name is emilie, age is 26');
    expect(m.genName).toHaveBeenCalled(); 

  });

});

how to type the mock function genName of module m ?

typescript give me an error here:

Error:(8, 7) TS2540:Cannot assign to 'genName' because it is a constant or a read-only property.

This is how I have solved the same problem and how I do all of my mocking and spying now.

import * as m from './module';

describe('your test', () => {
  let mockGenName;

  beforeEach(() => {
    mockGenName = jest.spyOn(m, 
      'genName').mockImplemetation(() => 'franc');
  })

  afterEach(() => {
    mockGenName.mockRestore();
  })


  test('your test description', () => {
    // do something that calls the genName function
    expect(mockGenName).toHaveBeenCalledTimes(1);
  })

})

With this setup, you can programmatically change the implementation of the mock for different tests, and then assert that the function was called and what it was called with, all while clearing your mock in between tests and after all tests.

Try this one - https://jestjs.io/docs/mock-function-api#typescript

In short there are only three strategies possible

  1. Mock the entire module being imported and get handler to the mocked function to manipulate it (jest.Mock(), jest.MockedFunction)
  2. Mock the module partially being imported and get handler to the mocked function to manipulate it (jest.Mock() with factory, jest.MockedFunction)
  3. Import the module as is and then spy on the function which needs to be mocked (jest.spy())

You want to mock the module and then alter the exported function within it. This should replace your import statement.

jest.mock('./module', () => ({
    genName: jest.fn().mockImplementation(() => 'emilie')
}))
import * as m from './module'

jest.mock('./module', () => ({
    genName: jest.fn().mockImplementation(() => 'emilie')
    // will return "enilie" for all tests
}))

it('returns franc', () => {
  m.genName.mockImplementationOnce(() => 'franc')
  // will return "franc" for this particular test
})

The reason why I got the error is:

The properties of a module object foo (import * as foo from 'foo') are like the properties of a frozen object.

For more info, see In ES6, imports are live read-only views on exported values

When I changed import * as m from './module' to import m from './module'; , The error is gone.

Package versions:

"typescript": "^3.6.4"
"ts-jest": "^24.1.0"
"jest": "^24.9.0",

jest.config.js :

module.exports = {
  preset: 'ts-jest/presets/js-with-ts',
  //...
}

tsconfig.json :

"compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    //...
}

I'm mocking it a follow:

jest.mock('./module')
const {genName} = require('./module')

and in my test:

 genName.mockImplementationOnce(() => 'franc')

works great for me and no typescript errors

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM