Я пытаюсь выяснить, есть ли способ предотвратить предупреждение not wrapped in act (...), выданное Jest / testing-library, когда мне нечего утверждать после обновления состояния, которое вызывает предупреждение, или если Я должен просто проигнорировать это предупреждение.
Предположим, у меня есть этот простой компонент:
import React, {useEffect, useState} from 'react';
import {getData} from 'services';
const MyComponent = () => {
const [arr, setArr] = useState([]);
useEffect(() => {
(async () => {
const {items} = await getData();
setArr(items);
})();
}, []);
return (
<div>
{!(arr.length > 0) && <p>no array items</p>}
{arr.length > 0 && (
<ul>
{arr.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
)}
</div>
);
};
export default MyComponent;
Предположим, я хочу просто проверить, нормально ли работает этот компонент, даже если getData()
не возвращает мне никаких данных.
Итак, у меня есть такой тест:
import React from 'react';
import {getData} from 'services';
import {render, screen} from 'testUtils';
import MyComponent from './MyComponent';
jest.mock('services', () => ({
getData: jest.fn(),
}));
it('renders', () => {
getData.mockResolvedValue({items: []});
render(<MyComponent />);
expect(screen.getByText('no array items')).toBeInTheDocument();
});
Этот тест будет пройден, но я получу предупреждение not wrapped in act (...), потому что тест завершится до того, как getData()
успеет закончиться.
В этом случае ответ от getData()
устанавливает arr
на то же значение (пустой массив), которое я изначально установил в верхней части компонента. Таким образом, мой пользовательский интерфейс не меняется после завершения асинхронной функции - я все еще просто смотрю на абзац, в котором нет элементов массива - поэтому у меня действительно нет ничего, что я мог бы утверждать, что ожидало бы завершения обновления состояния. .
Я могу expect(getData).toHaveBeenCalledTimes(1)
, но это не дожидается фактического обновления состояния после вызова функции.
Я попытался сделать в тесте произвольную паузу, чтобы дать время setArr(items)
:
it('renders', async () => {
getData.mockResolvedValue({items: []});
render(<MyComponent />);
expect(screen.getByText('no array items')).toBeInTheDocument();
await new Promise(resolve => setTimeout(resolve, 2000));
expect(screen.getByText('no array items')).toBeInTheDocument();
});
Но, похоже, это не помогает, и я, честно говоря, не знаю почему.
Есть ли способ справиться с этой ситуацией, изменив только тест?
Я уверен, что смогу решить эту проблему путем рефакторинга MyComponent, например, передав arr
в MyComponent в качестве опоры и переместив вызов getData()
в родительский компонент или создав некую настраиваемую опору, используемую только для тестирования, которая полностью пропустила бы вызов getData()
, но Я не хочу изменять компоненты только для того, чтобы избежать предупреждений в тестах.
Я использую testing-library / react, v11.2.2.