Jest - тестирование clearTimeout в хуке useEffect - PullRequest
1 голос
/ 28 июня 2019

В моем компоненте кнопки при нажатии я принудительно отключаю кнопку на 500 мс, чтобы предотвратить многократные отправки, а через 0,5 с отключенное состояние возвращается к значению по умолчанию. Несмотря на разные подходы, я получаю две строки кода, которые я не могу охватить в своем модульном тесте.

См. Упрощенный источник компонентов ниже:

import React, {useState, useEffect} from 'react';
const Button = ({disabled, onClick}) => {
    const [disableButton, forceDisabledButton] = useState(false);
    useEffect(() => {
        let timeId;
        if (disableButton) {
            timeId = setTimeout(() => {
                forceDisabledButton(false);
            }, 500);
        }
        return () => {
            if (timeId) {
                clearTimeout(timeId);
            }
        }
    }, [disableButton]);
    const onButtonClick = (e) => {
        onClick && onClick(e);
        forceDisabledButton(true);
    }
    return (
        <button onClick={onButtonClick} disabled={!disableButton ? disabled : disableButton}>Button</button>
    )
}

Значение по умолчанию disabled установлено на false. Тестовый кейс:

(...)
it('should become disabled after click and then return to its previous disabled state', () => {
    const mountButton = shallow(<Button/>);
    jest.useFakeTimers();
    expect(mountButton.find('button').length).toEqual(1);
    mountButton.find('button').simulate('click');
    expect(mountButton.find('button').prop('disabled')).toEqual(true);
    setTimeout(() => {
        expect(mountButton.find('button').prop('disabled')).toEqual(false);
        expect(clearTimeout).toHaveBeenCalledWith(expect.any(Number));
    }, 600)
})

Строки, которые не охватываются: forceDisabledButton(false); и clearTimeout(timeId);. Сначала я попробовал jest.runAllTimers(), но он также не смог охватить эти две функции. Тест проходит, и в приложении у меня нет никаких предупреждений об утечке памяти (и визуального подтверждения того, что кнопка отключается на 500 мс), поэтому я знаю, что она работает нормально, и обе эти функции вызываются. Какие модификации я могу попытаться применить к этим двум функциям в моем модульном тесте?

Спасибо

1 Ответ

0 голосов
/ 28 июня 2019

Вы можете использовать runAllTimers:

it('should become disabled after click and then return to its previous disabled state', (done) => {
    const mountButton = mount(<Button/>);
    jest.useFakeTimers();
    expect(mountButton.find('button').length).toEqual(1);
    mountButton.find('button').simulate('click');
    expect(mountButton.find('button').prop('disabled')).toEqual(true);
    setTimeout(() => {
        expect(mountButton.find('button').prop('disabled')).toEqual(false);
        done(); // not sure if it's required for case with `runAllTimers`
    }, 600);
    jest.runAllTimers();
})

Или вы можете использовать advanceTimersByTime, который вы можете проверить, если задержка точно равна 500:

it('should become disabled after click and then return to its previous disabled state', () => {
    const mountButton = mount(<Button/>);
    jest.useFakeTimers();
    // ...
    jest.advanceTimersByTime(499);
    expect(mountButton.find('button').prop('disabled')).toEqual(true);
    jest.advanceTimersByTime(2);
    expect(mountButton.find('button').prop('disabled')).toEqual(false);
})

Что касается clearTimeout как часть cleanout для useEffect, он будет вызываться либо при повторном рендеринге, либо при монтировании. Так что если вы действительно хотите проверить, называется ли это, просто запустите повторный рендеринг с mountButton.update(). Но вы можете просто проверить, вызван ли clearTimeout, а проверить, был ли он вызван как часть useEffect hook.

в общем, более безопасно использовать runOnlyPendingTimers сверх runAllTimers, так как позже один раз может вызвать бесконечный цикл, если мы имеем последовательный setTimeout в useEffect (но не в этом случае)

[UPD] shallow() может не работать должным образом, поскольку по-прежнему остается проблемой при интеграции с перехватчиками.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...