首页 > 解决方案 > 强制重新查询元素以触发点击处理程序

问题描述

我有一个测试,我断言我的 API 请求提供了正确的参数。我正在使用 MSW 来模拟 api,并为请求处理程序提供了一个间谍:

test("supplies order direction descending if header button is clicked twice", async () => {
    const mockHandler = jest.fn(handler);

    server.use(rest.get(`${config.apiHost}/targets`, mockHandler));

    // First request to /targets happens on render
    render(<Route>{(props) => <TargetList history={props.history} />}</Route>);
    const button = await screen.findByRole("button", { name: "Port" });

    // Second request to /targets happens on button click
    userEvent.click(button);
    await waitFor(() => {
      expect(mockHandler).toHaveBeenCalledTimes(2);
    });
    
    // Third request to /targets SHOULD happen here but doesn't
    userEvent.click(button);
    await waitFor(() => {
      expect(mockHandler).toHaveBeenCalledTimes(3);
      const lastCall = mockHandler.mock.calls[2];
      const requestArg = lastCall[0];
      expect(requestArg.url.searchParams.get("orderby")).toBe("port");
      expect(requestArg.url.searchParams.get("direction")).toBe("descending");
    });
  });

上面的代码不起作用,因为在按钮上第二次触发 click 事件似乎什么也没做。但是,如果我重新查询按钮,则可以成功触发处理程序:

test("supplies order direction descending if header button is clicked twice", async () => {
    ...
    const button = await screen.findByRole("button", { name: "Port" });

    // Second request to /targets happens on b utton click
    userEvent.click(button);
    await waitFor(() => {
      expect(mockHandler).toHaveBeenCalledTimes(2);
    });
    // Third request to /targets now works!
    const button2 = await screen.findByRole("button", { name: "Port" });
    userEvent.click(button2);
    await waitFor(() => {
      expect(mockHandler).toHaveBeenCalledTimes(3); // SUCCESS!
      ...
    });
  });

为什么我必须重新查询相同的元素?我做错了什么吗?

标签: react-testing-library

解决方案


我没有完整的源代码,但我会假设您正在对您的点击事件处理程序执行某些操作,这将强制响应再次呈现,在这种情况下,旧元素将不再存在于 DOM 上,因此不会调用点击事件处理程序。

PS:您可以使用反应生命周期挂钩来确定组件是否被重新渲染。


推荐阅读