reactjs 测试时,应将导致React状态更新的代码 Package 到act中

ctehm74n  于 2023-02-04  发布在  React
关注(0)|答案(8)|浏览(205)

我有这样的测试:

import {
  render,
  cleanup,
  waitForElement
} from '@testing-library/react'

const TestApp = () => {
  const { loading, data, error } = useFetch<Person>('https://example.com', { onMount: true });

  return (
    <>
      {loading && <div data-testid="loading">loading...</div>}
      {error && <div data-testid="error">{error.message}</div>}
      {data && 
        <div>
          <div data-testid="person-name">{data.name}</div>
          <div data-testid="person-age">{data.age}</div>
        </div>
      }
    </>
  );
};

  describe("useFetch", () => {
    const renderComponent = () => render(<TestApp/>);

    it('should be initially loading', () => {
      const { getByTestId } = renderComponent();

      expect(getByTestId('loading')).toBeDefined();
    })
  });

测试通过,但收到以下警告:
警告:测试内的TestApp更新未 Package 在act(...)中。

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser
    in TestApp

错误节点_模块/react-dom/cjs/react-dom.development.js:506警告:测试中对TestApp的更新未 Package 在act(...)中。

When testing, code that causes React state updates should be wrapped into act(...):

act(() => {
  /* fire events that update state */
});
/* assert on the output */

This ensures that you're testing the behavior the user would see in the browser
    in TestApp
7jmck4yq

7jmck4yq1#

关键是awaitact然后使用async箭头功能。

await act( async () => render(<TestApp/>));

资料来源:
https://stackoverflow.com/a/59839513/3850405

9njqaruj

9njqaruj2#

尝试在'await waitFor()'中Assert-为此,您的it()函数应该是异步的

it('should be initially loading', async () => {
  const { getByTestId } = renderComponent();

  await waitFor(() => {
    expect(getByTestId('loading')).toBeDefined();
  });
});

保持冷静和快乐的编码

jchrr9hc

jchrr9hc3#

我遇到了同样的问题,通过使用异步查询(findBy*)而不是getBy* 或queryBy* 来解决。

expect(await screen.findByText(/textonscreen/i)).toBeInTheDocument();

异步查询返回Promise而不是element,它在找到与给定查询匹配的元素时进行解析。如果未找到元素或在默认超时1000毫秒后找到多个元素,则拒绝Promise。如果需要查找多个元素,请使用findAllBy。
https://testing-library.com/docs/dom-testing-library/api-async/
但是正如你所知道的,如果屏幕上没有什么东西,它就不能正常工作,所以对于queryBy*,可能需要相应地更新测试用例
[Note:此处没有用户事件,只有简单的呈现,因此findBy将工作,否则我们需要将用户事件置于活动中]

bvhaajcl

bvhaajcl4#

尝试在行为中使用wait

import { act } from 'react-dom/test-utils';
await act(async () => {
            wrapper = mount(Commponent);
            wrapper.find('button').simulate('click');
        });
noj0wjuj

noj0wjuj5#

test('handles server ok', async () => {
    render(
      <MemoryRouter>
        <Login />
      </MemoryRouter>
    )

    await waitFor(() => fireEvent.click(screen.getByRole('register')))

    let domInfo
    await waitFor(() => (domInfo = screen.getByRole('infoOk')))

    // expect(domInfo).toHaveTextContent('登陆成功')
  })

我用这种方法解决了这个问题,你可以试试。

t98cgbkg

t98cgbkg6#

我没有看到act错误的堆栈,但我猜,它是由加载结束时触发的,这导致TestApp状态在测试完成后发生变化并重新呈现。因此,测试结束时的waiting for the loading to disappear应解决此问题。

describe("useFetch", () => {
  const renderComponent = () => render(<TestApp/>);

  it('should be initially loading', async () => {
    const { getByTestId } = renderComponent();

    expect(getByTestId('loading')).toBeDefined();
    await waitForElementToBeRemoved(() => queryByTestId('loading'));
  });
});
twh00eeo

twh00eeo7#

带有react测试库的React应用程序:
我尝试了很多方法,对我有效的是在火灾事件发生后等待一些事情,这样测试完成后就什么都不会发生。
在我的例子中,它是一个日历,在输入字段获得焦点时打开。我触发焦点事件,检查结果焦点事件是否发生,并完成测试。我想可能是日历在我的测试完成之后但在系统完成之前打开,这触发了警告。在完成之前等待日历显示就达到了目的。

fireEvent.focus(inputElement);

await waitFor(async () => {
  expect(await screen.findByText('December 2022')).not.toBeNull();
});
expect(onFocusJestFunction).toHaveBeenCalledTimes(1);
// End

希望这能帮到什么人,我刚花了半天的时间在这上面。

ef1yzkbh

ef1yzkbh8#

这只是react-testing-library (RTL)中的一个警告。您不必在RTL中使用act,因为它已经在后台使用它了。如果您没有使用RTL,则必须使用act

import {act} from "react-dom/test-utils"
test('',{
    act(()=>{
        render(<TestApp/>)
    })
})

当你的组件提取数据时,你会看到这个警告。因为数据提取是异步的,当你在act()中渲染组件时,在场景之后,所有的数据提取和状态更新都将首先完成,然后act()将完成。所以你将使用最新的状态更新来渲染组件
在RTL中消除此警告的最简单方法是运行异步查询函数findBy*

test("test", async () => {
  render(
    <MemoryRouter>
      <TestApp />
    </MemoryRouter>
  );

  await screen.findByRole("button");
});

相关问题