React + Jest:测试未调用 setTimeOut

时间:2021-07-05 06:52:45

标签: reactjs jestjs settimeout use-effect react-testing-library

我目前在 setTimeOut 中有一个 useEffect,我可以使用以下方法对其进行测试:

jest.useFakeTimers();
jest.advanceTimersByTime(5000);

而且效果很好。但是,随着 successMessage 的变化,setTimeout 会被触发几次。如何编写测试来检查 setTimeOut 仅在 successMessage 不是空字符串时才被调用?

我正在使用 jest 和 react-testing-library。

这是我的反应代码。

enum HELPER_MESSAGES {
    SUCCESS = 'Congratulations you signed up!',
    ERROR = 'Email address invalid',
}

export function EmailCapture (): ReactElement {
    const [inputValue, setInputValue] = useState<string>('');
    const [errorMessage, setErrorMessage] = useState<string>('');
    const [successMessage, setSuccessMessage] = useState<string>('');

    function handleOnClick (): void {
        const EMAIL_REGEX: RegExp = /^[a-zA-Z0-9]+([-._][a-zA-Z0-9]+)*@([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*.)+\.+[a-zA-Z]{2,}$/;
        const isInputValid: boolean = EMAIL_REGEX.test(inputValue) && inputValue !== '';

        if (isInputValid) {
            setSuccessMessage(HELPER_MESSAGES.SUCCESS);
        } else {
            setErrorMessage(HELPER_MESSAGES.ERROR);
        }
    }

    useEffect((): () => void => {
        const resetAfterSuccessTimer: NodeJS.Timeout = setTimeout((): void => {
            setSuccessMessage('');
        }, 5000);

        return (): void => {
            clearTimeout(resetAfterSuccessTimer);
        };
    }, [successMessage]);

    function handleOnChange (e: ChangeEvent<HTMLInputElement>): void {
        setInputValue(e.target.value);
        setErrorMessage('');
        setSuccessMessage('');
    }

    return (
        <TextInput
            onChange={handleOnChange}
            error={errorMessage}
            success={successMessage}
            value={inputValue}
        />
    );
}

我正在关注 TDD,所以我希望编写一个测试来让我编写以下代码:

useEffect((): () => void => {
    let resetAfterSuccessTimer: NodeJS.Timeout;

    if (successMessage) {
        resetAfterSuccessTimer= setTimeout((): void => {
            setSuccessMessage('');
            setButtonText('Sign up!');
            console.log('sexy');
        }, 5000);
    }

    return (): void => {
        clearTimeout(resetAfterSuccessTimer);
    };
}, [successMessage]);

sexy 这个词应该只被控制台记录一次。

1 个答案:

答案 0 :(得分:0)

根据他们的文档弄清楚:https://jestjs.io/docs/timer-mocks,您可以执行以下操作:

expect(setTimeout).not.toHaveBeenCalled();

当你想检查它是否被调用过一次时,你可以这样做:

expect(setTimeout).toHaveBeenCalledTimes(1);

注意:这是在测试一个实现细节,所以要注意这一点。