Reputation: 102207
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.
Upvotes: 15
Views: 35075
Reputation: 71
Try this one - https://jestjs.io/docs/mock-function-api#typescript
In short there are only three strategies possible
Upvotes: 4
Reputation: 102207
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",
//...
}
Upvotes: 1
Reputation: 199
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.
Upvotes: 19
Reputation: 79
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
Upvotes: -1
Reputation: 543
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
})
Upvotes: 0
Reputation: 571
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')
}))
Upvotes: 3