Проверьте промежуточное состояние в обработчике asyn c с React и Enzyme - PullRequest
0 голосов
/ 23 марта 2020

Несмотря на чтение документации энзим и act , я не смог найти ответ на свой вариант использования, потому что примеры показывают только простые варианты использования.

У меня есть компонент React, отображающий кнопку. Обработчик onClick устанавливает логическое значение загрузки и вызывает внешний API. Я хочу утверждать, что компонент показывает индикатор загрузки, когда мы нажимаем на кнопку.

Вот компонент:

export default function MyButton(): ReactElement {
    const [loading, setLoading] = useState<boolean>(false);
    const [data, setData] = useState<any>(null);

    const onClick = async (): Promise<void> => {
        setLoading(true);

        const response = await fetch('/uri');
        setData(await response.json());

        setLoading(false);
    };

    if (loading) {
        return <small>Loading...</small>;
    }

    return (
        <div>
            <button onClick={onClick}>Click Me!</button>

            <div>
                {data}
            </div>
        </div>
    );
}

А вот тест:

test('should display Loading...', async () => {
    window.fetch = () => Promise.resolve({
        json: () => ({
            item1: 'item1',
            item2: 'item2',
        }),
    });

    const component = mount(<MyButton />);

    // Case 1 ✅ => validates the assertion BUT displays the following warning
    component.find('button').simulate('click');
    // Warning: An update to MyButton 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 [URL to fb removed because SO does not accept it]

    // Case 2 ❌ => fails the assertion AND displays the warning above
    act(() => {
        component.find('button').simulate('click');
    });

    // Case 3 ❌ => fails the assertion BUT does not display the warning
    await act(async () => {
        component.find('button').simulate('click');
    });

    expect(component.debug()).toContain('Loading...');
});

Как вы можете видеть, если я избавлюсь от предупреждения, мой тест больше не будет удовлетворять, поскольку он ожидает выполнения обещания. Как мы можем утверждать изменение промежуточного состояния при использовании act?

Спасибо.

1 Ответ

1 голос
/ 23 марта 2020

Просто разрешите обещание вручную:

const mockedData = {
  json: () => ({
    item1: 'item1',
    item2: 'item2',
  }),
};
let resolver;
window.fetch = () => new Promise((_resolver) => {
  resolver = _resolver;
});

// ....
await act(async () => {
  component.find('button').simulate('click');
});
expect(component.debug()).toContain('Loading...');
resolver(mockedData);
expect(component.debug()).not.toContain('Loading...');

PS, но для удобства чтения я бы предпочел 2 отдельных теста: один с new Promise();, который никогда не разрешается, и другой с Promise.resolve(mockedData), который будет разрешен автоматически

...