Тестирование setInterval () с sinon.fakeTimers не работает?

У меня есть действие в моем componentDidMount, которое извлекает изображения из Reddit через 30000 мс. Я хочу проверить это, но не могу понять?!?! Какие-либо предложения?

    componentDidMount() {
       this.getHumorEvery(30000)
    }

    getHumorEvery = async (ms) => {
        await this.props.getHumor()

        return setInterval(() => {
            this.props.getHumor()
    }, ms)

Так что getHumor () получает вызов немедленно. Затем через 30000 мс он снова вызывается и так далее.

Тогда мой тест ...

it('should refetch images every 30000 ms', () => {
    const clock = sinon.useFakeTimers();
    const getHumorSpy = sinon.spy();

    renderComponent(requiredProps({ getHumor: getHumorSpy }));
    clock.tick(30000)

    sinon.assert.calledTwice(getHumorSpy)

})

Тест не пройден, потому что getHumor вызывается только один раз. SetInterval () никогда не запускается?

Вызывается ли когда-либо ваш обратный вызов setInterval? Если да, то определен ли this.props.getHumor внутри обратного вызова, и уверены ли вы, что это шпион sinon?

Alan Friedman 27.07.2018 03:36

Да, если вы console.info (setInterval) прямо перед вызовом setInterval, а затем поместите другой console.info () в setTimeout, а затем запустите тесты, результат будет .... 1) setInterval выводит заглушенный setInterval 2) console.info () внутри setInterval никогда не выходит из системы Таким образом, кажется, что да, setInterval заглушен правильно, но все же он никогда не вызывает setInerval ()

Andrew Schubert 27.07.2018 16:23

Пробовали ставить галочку на что-то выше, например 40000?

Alan Friedman 27.07.2018 17:46

Я сделал .. Я пробовал несколько раз.

Andrew Schubert 27.07.2018 17:47

Зачем нужен async/await в getHumorEvery()? Думаю, причина в этом.

Yonggoo Noh 28.07.2018 16:09
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
5
1 522
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вызов затем на обещаниях и вызов await в асинхронной функции ставит в очередь код для цикла событий, который не выполняется до тех пор, пока не завершится текущий синхронный код и не отсчитываются часы. Точно так же setTimeout обычно добавляет код в очередь, который также должен ждать следующего такта часов.

Поддельные таймеры Sinon «являются синхронными реализациями setTimeout и друзей», которые «перезаписывают глобальные функции» и управляют кодом, поставленным в очередь с setTimeout и подобными глобальными переменными, и вызывают его синхронно, когда тикают смоделированные часы.

Это разъединение между кодом, который все еще находится в очереди для цикла событий, и кодом, который ранее был поставлен в очередь для цикла событий, но теперь вызывается синхронно, может вызвать проблемы (например, это и это).

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

В этом случае превращение теста в асинхронную функцию и вызов await для разрешенного обещания дает ожидающему коду в очереди возможность запускаться до синхронного тика часов, что позволяет коду вести себя так, как ожидалось, и правильно утверждать:

it('should refetch images every 30000 ms', async () => {
    const clock = sinon.useFakeTimers();
    const getHumorSpy = sinon.spy();

    renderComponent(requiredProps({ getHumor: getHumorSpy }));

    // let event loop cycle
    await Promise.resolve();

    clock.tick(30000);
    sinon.assert.calledTwice(getHumorSpy);
})

Я бы попытался заменить clock.tick на clock.tickAsync и избежать лишнего await Promise.resolve();

Dudi 18.05.2020 14:45

Другие вопросы по теме