Тестирование функции, которая использует setTimeout с Jest: почему этот тест не проходит? - PullRequest
2 голосов
/ 27 марта 2019

У меня есть функция rateLimit (это просто модифицированная версия этого кода ):

function rateLimit(func, wait) {
    var timeout;
    return function () {
        var context = this;
        var args = arguments;
        var later = function () {
            timeout = null;
            func.apply(context, args);
        };
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
    };
}

Эта функция прекрасно работает в моем приложении, поэтому я вполне уверен, что реализация в порядке. Однако следующий тест не пройден:

jest.useFakeTimers();

test('rateLimit', () => {
    const action = jest.fn();

    const doAction = rateLimit(action, 100);

    doAction(); // This should increment the call count
    doAction(); // This shouldn't, because 100ms hasn't elapsed yet

    jest.advanceTimersByTime(101);

    doAction(); // This should increment the count again

    expect(action).toHaveBeenCalledTimes(2);
});

С ошибкой:

Expected mock function to have been called two times, but it was called one time.

Вот исполняемая версия этого кода на repl.it .

Что я здесь не так делаю?

Ответы [ 2 ]

3 голосов
/ 27 марта 2019

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

Вы простонеобходимо снова включить таймеры, чтобы снова вызвать функцию:

jest.useFakeTimers();

test('rateLimit', () => {
    const action = jest.fn();

    const doAction = rateLimit(action, 100);

    doAction(); // This should increment the call count
    doAction(); // This shouldn't, because 100ms hasn't elapsed yet

    jest.advanceTimersByTime(101);

    doAction(); // This should increment the count again

    jest.advanceTimersByTime(101);  // <= advance the timers again

    expect(action).toHaveBeenCalledTimes(2);  // Success!
});
0 голосов
/ 27 марта 2019

Вы должны использовать второй вызов для срабатывания таймеров:

Подробнее здесь

test('rateLimit', () => {
  const action = jest.fn();

  const doAction = rateLimit(action, 100);

  doAction(); // This should increment the call count
  doAction(); // This shouldn't, because 100ms hasn't elapsed yet

  jest.runAllTimers();

  doAction(); // This should increment the count again

  jest.runAllTimers();

  expect(action).toHaveBeenCalledTimes(2);
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...