Spec-Zone.ru › Jest

Тестирование асинхронного кода

В JavaScript часто встречается асинхронный код. Когда у вас есть асинхронный код, Jest должен знать, когда тестируемый код завершен, прежде чем перейти к другому тесту. Jest предоставляет несколько способов для этого.

Обещания

Возвращайте promise из вашего теста, и Jest будет ждать, пока это обещание не разрешится. Если обещание отклоняется, тест завершится с ошибкой.

Например, предположим, что fetchData возвращает обещание, которое должно разрешиться до строки 'peanut butter'. Мы можем протестировать это так:

test('the data is peanut butter', () => {
  return fetchData().then(data => {
    expect(data).toBe('peanut butter');
  });
});

Async/Await

В качестве альтернативы, вы можете использовать async и await в своих тестах. Для написания асинхронного теста используйте ключевое слово async перед функцией, переданной в test. Например, тот же сценарий fetchData может быть протестирован так:

test('the data is peanut butter', async () => {
  const data = await fetchData();
  expect(data).toBe('peanut butter');
});

test('the fetch fails with an error', async () => {
  expect.assertions(1);
  try {
    await fetchData();
  } catch (e) {
    expect(e).toMatch('error');
  }
});

Вы можете комбинировать async и await с .resolves или .rejects.

test('the data is peanut butter', async () => {
  await expect(fetchData()).resolves.toBe('peanut butter');
});

test('the fetch fails with an error', async () => {
  await expect(fetchData()).rejects.toMatch('error');
});

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

внимание

Убедитесь, что вы возвращаете (или await ) обещание — если вы опустите инструкцию return/await, ваш тест завершится до того, как обещание, возвращаемое из fetchData, разрешится или отклонится.

Если вы ожидаете, что обещание будет отклонено, используйте метод .catch. Убедитесь, что добавлено expect.assertions, чтобы проверить, что определенное количество утверждений вызваны. В противном случае выполненное обещание не приведет к сбою теста.

test('the fetch fails with an error', () => {
  expect.assertions(1);
  return fetchData().catch(e => expect(e).toMatch('error'));
});

Обратные вызовы

Если вы не используете обещания, вы можете использовать обратные вызовы. Например, предположим, что fetchData, вместо возвращения обещания, ожидает обратный вызов, т.е. извлекает некоторые данные и вызывает callback(null, data), когда задача завершена. Вы хотите проверить, что эти возвращаемые данные — это строка 'peanut butter'.

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

// Don't do this!
test('the data is peanut butter', () => {
  function callback(error, data) {
    if (error) {
      throw error;
    }
    expect(data).toBe('peanut butter');
  }

  fetchData(callback);
});

Проблема в том, что тест завершится сразу после завершения fetchData, до вызова обратного вызова.

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

test('the data is peanut butter', done => {
  function callback(error, data) {
    if (error) {
      done(error);
      return;
    }
    try {
      expect(data).toBe('peanut butter');
      done();
    } catch (error) {
      done(error);
    }
  }

  fetchData(callback);
});

Если done() никогда не вызывается, тест завершится с ошибкой (с ошибкой тайм-аута), что и должно произойти.

Если инструкция expect завершается с ошибкой, она генерирует ошибку, и done() не вызывается. Если мы хотим увидеть в журнале теста, почему произошла ошибка, мы должны обернуть expect в блок try и передать ошибку в блок catch в done. В противном случае мы получим неясную ошибку тайм-аута, которая не показывает, какое значение было получено expect(data).

Примечание: done() не следует смешивать с обещаниями, так как это может привести к утечкам памяти в ваших тестах.

.resolves / .rejects

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

test('the data is peanut butter', () => {
  return expect(fetchData()).resolves.toBe('peanut butter');
});

Убедитесь, что возвращаете утверждение — если вы опустите эту return инструкцию, ваш тест завершится до того, как обещание, возвращенное из fetchData, будет разрешено, и then() не будет иметь возможности выполнить обратный вызов.

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

test('the fetch fails with an error', () => {
  return expect(fetchData()).rejects.toMatch('error');
});

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

© 2022 Facebook, Inc.
Licensed under the MIT License.
https://jestjs.io/docs/asynchronous

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API