无法使用 React 测试库模拟 useAsync

Can't mock useAsync with react test library

我正在尝试使用 @testing-library/react 测试使用 useAsync 挂钩的组件。

如果我在 TestAPI 模块上使用 jest.mock,然后是 getTest.mockResolvedValueOnce(testArray);在 getTest 函数上然后我希望模拟正确 return 测试值。

测试:

import React from "react";
import { render, screen, waitFor } from "@testing-library/react";
import TestPanel from "./TestPanel";
import { getTest } from "./TestAPI";

jest.mock("./TestAPI");

it("renders cards correctly", async () => {
  const testArray = ["hi there"];
  getTest.mockResolvedValueOnce(testArray);

  render(<TestPanel />);

  expect(getTest).toHaveBeenCalledTimes(1);
  expect(getTest).toHaveBeenCalledWith();

  await waitFor(() => expect(screen.getByText("hi there")).toBeInTheDocument());
});

要测试的组件:

import React from "react";
import { useAsync } from "react-async-hook";
import { getTest } from "./TestAPI";

export default function TestPanel() {
  const { result: elems } = useAsync(getTest, []);

  return (
    <div>
      {elems &&
        elems.map((elem) => {
          return <div>{elem}</div>;
        })}
    </div>
  );
}

API 调用:

import React from "react";
import axios from "axios";

export async function getTest(): Promise {
  const response = await axios.get("/someservice");

  return response.data || [];
}

但是如果我 运行 测试然后抛出一个异常说“elems.map”是未定义的。

仔细观察,元素似乎是一个承诺。

我做错了什么吗?

我认为你应该从 useAsync 挂钩本身模拟你的 return。

jest.mock("path/to/useAsync", () => ({
  result: ["test"]
}));`

这些是您的问题:react-async-hook & jest

Here react-async-hook 使用 instanceof PromiseJest.mockResolvedValueOnce returns 不是真正的 JS Promise,而是一个类似 promise 的对象。因此 useAsync() 将 mock 视为 sycn 函数。

解决方案是使用mockImplementationOnce代替mockResolvedValueOnce

getTest.mockImplementation(async () => testArray)

来自docs:

mockFn.mockResolvedValueOnce(value)

Syntactic sugar function for:

jest.fn().mockImplementationOnce(() => Promise.resolve(value));

但是,遗憾的是,它不仅仅是语法糖。