Mock dependency in Jest with TypeScript
You can use type casting and your test.ts
should look like this:
import * as dep from '../dependency';jest.mock('../dependency');const mockedDependency = <jest.Mock<typeof dep.default>>dep.default;it('should do what I need', () => { //this throws ts error // Property mockReturnValueOnce does not exist on type (name: string).... mockedDependency.mockReturnValueOnce('return');});
TS transpiler is not aware that jest.mock('../dependency');
changes type of dep
thus you have to use type casting. As imported dep
is not a type definition you have to get its type with typeof dep.default
.
Here are some other useful patterns I've found during my work with Jest and TS
When imported element is a class then you don't have to use typeof for example:
import { SomeClass } from './SomeClass';jest.mock('./SomeClass');const mockedClass = <jest.Mock<SomeClass>>SomeClass;
This solution is also useful when you have to mock some node native modules:
import { existsSync } from 'fs';jest.mock('fs');const mockedExistsSync = <jest.Mock<typeof existsSync>>existsSync;
In case you don't want to use jest automatic mock and prefer create manual one
import TestedClass from './TestedClass';import TestedClassDependency from './TestedClassDependency';const testedClassDependencyMock = jest.fn<TestedClassDependency>(() => ({ // implementation}));it('Should throw an error when calling playSomethingCool', () => { const testedClass = new TestedClass(testedClassDependencyMock());});
testedClassDependencyMock()
creates mocked object instanceTestedClassDependency
can be either class or type or interface
Use the mocked
helper from ts-jest
like explained here
// foo.spec.tsimport { mocked } from 'ts-jest/utils'import { foo } from './foo'jest.mock('./foo')// here the whole foo var is mocked deeplyconst mockedFoo = mocked(foo, true)test('deep', () => { // there will be no TS error here, and you'll have completion in modern IDEs mockedFoo.a.b.c.hello('me') // same here expect(mockedFoo.a.b.c.hello.mock.calls).toHaveLength(1)})test('direct', () => { foo.name() // here only foo.name is mocked (or its methods if it's an object) expect(mocked(foo.name).mock.calls).toHaveLength(1)})
There are two solutions tested for TypeScript version 3.x and 4.x, both are casting desired function
1) Use jest.MockedFunction
import * as dep from './dependency';jest.mock('./dependency');const mockMyFunction = dep.myFunction as jest.MockedFunction<typeof dep.myFunction>;
2) Use jest.Mock
import * as dep from './dependency';jest.mock('./dependency');const mockMyFunction = dep.default as jest.Mock;
There is no difference between these two solutions. The second one is shorter and I would therefore suggest using that one.
Both casting solutions allows to call any jest mock function on mockMyFunction
like mockReturnValue
or mockResolvedValue
https://jestjs.io/docs/en/mock-function-api.html
mockMyFunction.mockReturnValue('value');
mockMyFunction
can be used normally for expect
expect(mockMyFunction).toHaveBeenCalledTimes(1);