使用 Jest 模拟 React 自定义钩子

dar*_*arx 25 mocking reactjs jestjs react-hooks

在对 React 组件进行单元测试时,我需要模拟我的自定义钩子。我读过一些关于这个简单任务的教程和 stackoverflow 答案,但没有运气正确地实现它。

我对单一测试最简单的设置如下:

// TestComponent.js

import React from "react";
import useTest from "./useTest";

const TestComponent = () => {
  const { state } = useTest("initial_value");

  return <div>{state}</div>;
};

export default TestComponent;
Run Code Online (Sandbox Code Playgroud)
// useTest.jsx - simple custom hook

import React, { useState } from "react";

const useTest = (initialState) => {
  const [state] = useState(initialState);
  return { state };
};

export default useTest;

Run Code Online (Sandbox Code Playgroud)
// TestComponent.test.jsx - my test case

import React from "react";
import { render } from "@testing-library/react";
import TestComponent from "./TestComponent";

jest.mock("./useTest", () => ({
  useTest: () => "mocked_value",
}));

test("rendertest", () => {
  const component = render(<TestComponent />);
  expect(component.container).toHaveTextContent("mocked_value");
});

Run Code Online (Sandbox Code Playgroud)

因此,我尝试模拟useTest自定义挂钩以返回“mocked_value”,而不是真正的自定义挂钩中的“initial_value”。但上面的代码只是给了我这个错误:

TypeError: (0 , _useTest.default) is not a function

      3 | 
      4 | const TestComponent = () => {
    > 5 |   const { state } = useTest("initial_value");
        |                     ^
      6 | 
      7 |   return <div>{state}</div>;
      8 | };
Run Code Online (Sandbox Code Playgroud)

我也尝试过:

import useTest from './useTest';
// ...
jest.spyOn(useTest, "useTest").mockImplementation(() => "mocked_value");
Run Code Online (Sandbox Code Playgroud)
import useTest from './useTest';
// ...
jest.spyOn(useTest, "useTest").mockReturnValue("mocked_value");
Run Code Online (Sandbox Code Playgroud)

但两者都给了我错误Cannot spy the useTest property because it is not a function; undefined given instead

我该如何实施这个测试?

dar*_*arx 48

我在回答我自己。这样它就可以工作了:

jest.mock("./useTest", () => ({
  useTest: () => ({ state: 'mocked_value' }),
}));
Run Code Online (Sandbox Code Playgroud)

如果我想在自定义挂钩中使用默认导出:

jest.mock("./useTest", () => ({
  __esModule: true,
  default: () => ({ state: 'mocked_value' }),
}));
Run Code Online (Sandbox Code Playgroud)

另外,如果我还想setState在我的钩子中使用方法并将其导出,我可以这样模拟它:

const mockedSetState = jest.fn();

jest.mock("./useTest", () => ({
  useTest: () => ({ state, setState: mockedSetState }),
}));
Run Code Online (Sandbox Code Playgroud)

现在可以检查是否setState被调用过一次:

expect(mockedSetState).toHaveBeenCalledTimes(1);
Run Code Online (Sandbox Code Playgroud)