Возврат Promise из тестов

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

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

Когда функция теста возвращает промис, Jasmine автоматически ожидает его разрешения или отклонения. Это устраняет необходимость вручную вызывать done() и упрощает написание асинхронных проверок.

Пример базового теста с промисом:

it('должен получить данные с сервера', function() {
    return fetchData().then(function(data) {
        expect(data).toBeDefined();
        expect(data.length).toBeGreaterThan(0);
    });
});

В этом примере:

  • fetchData() возвращает промис.
  • Тест не завершится, пока промис не разрешится.
  • Если промис отклоняется, тест автоматически считается провалившимся.

Использование async/await

С введением async/await синтаксис становится более читаемым, сохраняя возможность возврата промиса:

it('должен корректно обработать асинхронный запрос', async function() {
    const data = await fetchData();
    expect(data).toBeDefined();
    expect(data.length).toBeGreaterThan(0);
});

Важно отметить:

  • Jasmine корректно обрабатывает async функции.
  • await позволяет писать асинхронный код линейно, без цепочек .then().

Ошибки и исключения

Если промис отклоняется, Jasmine автоматически фиксирует ошибку теста. Можно дополнительно проверять отлов исключений с помощью expectAsync:

it('должен выбросить ошибку при некорректных данных', async function() {
    await expectAsync(fetchData('invalid')).toBeRejected();
});

Ключевые методы expectAsync:

  • toBeResolved(): промис успешно разрешился.
  • toBeRejected(): промис отклонён.
  • toBeResolvedTo(value): промис разрешился с конкретным значением.
  • toBeRejectedWith(error): промис отклонён с конкретной ошибкой.

Совмещение с beforeEach и afterEach

Асинхронные операции часто выполняются в хуках beforeEach и afterEach. Для работы с промисами они также могут возвращать промис:

beforeEach(function() {
    return initializeDatabase();
});

afterEach(function() {
    return cleanupDatabase();
});

Или с async/await:

beforeEach(async function() {
    await initializeDatabase();
});

afterEach(async function() {
    await cleanupDatabase();
});

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

Важные нюансы

  1. Не смешивать done и возврат промиса. Либо использовать done, либо возвращать промис/async функцию, иначе поведение теста может быть непредсказуемым.
  2. Цепочки промисов должны быть корректно возвращены. Пример неправильного варианта:
it('неправильный пример', function() {
    fetchData().then(function(data) {
        expect(data).toBeDefined();
    });
});

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

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

it('правильный пример', function() {
    return fetchData().then(function(data) {
        expect(data).toBeDefined();
    });
});
  1. Асинхронные проверки внутри циклов требуют аккуратного использования Promise.all или for...of с await, чтобы Jasmine корректно дождался всех операций.

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

Когда промисы зависят от таймеров (setTimeout), Jasmine предоставляет возможность управления временем через jasmine.clock(). В сочетании с возвратом промиса это позволяет синхронно тестировать асинхронное поведение:

it('должен дождаться таймера', function() {
    jasmine.clock().install();

    const promise = new Promise(resolve => setTimeout(() => resolve('done'), 1000));

    jasmine.clock().tick(1000);

    return promise.then(result => {
        expect(result).toBe('done');
    }).finally(() => jasmine.clock().uninstall());
});

Рекомендации по организации тестов с промисами

  • Использовать async/await для повышения читаемости.
  • Отдавать предпочтение expectAsync для проверки отклонённых промисов.
  • Возвращать промисы из всех асинхронных хуков (beforeEach, afterEach).
  • Избегать смешения done и промисов.
  • Следить за корректным завершением всех цепочек промисов, чтобы исключить ложные срабатывания.

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