Запустить фоновую задачу внутри Jest

avatar
sphoenix
1 июля 2021 в 17:14
234
1
0

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

test('Some potato poteto test', () => {
    jest.setTimeout(12000000); // 20 min

    const intervalPeriod = 5 * 60 * 1000; // 5 min

    let retry = 0;

    const intervalId = setInterval(() => {
      console.log("I am doing my 5 minutes check");
      
      // my custom logic goes here

      retry++;
  
      if(retry === MAX_RETRY) { // this will be always hit
        clearInterval(intervalId)
      }
    }, intervalPeriod);
});

Итак, каждые 5 минут я буду звонить по сети, выполняя какую-то свою собственную логику. Теперь проблема в том, что во время выполнения тест завершен, но jest не может завершиться.

Под "тестирование завершено" я имел в виду, что набор тестов запущен, но код внутри setInterval не выполняется сразу.

Мой вопрос: это происходит из-за того, что setInterval не запускается немедленно в цикле событий и jest не настроен для запуска setInterval?

Обратите внимание, что я не хочу издеваться над setInterval, а также не хочу использовать фальшивый таймер.

Поэтому возможно ли добиться этого с помощью Jest?

Я пробовал то же самое с библиотекой cron для узла, но проблема та же. Jest не выполняет код и завершает выполнение, а затем останавливается, поскольку эти setInterval/cron все еще работают в фоновом режиме.

Есть ли способ запустить эти задачи внутри Jest? Я имею в виду, есть ли способ запустить эти задания и, когда они будут выполнены, завершить работу Jest?

Источник
Noriller
1 июля 2021 в 17:48
0

useFakeTimers - это то, что нужно... но если вы действительно этого не хотите... есть флаг --maxWorkers, который охватывает воркеров на основе ядер вашей машины... один только этот тест потребляет все ядро ​​​​в течение 5 минут. ... так что... может быть, вы могли бы сделать этот тест как нечто отдельное? (например, запускать только тогда, когда вы делаете что-то вроде test:thatone, который занимает 5 минут)

Ответы (1)

avatar
devdgehog
1 июля 2021 в 19:02
0

Это и было задумано, Jest выполнил все инструкции теста и вышел из теста.

Чтобы jest ждал вычисления, вам нужно использовать Promises и его асинхронный режим.

Документ для асинхронного режима Jest: https://jestjs.io/docs/asynchronous

Узнайте больше об обещаниях здесь: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

Асинхронный/ожидающий синтаксис здесь: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

Это наивный способ сделать это:

const MAX_RETRY = 3;
const INTERVAL_PERIOD = 5 * 60 * 1000; // 5 min
const SAFETY_TIME = INTERVAL_PERIOD;
const TEST_TIMEOUT = (1 + MAX_RETRY) * INTERVAL_PERIOD + SAFETY_TIME; 

test('Some potato poteto test', async () => {
    let retry = 0;
    let success = false;
    function yourLogicFunction(): boolean {
        const resultOfYourLogicFunction = retry === MAX_RETRY; // because retry is used in this condition I store the result before changing it
        console.log(`this is my attempt number ${retry}`);
        retry++;
        return resultOfYourLogicFunction;
    }
    function mockRequest(resolve: (value: unknown) => void): void {
        setTimeout(() => resolve(yourLogicFunction()), INTERVAL_PERIOD);
    }
    while (!success && retry <= MAX_RETRY) {
        success = await new Promise(mockRequest) as boolean;
    }
}, TEST_TIMEOUT);

Третий параметр теста — время ожидания.