【问题标题】:jest spyOn not working on index file, cannot redefine propertyjest spyOn 无法处理索引文件,无法重新定义属性
【发布时间】:2021-08-24 14:19:40
【问题描述】:

我有UserContext 和一个从src/app/context/user-context.tsx 导出的钩子useUser。 此外,我在src/app/context 中有一个 index.tsx 文件,它导出所有子模块。

如果我监视 src/app/context/user-context 它可以工作,但将导入更改为 src/app/context 我得到:

TypeError: Cannot redefine property: useUser at Function.defineProperty (<anonymous>)

为什么会这样?

源代码:

// src/app/context/user-context.tsx

export const UserContext = React.createContext({});

export function useUser() {
  return useContext(UserContext);;
}

// src/app/context/index.tsx

export * from "./user-context";
// *.spec.tsx

// This works:
import * as UserContext from "src/app/context/user-context";

// This does not work:
// import * as UserContext from "src/app/context";

it("should render complete navigation when user is logged in", () => {

    jest.spyOn(UserContext, "useUser").mockReturnValue({
        user: mockUser,
        update: (user) => null,
        initialized: true,
    });
})

【问题讨论】:

  • 你是如何在被测试的代码中导入UserContext的?如果您从“src/app/context/user-context”导入,那么您需要在规范文件中以相同的方式导入它,否则它不会模拟相同的东西。虽然您的 TypeError 似乎是一个不同的问题......

标签: reactjs typescript jestjs spyon


【解决方案1】:

UserContextapp/context/index.tsx 重新导出时会引发该问题,因为它是 Typescript 在 3.9 之前的版本中如何处理重新导出的错误。

这个问题在 3.9 版本已经修复,所以将你项目中的 Typescript 升级到这个版本或更高版本。

这个问题是reported here 并已解决 与 fix here 上的 cmets

以下是不升级版本的解决方法。

在您的index.tsx 文件中有一个对象,其属性作为导入的方法,然后导出该对象。

src/app/context/index.tsx

import { useUser } from './context/user-context.tsx'

const context = {
  useUser,
  otherFunctionsIfAny
}

export default context;

或者这也应该有效,

import * as useUser from './context/user-context.tsx';

export { useUser };

export default useUser;

然后监视他们,

import * as UserContext from "src/app/context";

it("should render complete navigation when user is logged in", () => {

    jest.spyOn(UserContext, "useUser").mockReturnValue({
        user: mockUser,
        update: (user) => null,
        initialized: true,
    });
});

Ref

提示:- 除了重新导出的问题外,以前的版本也不支持实时绑定,即,当导出模块发生变化时,导入模块无法看到发生的变化在出口商方面。

例如:

Test.js

let num = 10;

function add() {
    ++num;  // Value is mutated
}

exports.num = num;
exports.add = add;

index.js

一个similar issue,但由于导入的路径。

此错误消息(JavaScript)的原因在这篇文章TypeError: Cannot redefine property: Function.defineProperty ()中进行了解释

【讨论】:

  • 我们使用的是 TS 4.4.4,但还是有问题;我相信这是esbuild的问题?
【解决方案2】:

如果您查看 js 代码 produced 进行重新导出,它看起来像这样

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _context = require("context");

Object.keys(_context).forEach(function (key) {
  if (key === "default" || key === "__esModule") return;
  if (key in exports && exports[key] === _context[key]) return;
  Object.defineProperty(exports, key, {
    enumerable: true,
    get: function get() {
      return _context[key];
    }
  });
});

您得到的错误是由于编译器没有在defineProperty 的选项中添加configurable: true,这将允许开玩笑重新定义导出以模拟它,来自docs

可配置

true 如果此属性描述符的类型可以更改并且如果 可以从相应的对象中删除属性。 默认为false

我认为您可以以某种方式调整您的配置以使编译器添加它,但这完全取决于您使用的工具。

一种更易于访问的方法是使用 jest.mock 而不是 jest.spyOn 来模拟用户上下文文件,而不是尝试重新定义不可配置的导出

it("should render complete navigation when user is logged in", () => {
  jest.mock('./user-context', () => {
    return {
      ...jest.requireActual('./user-context'),
      useUser: jest.fn().mockReturnValue({
        user: {},
        update: (user: any) => null,
        initialized: true
      })
    }
  })
});

【讨论】:

    猜你喜欢
    • 2019-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-26
    • 1970-01-01
    相关资源
    最近更新 更多