Jest.js 带有userEvent.click错误act()警告的React测试库

o8x7eapl  于 2023-09-28  发布在  Jest
关注(0)|答案(4)|浏览(205)

我用Jest和React测试库写了几个测试。它们都模拟fetch,并使用userEvent.click调用来触发提交按钮,从而发出fetch请求。状态在组件中得到更新,我做出Assert。我使用useEffect钩子来填充数据数组,但它只在初始加载时运行,因为我向它传递了一个空的依赖数组。目前我所有的测试都通过了。如果我把它们一起运行,我会得到一个错误的act()错误,它源于useEffect:

Warning: It looks like you're using the wrong act() around your test interactions.
Be sure to use the matching version of act() corresponding to your renderer:

// for react-dom:
import {act} from 'react-dom/test-utils';
// ...
act(() => ...);

// for react-test-renderer:
import TestRenderer from react-test-renderer';
const {act} = TestRenderer;
// ...
act(() => ...);

但是,当我单独运行其中一个时,我不会收到警告。我可以自己运行其中任何一个,而不会得到任何警告。只有在同时运行两个或更多测试时,我才会收到警告。
我的测试是:

describe("CartDetail", () => {
  test("Order is submitted when user clicks Place Order button.", async () => {
    global.fetch = jest.fn().mockImplementationOnce(() =>
      Promise.resolve({
        status: 200,
      })
    );
    
    renderComponent();

    await act(async () => {
      userEvent.click(await screen.findByRole("button", { name: "Place Order" }));
    });

    expect(screen.queryByText("Your meal order was successfully processed.")).toBeInTheDocument();
  });

  test("Error message is displayed to user when order fails with a 400.", async () => {
    global.fetch = jest.fn().mockImplementationOnce(() =>
      Promise.resolve({
        status: 400,
      })
    );
    
    renderComponent();

    await act(async () => {
      userEvent.click(await screen.findByRole("button", { name: "Place Order" }));
    });

    expect(screen.queryByText("Please confirm that you are ordering at least one of each meal you have in your cart.")).toBeInTheDocument();
    userEvent.click(screen.getByLabelText("Close alert"));
  });

  test("Error message is displayed to user when API fails.", async () => {
    global.fetch = jest.fn().mockRejectedValueOnce(() =>
      Promise.reject({
        status: 500,
      })
    );
    
    renderComponent();

    await act(async () => {
      userEvent.click(await screen.findByRole("button", { name: "Place Order" }));
    });

    expect(screen.queryByText("Your order failed.")).toBeInTheDocument();
    userEvent.click(screen.getByLabelText("Close alert"));
  });
});

我读到过你不必在act()中 Package userEvent,因为它已经在幕后了。然而,如果我没有将其封装在act中,我的测试就会失败并抛出:

Warning: An update to CartDetail inside a test was not wrapped in act(...).
    
When testing, code that causes React state updates should be wrapped into act(...):
    
act(() => {
  /* fire events that update state */
});
/* assert on the output */

即使我注解掉了Assert,我的测试通过了(当然),但我仍然得到错误的act()警告。问题直接来自:

await act(async () => {
  userEvent.click(await screen.findByRole("button", { name: "Place Order" }));
});

我不明白这个问题是如何从useEffect中产生的,当它在初始加载时执行并且不再运行时,包括通过www.example.com()单击按钮时userEvent.click。我已经搜索了互联网,没有什么比这更接近我了。This GitHub thread提到这是一个已知的问题,但它现在有点旧,所以我不知道它是否仍然有效。

bttbmeg0

bttbmeg01#

您可能只需要等待click调用。

await userEvent.click(await screen.findByRole("button", { name: "Place Order" });

14版本中,像clicktype这样的方法返回一个Promise。这在13版本中是不同的。

y0u0uwnf

y0u0uwnf2#

我终于找到了一个变通办法。这篇GitHub文章提到了在act()中 Package userEvent()调用,我已经做过了。解决Warning: It looks like you're using the wrong act() around your test interactions.控制台错误的方法是在userEvent()调用之后和Assert之前添加以下代码:

await new Promise((resolve) => setTimeout(resolve, 0));

我更新的测试现在看起来像这样:

test("Order is submitted when user clicks Place Order button.", async () => {
    global.fetch = jest.fn().mockImplementationOnce(() =>
      Promise.resolve({
        status: 200,
      })
    );
    
    renderComponent();

    await act(async () => {
      userEvent.click(await screen.findByRole("button", { name: "Place Order" }));
    });

    await new Promise((resolve) => setTimeout(resolve, 0));

    expect(screen.queryByText("Your meal order was successfully processed.")).toBeInTheDocument();
  });

错误行为()警告现在已经消失。

ecfdbz9o

ecfdbz9o3#

我的问题与此类似,因为我从act(...)块中获得了“use act(...)”错误,但修复方法略有不同。
根据这个https://github.com/testing-library/user-event/issues/255#issuecomment-624847626,
如果您使用act Package userEvent调用,它应该可以工作。react-testing-library中的fireEvent会自动执行此操作,但dom-testing-library中的fireEvent不会(因为act是react特性)。user-event从dom-testing-library调用fireEvent,因为这个库不是react特定的。
因此,我替换了userEvent.click并返回到fireEvent.click,加上您使用macrotask等待微任务队列为空的修复,整个事情终于工作了。
我的测试的其余部分使用await ...find*(..)而不是getquery,并且总是重新查找DOM元素而不是将其放入变量中,并且每个事件都通过helper函数 Package 在act中。真是一团糟。
感觉就像@testing-library/react在计算React重新渲染之类的东西,而不是等待React稳定下来。我有一个工作测试失败,只是因为在onClick处理程序中添加了一个愚蠢的await Promise.resolve();,而这个处理程序已经是异步的。WTF.

t8e9dugd

t8e9dugd4#

我在不同类型的测试中遇到了同样的问题。其中一些通过使用awaitwaitFor进行Assert来修复
使用await waitFor(()=> expect(...))
对于剩余的测试,将react测试库更新到版本14解决了这个问题

"@testing-library/react": "^14.0.0",

相关问题