localStorage.setItem
вызывается асинхронно через .then
login = () => {
apiRequest.then(res => {
localStorage.setItem('token', res.token);
});
}
Так что насмешка не может помочь с асинхронным потоком.Эта небольшая часть
.then(res => {
localStorage.setItem('token', res.token);
}
просто помещается в конец очереди (она называется очередь микрозадач , если вас интересуют подробности)
Итак, ваш тестовый код завершени только после этого выполняется эта небольшая микрозадача.
Как вы справитесь с этим?Вы можете написать тест по асинхронному способу и поместить дополнительную expect
в выделенную микрозадачу, которая будет запускаться после тех, что с вызовом localStorage.setItem
.
Вы можете использовать setTimeout
(макрозадачу) для этого:
it('sets a token in local storage', done => {
const { getByText } = renderLogin();
const loginButton = getByText(/login/i);
expect(apiRequest).toBeCalledTimes(1);
setTimeout(() => {
// runs after then(....setItem) has been called
expect(localStorage.setItem).toBeCalledWith('token');
done();
}, 0);
});
или создайте микрозадачу с Promise / async / await:
it('sets a token in local storage', async () => {
const { getByText } = renderLogin();
const loginButton = getByText(/login/i);
expect(apiRequest).toBeCalledTimes(1);
await Promise.resolve(); // everything below goes into separate microtask
expect(localStorage.setItem).toBeCalledWith('token');
});
[UPD] интересная вещь о await
, которую можно использовать со всем остальным, не только с Promise.И это может работать как Promise.resolve(<some value here>)
.Так что в вашем случае
it('sets a token in local storage', async () => {
const { getByText } = renderLogin();
const loginButton = getByText(/login/i);
await expect(apiRequest).toBeCalledTimes(1);
expect(localStorage.setItem).toBeCalledWith('token');
});
также будет работать.Но я полагаю, что это выглядит запутанным («ваааат? .toHaveBeenCalled()
возвращает обещание по-настоящему ?!») и подозрительным (это волшебство! Мне не разрешают это трогать!).Так что лучше выбрать версию с простой «отсрочкой»