简体   繁体   English

React 测试库如何使用 waitFor

[英]React testing library how to use waitFor

I'm following a tutorial on React testing.我正在关注关于 React 测试的教程 The tutorial has a simple component like this, to show how to test asynchronous actions:本教程有一个像这样的简单组件,用于展示如何测试异步操作:

import React from 'react'

const TestAsync = () => {
  const [counter, setCounter] = React.useState(0)

  const delayCount = () => (
    setTimeout(() => {
      setCounter(counter + 1)
    }, 500)
  )
  
  return (
    <>
      <h1 data-testid="counter">{ counter }</h1>
      <button data-testid="button-up" onClick={delayCount}> Up</button>
      <button data-testid="button-down" onClick={() => setCounter(counter - 1)}>Down</button>
    </>
  )
}
  
export default TestAsync

And the test file is like this:并且测试文件是这样的:


import React from 'react';
import { render, cleanup, fireEvent, waitForElement } from '@testing-library/react';
import TestAsync from './TestAsync'

afterEach(cleanup);
  
it('increments counter after 0.5s', async () => {
  const { getByTestId, getByText } = render(<TestAsync />); 

  fireEvent.click(getByTestId('button-up'))

  const counter = await waitForElement(() => getByText('1')) 

  expect(counter).toHaveTextContent('1')
});

The terminal says waitForElement has been deprecated and to use waitFor instead.终端说waitForElement已被弃用,改为使用waitFor

How can I use waitFor in this test file?如何在此测试文件中使用waitFor

If you're waiting for appearance , you can use it like this:如果你正在等待出现,你可以这样使用它:

it('increments counter after 0.5s', async() => {
  const { getByTestId, getByText } = render(<TestAsync />);

  fireEvent.click(getByTestId('button-up'));
  
  await waitFor(() => {
    expect(getByText('1')).toBeInTheDocument();
  });
});

Checking .toHaveTextContent('1') is a bit "weird" when you use getByText('1') to grab that element, so I replaced it with .toBeInTheDocument() .当您使用getByText('1')抓取该元素时,检查.toHaveTextContent('1')有点“奇怪”,因此我将其替换为.toBeInTheDocument()

Would it be also possible to wrap the assertion using the act function?是否也可以使用行为 function 来包装断言? Based on the docs I don't understand in which case to use act and in which case to use waitFor.根据文档,我不明白在哪种情况下使用 act 以及在哪种情况下使用 waitFor。

The answer is yes.答案是肯定的。 You could write this instead using act():你可以用 act() 来代替:

    import { act } from "react-dom/test-utils";

        it('increments counter after 0.5s', async() => {
          const { getByTestId, getByText } = render(<TestAsync />);

// you wanna use act() when there is a render to happen in 
// the DOM and some change will take place:
          act(() => {
              fireEvent.click(getByTestId('button-up'));
          });
            expect(getByText('1')).toBeInTheDocument();
        });

Hope this helps.希望这可以帮助。

Current best practice would be to use findByText in that case.当前的最佳做法是在这种情况下使用findByText This function is a wrapper around act , and will query for the specified element until some timeout is reached.这个 function 是act的包装器,它将查询指定的元素,直到达到某个超时。

In your case, you can use it like this:在您的情况下,您可以像这样使用它:

it('increments counter after 0.5s', async () => {
  const { findByTestId, findByText } = render(<TestAsync />); 

  fireEvent.click(await findByTestId('button-up'))

  const counter = await findByText('1')
});

You don't need to call expect on its value, if the element doesn't exist it will throw an exception你不需要调用它的值,如果元素不存在它expect抛出异常

You can find more differences about the types of queries here您可以在此处找到有关查询类型的更多差异

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM