I currently have a setTimeOut
inside a useEffect
, I was able to test it by using:
jest.useFakeTimers();
jest.advanceTimersByTime(5000);
And it works great. However, the setTimeout is getting triggered a few times as successMessage
changes. How can I write a test that checks that setTimeOut
is only called when successMessage
is not an empty string?
I'm using jest and react-testing-library.
Here is my react code.
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}
/>
);
}
I'm following TDD, so I'm looking to write a test that will make me write the following code:
useEffect((): () => void => {
let resetAfterSuccessTimer: NodeJS.Timeout;
if (successMessage) {
resetAfterSuccessTimer= setTimeout((): void => {
setSuccessMessage('');
setButtonText('Sign up!');
console.log('sexy');
}, 5000);
}
return (): void => {
clearTimeout(resetAfterSuccessTimer);
};
}, [successMessage]);
The sexy
word should only get console logged once.
Figured it out based on their documentation: https://jestjs.io/docs/timer-mocks , you can just do the following:
expect(setTimeout).not.toHaveBeenCalled();
And when you want to check that it got called once, you can do:
expect(setTimeout).toHaveBeenCalledTimes(1);
Note: This is testing an implementation detail, so be aware of that.