Estoy escribiendo una aplicación React con TypeScript. Hago mis pruebas unitarias usando Jest.
Tengo una función que hace una llamada a la API:
import { ROUTE_INT_QUESTIONS } from "../../../config/constants/routes"; import { intQuestionSchema } from "../../../config/schemas/intQuestions"; import { getRequest } from "../../utils/serverRequests"; const intQuestionListSchema = [intQuestionSchema]; export const getIntQuestionList = () => getRequest(ROUTE_INT_QUESTIONS, intQuestionListSchema); La función getRequest se ve así:
import { Schema } from "normalizr"; import { camelizeAndNormalize } from "../../core"; export const getRequest = (fullUrlRoute: string, schema: Schema) => fetch(fullUrlRoute).then(response => response.json().then(json => { if (!response.ok) { return Promise.reject(json); } return Promise.resolve(camelizeAndNormalize(json, schema)); }) );Quería probar la función API usando Jest así:
import fetch from "jest-fetch-mock"; import { ROUTE_INT_QUESTIONS } from "../../../config/constants/routes"; import { normalizedIntQuestionListResponse as expected, rawIntQuestionListResponse as response } from "../../../config/fixtures"; import { intQuestionSchema } from "../../../config/schemas/intQuestions"; import * as serverRequests from "./../../utils/serverRequests"; import { getIntQuestionList } from "./intQuestions"; const intQuestionListSchema = [intQuestionSchema]; describe("getIntQuestionList", () => { beforeEach(() => { fetch.resetMocks(); }); it("should get the int question list", () => { const getRequestMock = jest.spyOn(serverRequests, "getRequest"); fetch.mockResponseOnce(JSON.stringify(response)); expect.assertions(2); return getIntQuestionList().then(res => { expect(res).toEqual(expected); expect(getRequestMock).toHaveBeenCalledWith(ROUTE_INT_QUESTIONS, intQuestionListSchema); }); }); }); El problema es que la linea con spyOn arroja el siguiente error:
● getRestaurantList › should get the restaurant list TypeError: Cannot set property getRequest of #<Object> which has only a getter 17 | 18 | it("should get the restaurant list", () => { > 19 | const getRequestMock = jest.spyOn(serverRequests, "getRequest"); | ^ 20 | fetch.mockResponseOnce(JSON.stringify(response)); 21 | 22 | expect.assertions(2); at ModuleMockerClass.spyOn (node_modules/jest-mock/build/index.js:706:26) at Object.spyOn (src/services/api/IntQuestions/intQuestions.test.ts:19:33)Busqué en Google esto y solo encontré publicaciones sobre recarga en caliente. Entonces, ¿qué podría causar esto durante la prueba Jest? ¿Cómo puedo hacer para pasar esta prueba?
Este fue interesante.
Babel genera propiedades con solo definirse get funciones reexportadas.
utils/serverRequests/index.ts reexporta funciones de otros módulos, por lo que se genera un error cuando se usa jest.spyOn para espiar las funciones reexportadas.
Dado este código reexportando todo desde lib :
export * from './lib'; ... Babel produce esto:
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _lib = require('./lib'); Object.keys(_lib).forEach(function (key) { if (key === "default" || key === "__esModule") return; Object.defineProperty(exports, key, { enumerable: true, get: function get() { return _lib[key]; } }); }); Tenga en cuenta que todas las propiedades están definidas solo con get .
Intentar usar jest.spyOn en cualquiera de esas propiedades generará el error que está viendo porque jest.spyOn intenta reemplazar la propiedad con un espía que envuelve la función original, pero no puede si la propiedad se define solo con get .
En lugar de importar ../../utils/serverRequests (que vuelve a exportar getRequest ) a la prueba, importe el módulo donde se define getRequest y use ese módulo para crear el espía.
Simule todo el módulo utils/serverRequests como lo sugieren @Volodymyr y @TheF
Como se sugiere en los comentarios, jest requiere un setter en el objeto probado que los objetos del módulo es6 no tienen. jest.mock() le permite resolver esto burlándose de su módulo requerido después de la importación.
Intente burlarse de las exportaciones de su archivo serverRequests
import * as serverRequests from './../../utils/serverRequests'; jest.mock('./../../utils/serverRequests', () => ({ getRequest: jest.fn() })); // ... // ... it("should get the int question list", () => { const getRequestMock = jest.spyOn(serverRequests, "getRequest") fetch.mockResponseOnce(JSON.stringify(response)); expect.assertions(2); return getIntQuestionList().then(res => { expect(res).toEqual(expected); expect(getRequestMock).toHaveBeenCalledWith(ROUTE_INT_QUESTIONS, intQuestionListSchema); }); }); Aquí hay algunos enlaces útiles:
https://jestjs.io/docs/en/es6-class-mocks
https://jestjs.io/docs/en/mock-functions
Probado con ts-jest como compilador, funcionará si se burla del módulo de esta manera:
import * as serverRequests from "./../../utils/serverRequests"; jest.mock('./../../utils/serverRequests', () => ({ __esModule: true, ...jest.requireActual('./../../utils/serverRequests') })); const getRequestMock = jest.spyOn(serverRequests, "getRequest");