Почему хук реакции выдает ошибку действия при использовании с fetch API?

Я продолжаю получать Warning: An update to App inside a test was not wrapped in act(...). в своем наборе тестов всякий раз, когда делаю запрос API и обновляю состояние.

Я использую библиотеку тестирования реакции. Я также пробовал использовать тестовые утилиты ReactDOM, получил тот же результат. Еще одна вещь, которую я попробовал, это обернуть контейнер в act, но все равно получил тот же результат.

Обратите внимание, что: Мое приложение работает, и мой тест проходит. Мне просто нужно знать, что я делал неправильно, или это ошибка в пакете react-dom, из-за которой появляется эта ошибка. И плохо издеваться над ошибкой консоли и заглушать ее.

global.fetch = require('jest-fetch-mock');

it('should clear select content item', async () => {
    fetch.mockResponseOnce(JSON.stringify({ results: data }));

    const { container } = render(<App />);

    const content = container.querySelector('.content');

    await wait();

    expect(content.querySelectorAll('.content--item').length).toBe(2);
});

Вот реализация хука:

const [data, setData] = useState([]);
const [error, setError] = useState('');

const fetchInitData = async () => {
    try {
        const res = await fetch(API_URL);
        const data = await res.json();

        if (data.fault) {
            setError('Rate limit Exceeded');
        } else {
            setData(data.results);
        }
    } catch(e) {
        setError(e.message);
    }
};

useEffect(() => {
    fetchInitData();
}, [isEqual(data)]);

Это все внутри функции?

rrd 18.02.2019 15:08

Да это оно. Позвольте мне добавить, что это работает, и мой тест проходит. Единственная проблема - это раздражающие ошибки

Ademola Adegbuyi 18.02.2019 15:11
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
11
2
16 441
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Это известная проблема, проверьте эту проблему в Github https://github.com/kentcdodds/react-testing-library/issues/281.

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

Резюме:

The solution for this is a bit involved:

  • we polyfill Promise globally with an implementation that can resolve promises 'immediately', such as promise
  • transpile your javascript with a custom babel setup like the one in this repo
  • use jest.runAllTimers(); this will also now flush the promise task queue

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

global.fetch = require('jest-fetch-mock');

it('should clear select content item', /*async */ () => {
    jest.useFakeTimers();
    fetch.mockResponseOnce(JSON.stringify({ results: data }));

    const { container } = render(<App />);

    const content = container.querySelector('.content');

    // await wait();
    act(() => {
      jest.runAllTimers();
    });

    expect(content.querySelectorAll('.content--item').length).toBe(2);
});

Для всех, кто наткнется на это больше года спустя, как и я, проблема, о которой упоминает Джорджио, с тех пор решена, и с тех пор wait заменен на waitFor, как описано здесь:

https://testing-library.com/docs/dom-testing-library/api-async/

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

import { render, waitFor } from '@testing-library/react';
// ...

it('should clear select content item', async () => {
    fetch.mockResponseOnce(JSON.stringify({ results: data }));

    const { container } = render(<App />);

    const content = container.querySelector('.content');

    await waitFor(() =>
        expect(content.querySelectorAll('.content--item').length).toBe(2);
    );
});

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

  beforeEach(async () => {
    await waitFor(() => render(<App />));
  });

Другие вопросы по теме