0

我有一个使用从服务器获取数据的钩子的组件,并且我已经模拟了该钩子以返回我的测试数据。现在如果mutate调用函数(由钩子返回),正常的实现会再次获取数据并导致重新渲染(我正在使用swr这里是mutate参考)。

如何在模拟setState钩子上触发重新渲染/?

我要测试的内容:简单地说,如果用户创建了一个项目,则应该重新获取并显示项目列表。

说明问题的代码:

const existing = [...]
const newlyCreated = [...];

useData.mockReturnValue({ data: [existing] });

const { getByRole, findByText } = render(<MyComponent />);
const form = getByRole("form");
const createButton = within(form).getByText("Create");

useData.mockReturnValue({ data: [existing, newlyCreated] });

// createButton.click();
// Somehow trigger re-render???

for (const { name } of [existing, newlyCreated]) await findByText(name);
4

1 回答 1

0

您无需在测试中触发重新渲染。

问题是:你的 UI 上的按钮会改变数据,但是因为你在嘲笑useData这种改变并没有发生。

您可以简单地添加mutate()到您的模拟并为其分配模拟功能。

您不需要对 SWR 自己的内部工作进行单元测试mutate()- 他们自己的项目已经涵盖了这一点。

const existing = ["Mercury", "Venus", "Earth", "Mars"];
const newItem = "Jupiter";

test("Create button should call mutate() with correct value", async () => {
  const mutate = jest.fn();
  jest.spyOn(useData, "default").mockImplementation(() => ({
    data: existing,
    mutate
  }));
  let result;
  act(() => {
    result = render(<Form />);
  });
  await waitFor(() => {
    existing.forEach((item) => {
      expect(result.getByText(item)).toBeInTheDocument();
    });
  });
  const input = result.container.querySelector("input");
  fireEvent.change(input, { target: { value: newItem } });
  const createButton = result.getByText("Create");
  createButton.click();
  expect(mutate).toBeCalledWith([...existing, newItem], false);
});

CodeSandbox 上的示例

于 2021-07-21T13:06:05.520 回答