J'écris une application React avec TypeScript. Je fais mes tests unitaires en utilisant Jest.
J'ai une fonction qui fait un appel 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 fonction getRequest
ressemble à ceci:
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));
})
);
Je voulais essayer la fonction API en utilisant Jest comme ceci:
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);
});
});
});
Le problème est que la ligne avec spyOn
lève l'erreur suivante:
● 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)
Je l'ai cherché sur Google et n'ai trouvé que des articles sur le rechargement à chaud. Alors, qu'est-ce qui pourrait causer cela pendant le test Jest? Comment puis-je réussir ce test?
Celui-ci était intéressant.
Babel
génère des propriétés avec uniquement get
défini pour les fonctions réexportées.
utils/serverRequests/index.ts
réexporte des fonctions à partir d'autres modules afin qu'une erreur soit générée lorsque jest.spyOn
est utilisé pour espionner les fonctions réexportées.
Étant donné que ce code réexporte tout de lib
:
export * from './lib';
...Babel
produit ceci:
'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];
}
});
});
Notez que les propriétés sont toutes définies avec uniquement get
.
Essayer d'utiliser jest.spyOn
sur l'une de ces propriétés générera l'erreur que vous voyez, car jest.spyOn
tente de remplacer la propriété par un espion enveloppant la fonction d'origine, mais ne le pourra pas si la propriété est définie avec seulement get
.
Au lieu d'importer ../../utils/serverRequests
(qui réexporte getRequest
) dans le test, importez le module dans lequel getRequest
est défini et utilisez-le pour créer l'espion.
Simulez le module utils/serverRequests
complet comme suggéré par @Volodymyr et @TheF
Comme suggéré dans les commentaires, jest nécessite un objet de définition sur l'objet testé, ce que les objets de module es6 ne possèdent pas. jest.mock()
vous permet de résoudre ce problème en moquant votre module requis après l'importation.
Essayez de vous moquer des exportations à partir de votre fichier 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);
});
});
Voici quelques liens utiles:
https://jestjs.io/docs/en/es6-class-mocks
https://jestjs.io/docs/en/mock-functions