Jest.js 如何使用React Query自定义挂接对组件进行单元测试?

5hcedyr0  于 12个月前  发布在  Jest
关注(0)|答案(1)|浏览(112)

我在练习是因为我对React Testing Library with Jest很感兴趣。
我正在编写组件的单元测试,但是我总是遇到错误,所以我想问你一个问题。
首先,我正在为webtoon信息编写一个组件,其中有一个名为useWebtoonsQuery的自定义挂钩。
useWebtoonsQuery如下所示。

const useWebtoonsQuery = () => {
  const webtoons = new WebtoonService();
  const queryClient = useQueryClient();

  const toggleFollowing = useMutation(({ id }: IToggle) => webtoons.followWebtoon(id));

  const webtoonAlimToggle = (id: number) => {
    const queryClient = useQueryClient();
    return useMutation(() => webtoons.updateWebtoonAlim(id));
  };

  return {
    toggleFollowing,
    webtoonAlimToggle,
  };
};

export default useWebtoonsQuery;

字符串
我编写了如下测试代码,以确认在单元测试中按下了钟形按钮(如果按下了,图标的颜色会发生变化)。

function withRouter(routes: React.ReactNode, initialEntry = "/") {
  return (
    <MemoryRouter initialEntries={[initialEntry]}>
      <Routes>{routes}</Routes>
    </MemoryRouter>
  );
}

function withQuery(ui: React.ReactNode) {
  const testClient = createTestQueryClient();
  const { rerender, ...result } = render(
    <QueryClientProvider client={testClient}>{ui}</QueryClientProvider>
  );

  return {
    ...result,
    rerender: (rerenderUi: React.ReactElement) =>
      rerender(
        <QueryClientProvider client={testClient}>
          {rerenderUi}
        </QueryClientProvider>
      ),
  };
}

// WebtoonInfo.test.tsx
jest.mock("../../../hooks/useWebtoonsQuery", () => ({
  __esModule: true,
  default: () => ({
    data: testData,
    toggleFollowing: {
      mutate: jest.fn(),
    },
    webtoonAlimToggle: jest.fn().mockReturnValue({
      mutate: jest.fn(),
    }),
  }),
}));

describe("WebtoonInfo component", () => {
 
  it("should call webtoonAlimToggle.mutate when bell button is clicked", () => {
    withQuery(
      withRouter(
        <Route
          path="/"
          element={
            <RecoilRoot>
              <WebtoonInfo data={testData} />
            </RecoilRoot>
          }
        />
      )
    );

    const bellButton = screen.getByLabelText("bell");
    userEvent.click(bellButton);

    const useWebtoonsQuery = jest.fn().mockReturnValue({
      webtoonAlimToggle: jest.fn().mockReturnValue({
        mutate: jest.fn(),
      }),
    });
    const { webtoonAlimToggle } = useWebtoonsQuery();

    expect(webtoonAlimToggle.mutate).toHaveBeenCalledTimes(1);
  });
});


但是,与预期结果相反,出现了以下错误。

应为(已收到)。toHaveBeenCalledTimes(应为)

Matcher error: received value must be a mock or spy function

Received has value: undefined

  145 |     const { webtoonAlimToggle } = useWebtoonsQuery();
  146 |
> 147 |     expect(webtoonAlimToggle.mutate).toHaveBeenCalledTimes(1);
      |                                      ^
  148 |   });
  149 | });
  150 |


我想模拟useQuery的自定义钩子,并只进行UI测试。
我们将单独测试自定义挂钩。
但是,我写的代码不好,因为我不知道,所以我会很感激,如果你能告诉我如何解决它。

qoefvg9y

qoefvg9y1#

您试图直接从模拟的useWebtoonsQuery钩子访问webtoonAlimToggle的mutate函数。然而,在测试中模拟useWebtoonsQuery钩子的方法并不能正确地返回所需的值。这样试试

import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { MemoryRouter, Route, Routes } from "react-router-dom";
import { QueryClientProvider } from "react-query";
import { RecoilRoot } from "recoil";
import WebtoonInfo from "./WebtoonInfo";
import useWebtoonsQuery from "../../../hooks/useWebtoonsQuery";

jest.mock("../../../hooks/useWebtoonsQuery");

describe("WebtoonInfo component", () => {
  it("should call webtoonAlimToggle.mutate when bell button is clicked", () => {
    const mockMutate = jest.fn();

    useWebtoonsQuery.mockReturnValue({
      webtoonAlimToggle: jest.fn().mockReturnValue({
        mutate: mockMutate,
      }),
    });

    render(
      <MemoryRouter initialEntries={["/"]}>
        <Routes>
          <Route
            path="/"
            element={
              <RecoilRoot>
                <WebtoonInfo data={testData} />
              </RecoilRoot>
            }
          />
        </Routes>
      </MemoryRouter>
    );

    const bellButton = screen.getByLabelText("bell");
    userEvent.click(bellButton);

    expect(mockMutate).toHaveBeenCalledTimes(1);
  });
});

字符串
这里使用jest.mock函数模拟useWebtoonsQuery钩子。然后,在测试用例中,使用WebtoonsQuery.mockReturnValue指定模拟钩子的期望返回值。
这确保了webtoonAlimToggle函数返回一个带有可变函数的对象,该对象可以被监视和Assert。

相关问题