Миграция с Jasmine 2.x на 3.x

Введение в Jasmine 3.x

Jasmine — это популярная библиотека для тестирования JavaScript, используемая для написания юнит-тестов. С выходом Jasmine 3.x были внесены несколько изменений, улучшений и изменений в API, которые могут потребовать корректировок в уже существующих проектах, использующих версию 2.x. Понимание этих изменений и правильная миграция к новой версии обеспечат стабильную работу тестов и улучшенную производительность тестирования.

Основные изменения между Jasmine 2.x и 3.x

1. Удаление поддержки beforeEach/afterEach для асинхронных операций через done()

В Jasmine 3.x была введена поддержка асинхронности через async и await, что позволило отказаться от использования колбека done() в beforeEach и afterEach для асинхронных операций. В Jasmine 2.x использование done() для асинхронных операций в этих хуках было обязательным, но начиная с версии 3.x это больше не требуется.

Пример старого кода (Jasmine 2.x):

beforeEach(function(done) {
  setTimeout(function() {
    // Асинхронная операция
    done();
  }, 1000);
});

Пример кода для Jasmine 3.x:

beforeEach(async () => {
  await new Promise(resolve => setTimeout(resolve, 1000));
});

2. Удаление toThrowError с параметром в виде регулярного выражения

В Jasmine 3.x был удален устаревший механизм использования регулярных выражений в toThrowError. Вместо этого рекомендуется использовать строковое представление ошибки или класс ошибки.

Пример старого кода (Jasmine 2.x):

expect(() => { throw new Error('Test Error') }).toThrowError(/Test/);

Пример кода для Jasmine 3.x:

expect(() => { throw new Error('Test Error') }).toThrowError('Test Error');

3. Изменения в spyOn

В Jasmine 3.x появилась возможность работать с объектами, используя spyOn и проверку на аргументы метода. В версии 2.x не было поддержки проверки за пределами вызова методов через spyOn, что значительно улучшилось в версии 3.x. Теперь можно использовать дополнительные проверки на вызов функций.

Пример старого кода (Jasmine 2.x):

let obj = {
  foo: function() {
    return 'bar';
  }
};

spyOn(obj, 'foo');
obj.foo();
expect(obj.foo).toHaveBeenCalled();

Пример кода для Jasmine 3.x:

let obj = {
  foo: function() {
    return 'bar';
  }
};

spyOn(obj, 'foo').and.callThrough();
obj.foo();
expect(obj.foo).toHaveBeenCalled();

4. Улучшение поддержки работы с таймерами

В Jasmine 3.x значительно улучшена работа с таймерами, например, с функциями setTimeout и setInterval. В новой версии добавлены дополнительные утилиты, позволяющие более гибко и точно контролировать асинхронные таймеры в тестах.

Вместо использования jasmine.clock() для манипуляций с таймерами, теперь можно использовать jasmine.clock().install() и jasmine.clock().uninstall(), чтобы правильно управлять таймерами в тестах.

Пример старого кода (Jasmine 2.x):

beforeEach(function() {
  jasmine.clock().install();
});

afterEach(function() {
  jasmine.clock().uninstall();
});

it('ждет 1000ms', function() {
  setTimeout(function() {
    expect(true).toBe(true);
  }, 1000);
  jasmine.clock().tick(1000);
});

Пример кода для Jasmine 3.x:

beforeEach(function() {
  jasmine.clock().install();
});

afterEach(function() {
  jasmine.clock().uninstall();
});

it('ждет 1000ms', async function() {
  setTimeout(() => {
    expect(true).toBe(true);
  }, 1000);
  jasmine.clock().tick(1000);
});

5. Преобразование done() в async/await

В Jasmine 3.x появился более современный и удобный способ работы с асинхронными операциями через async/await. Это позволяет упростить код, сделать его более читаемым и избавить от необходимости вручную вызывать done() в тестах.

Пример старого кода (Jasmine 2.x):

it('тестирует асинхронную операцию', function(done) {
  someAsyncFunction(function(result) {
    expect(result).toBe(true);
    done();
  });
});

Пример кода для Jasmine 3.x:

it('тестирует асинхронную операцию', async function() {
  const result = await someAsyncFunction();
  expect(result).toBe(true);
});

6. Изменение в использовании fit и xit

В Jasmine 2.x использовались fit и xit для изолированного тестирования отдельных тестов. В Jasmine 3.x эта практика остается, но следует помнить, что использование этих методов ограничивает выполнение других тестов, что может повлиять на результаты тестирования. Кроме того, fit и xit могут быть полезными в процессе разработки, но должны быть удалены перед деплоем.

7. Поддержка Jest-style matcher API

Jasmine 3.x добавил поддержку Jest-style matcher API, что дает возможность использовать новые возможности для сравнения объектов и структур данных. Это позволяет тестировать более сложные структуры, такие как массивы и объекты, с меньшими усилиями.

Пример старого кода (Jasmine 2.x):

expect({ foo: 'bar' }).toEqual(jasmine.objectContaining({ foo: 'bar' }));

Пример кода для Jasmine 3.x:

expect({ foo: 'bar' }).toEqual(expect.objectContaining({ foo: 'bar' }));

8. Поддержка нового синтаксиса beforeAll и afterAll

С выходом Jasmine 3.x также была улучшена поддержка методов beforeAll и afterAll, которые позволяют выполнять действия до и после всех тестов в спецификации. Это особенно полезно для инициализации тестового окружения или очистки ресурсов, занимающих много времени.

Пример кода для Jasmine 3.x:

beforeAll(async () => {
  await setupTestEnvironment();
});

afterAll(async () => {
  await cleanupTestEnvironment();
});

it('тестирует что-то', function() {
  expect(true).toBe(true);
});

Заключение

Миграция с Jasmine 2.x на Jasmine 3.x требует внимательного подхода, особенно в части асинхронных операций и работы с методами spyOn, таймерами и матчерами. Большая часть изменений связана с улучшением асинхронной работы и упрощением синтаксиса тестирования. Понимание этих изменений и их внедрение позволит сделать тесты более стабильными, читаемыми и эффективными.