React testing-library - тестирование обещания, которое устанавливает состояния в первом хуке useEffect - PullRequest
1 голос
/ 04 мая 2020

У меня есть ловушка useEffect, которая загружается при монтировании компонента, например:

useEffect(() => {
   listFiles().then(keys => {
      setKeys(keys)
      console.log(keys)
   }).catch(err => {
        showFail(err.message)
   })
}, [])

Я пытаюсь протестировать функцию с помощью реагирующей библиотеки тестирования, просто используя функцию рендеринга:

beforeEach(() => {
  render(<Dashboard />)
})

Однако, когда я запускаю любой тест, который разрешает обещание и устанавливает состояние:

jest.mock('../utils/storage', () => ({
    listFiles: jest.fn(() => Promise.resolve([])),
}))

, я получаю странное предупреждение об использовании act, чтобы обернуть событие :

  Warning: An update to Dashboard 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 */

    This ensures that you're testing the behavior the user would see in the browser. Learn more at .. 
        in Dashboard

      18 |     useEffect(() => {
      19 |         listFiles().then(keys => {
    > 20 |             setKeys(keys)
         |             ^
      21 |             console.log(keys)
      22 |         }).catch(err => {
      23 |             showFail(err.message)

Я пытался обернуть рендер в act, но он, похоже, ничего не меняет.

Есть предложения, что я здесь не так делаю? Должен ли я делать рендеринг другим способом?

Заранее спасибо!

1 Ответ

1 голос
/ 05 мая 2020

Эта ошибка обычно возникает, когда вы пытаетесь подтвердить, прежде чем компонент завершит обновление всех состояний.

Обратите внимание, что внутри listFiles вы вызываете setKeys(keys), и это обновляет состояние.

Вы должны await, чтобы новые ключи (или файлы) отображались в документе:

expect(await findByText('some file name or key')).toBeInTheDocument();
// more asserts here

В качестве альтернативы, вы можете waitFor макет, чтобы иметь был вызван (хотя я думаю, что вышеуказанный вариант лучше).

await waitFor(() => expect(listFilesMock).toHaveBeenCalled());
// more asserts here

Вышеприведенные методы уже должны быть включены в act для вас библиотекой React Testing, так что вам не нужно это делать


Что такое act() из документа React :

При написании тестов пользовательского интерфейса такие задачи, как рендеринг, пользовательские события или выборка данных, могут рассматриваться как «единицы» взаимодействия с пользовательским интерфейсом. React предоставляет вспомогательный метод act (), который гарантирует, что все обновления, связанные с этими «модулями», были обработаны и применены к DOM, прежде чем вы сделаете какие-либо утверждения.

Имя act происходит от Arrange-Act-Assert pattern.


Полезные ссылки:

...