Jest spyOn 期间的 TypeError:无法设置只有 getter 的 #<Object> 的属性 getRequest

新手上路,请多包涵

我正在用 TypeScript 编写一个 React 应用程序。我使用 Jest 进行单元测试。

我有一个调用 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);

getRequest 函数如下所示:

 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));
    })
  );

我想尝试使用 Jest 的 API 函数,如下所示:

 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);
    });
  });
});

问题是带有 spyOn 的行会引发以下错误:

   ● 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)

我用谷歌搜索了这个,只找到了关于热重载的帖子。那么在 Jest 测试期间可能导致这种情况的原因是什么?我怎样才能让这个测试通过?

原文由 J. Hesters 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 657
2 个回答

这个很有趣。

问题

Babel 生成的属性只有 get 为重新导出的函数定义。

utils/serverRequests/index.ts 从其他模块重新导出函数,因此当 jest.spyOn 用于监视重新导出的函数时会引发错误。


细节

鉴于此代码从 lib 重新导出所有内容:

 export * from './lib';

Babel 产生这个:

 '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];
    }
  });
});

请注意,所有属性都仅使用 get 定义。

尝试在这些属性中的任何一个上使用 jest.spyOn 都会产生您看到的错误,因为 jest.spyOn 尝试用包含原始函数的间谍替换该属性,但如果该属性是仅用 get 定义。


解决方案

不要将 ../../utils/serverRequests (重新导出 getRequest )导入到测试中,而是导入定义了 getRequest 的模块并使用该模块创建 spy。

替代解决方案

按照@Volodymyr 和@TheF 的建议模拟整个 utils/serverRequests 模块

原文由 Brian Adams 发布,翻译遵循 CC BY-SA 4.0 许可协议

正如评论中所建议的,开玩笑需要在测试对象上设置一个 es6 模块对象没有的设置器。 jest.mock() 允许您通过在导入后模拟所需的模块来解决此问题。

尝试模拟 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);
    });
});

以下是一些有用的链接:

https://jestjs.io/docs/en/es6-class-mocks

https://jestjs.io/docs/en/mock-functions

原文由 The F 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进