Тестирование промисов

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

Основы работы с промисами

Промисы в JavaScript представляют собой объекты, которые асинхронно возвращают результат выполнения операции. В Jest тестирование промисов требует особого внимания, поскольку тесты должны правильно обрабатывать асинхронные операции.

Jest позволяет тестировать асинхронные функции с помощью таких методов, как resolves, rejects, async/await, а также возможности работы с таймерами.

Тестирование промиса с использованием resolves и rejects

Jest предоставляет специальные матчеры resolves и rejects, которые позволяют упростить проверку результатов промисов.

Проверка успешного выполнения промиса

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

Пример:

test('проверка успешного выполнения промиса', () => {
  const promise = Promise.resolve('успех');
  return expect(promise).resolves.toBe('успех');
});

В этом примере промис разрешается значением “успех”, и тест проверяет, что результат выполнения промиса соответствует ожидаемому значению.

Проверка неудачного выполнения промиса

Если промис должен быть отклонен с ошибкой, используется матчар rejects.

Пример:

test('проверка отклонения промиса', () => {
  const promise = Promise.reject(new Error('ошибка'));
  return expect(promise).rejects.toThrow('ошибка');
});

Здесь промис отклоняется с ошибкой, и тест проверяет, что ошибка соответствует ожидаемой.

Использование async/await для тестирования промисов

Использование синтаксиса async/await позволяет значительно упростить работу с асинхронными функциями. Вместо того чтобы явно указывать return в тестах, можно использовать await для ожидания выполнения промиса и проверки результата.

Пример:

test('проверка успешного выполнения промиса с async/await', async () => {
  const result = await Promise.resolve('успех');
  expect(result).toBe('успех');
});

В этом случае использование await позволяет ожидать результат промиса и затем проверять его через expect.

Таймеры и асинхронные операции

Иногда в тестах требуется работать с таймерами или асинхронными операциями, которые выполняются через задержку. Jest предоставляет встроенные методы для работы с таймерами — jest.useFakeTimers() и jest.advanceTimersByTime(). Они позволяют управлять временем в тестах, не дожидаясь реальных задержек.

Пример с использованием таймеров:

test('проверка работы с таймерами', () => {
  jest.useFakeTimers();

  const mockCallback = jest.fn();
  setTimeout(() => mockCallback('выполнено'), 1000);

  jest.advanceTimersByTime(1000);

  expect(mockCallback).toHaveBeenCalledWith('выполнено');
});

В этом примере используется функция jest.useFakeTimers(), которая позволяет управлять временем в тестах. С помощью jest.advanceTimersByTime() можно “перемотать” время на заданное количество миллисекунд и проверить, что колбэк был вызван.

Параллельное выполнение нескольких промисов

В случае, когда тестируемая функция работает с несколькими промисами, Jest позволяет удобно тестировать их выполнение параллельно. Например, можно использовать Promise.all для проверки нескольких промисов одновременно.

Пример:

test('параллельное выполнение промисов', async () => {
  const promise1 = Promise.resolve('результат 1');
  const promise2 = Promise.resolve('результат 2');
  
  const results = await Promise.all([promise1, promise2]);
  
  expect(results).toEqual(['результат 1', 'результат 2']);
});

Здесь оба промиса выполняются параллельно, и тест проверяет, что оба промиса разрешаются с правильными значениями.

Обработка ошибок в асинхронных тестах

Когда в асинхронном коде может возникнуть ошибка, важно корректно ее обработать. В Jest ошибки, возникающие в промисах, можно обрабатывать с помощью try/catch.

Пример:

test('обработка ошибки в промисе', async () => {
  try {
    await Promise.reject(new Error('ошибка'));
  } catch (e) {
    expect(e).toEqual(new Error('ошибка'));
  }
});

Здесь мы используем try/catch для того, чтобы поймать ошибку, отклоненную промисом, и проверить, что она соответствует ожидаемой.

Комбинированное использование матчеров и асинхронных операций

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

Пример:

test('комбинированное тестирование успешных и неудачных промисов', async () => {
  const successPromise = Promise.resolve('успех');
  const failurePromise = Promise.reject(new Error('ошибка'));

  await expect(successPromise).resolves.toBe('успех');
  await expect(failurePromise).rejects.toThrow('ошибка');
});

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

Советы по тестированию промисов

  1. Чистота тестов: При тестировании асинхронного кода важно, чтобы каждый тест был независимым и не влиял на другие. Поэтому рекомендуется использовать методы очистки, такие как jest.clearAllMocks(), для сброса состояния между тестами.

  2. Не используйте done() без необходимости: В Jest можно использовать коллбек done() для асинхронных тестов, но в большинстве случаев лучше использовать async/await, так как это делает код более читаемым и упрощает управление асинхронностью.

  3. Ожидайте результата до конца: Использование await гарантирует, что тест завершится только после выполнения всех асинхронных операций, что помогает избежать ошибок, связанных с не до конца выполненными промисами.

  4. Обработка ошибок: Всегда учитывайте, что промисы могут быть отклонены. Тесты, которые не проверяют ошибки, могут пропустить важные исключения.

Тестирование промисов в Jest предоставляет гибкие и удобные инструменты для проверки асинхронных функций, что делает процесс тестирования более эффективным и надежным.