Al probar un módulo que tiene una dependencia en un archivo diferente y asignar ese módulo para que sea un jest.mock , TypeScript da un error de que el método mockReturnThisOnce (o cualquier otro método jest.mock ) no existe en la dependencia, esto se debe a que se digita previamente.
¿Cuál es la forma correcta de hacer que TypeScript herede los tipos de jest.mock ?
Aquí hay un ejemplo rápido.
Dependencia
const myDep = (name: string) => name; export default myDep;prueba.ts
import * as dep from '../depenendency'; jest.mock('../dependency'); it('should do what I need', () => { //this throws ts error // Property mockReturnValueOnce does not exist on type (name: string).... dep.default.mockReturnValueOnce('return') }Siento que este es un caso de uso muy común y no estoy seguro de cómo escribirlo correctamente.
Puede usar la conversión de tipos y su test.ts debería verse así:
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 no sabe que jest.mock('../dependency'); cambia el tipo de dep , por lo que debe usar la conversión de tipos. Como el dep importado no es una definición de tipo, debe obtener su tipo con typeof dep.default .
Cuando el elemento importado es una clase, entonces no tiene que usar typeof, por ejemplo:
import { SomeClass } from './SomeClass'; jest.mock('./SomeClass'); const mockedClass = <jest.Mock<SomeClass>>SomeClass;Esta solución también es útil cuando tiene que simular algunos módulos nativos del nodo:
import { existsSync } from 'fs'; jest.mock('fs'); const mockedExistsSync = <jest.Mock<typeof existsSync>>existsSync;En caso de que no quieras usar el simulacro automático de broma y prefieras crear uno manual
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() crea una instancia de objeto TestedClassDependency puede ser una clase, un tipo o una interfaz.
Use el ayudante mocked como se explica aquí
// foo.spec.ts import { foo } from './foo' jest.mock('./foo') // here the whole foo var is mocked deeply const mockedFoo = jest.mocked(foo, true) test('deep', () => { // there will be no TS error here, and you'll have completion in modern IDEs mockedFoo.abchello('me') // same here expect(mockedFoo.abchello.mock.calls).toHaveLength(1) }) test('direct', () => { foo.name() // here only foo.name is mocked (or its methods if it's an object) expect(jest.mocked(foo.name).mock.calls).toHaveLength(1) })Hay dos soluciones probadas para TypeScript versión 3.x y 4.x , ambas están emitiendo la función deseada
1) Usa jest.MockedFunction
import * as dep from './dependency'; jest.mock('./dependency'); const mockMyFunction = dep.myFunction as jest.MockedFunction<typeof dep.myFunction>;2) Usa broma.Mock
import * as dep from './dependency'; jest.mock('./dependency'); const mockMyFunction = dep.default as jest.Mock;No hay diferencia entre estas dos soluciones. El segundo es más corto y, por lo tanto, sugeriría usar ese.
Ambas soluciones de conversión permiten llamar a cualquier función simulada de broma en mockMyFunction como mockReturnValue o mockResolvedValue https://jestjs.io/docs/en/mock-function-api.html
mockMyFunction.mockReturnValue('value'); mockMyFunction se puede usar normalmente para esperar
expect(mockMyFunction).toHaveBeenCalledTimes(1);