В тестировании на JavaScript важно обеспечивать изолированность тестов. Каждый тест должен выполняться в предсказуемой среде, не зависящей от изменений, внесённых другими тестами. Jasmine предоставляет для этого встроенные механизмы — хуки, позволяющие подготовить и очистить состояние перед или после выполнения тестов.
beforeEach и
afterEachbeforeEach выполняется перед каждым
тестом (it) внутри блока describe. Обычно
используется для подготовки состояния: инициализации объектов, создания
мока, очистки коллекций.
describe('Работа с массивом', () => {
let items;
beforeEach(() => {
items = [];
});
it('добавляет элемент в массив', () => {
items.push('apple');
expect(items.length).toBe(1);
});
it('начинается с пустого массива', () => {
expect(items.length).toBe(0);
});
});
В примере массив items создаётся заново перед каждым
тестом. Даже если первый тест что-то добавил, второй тест начнёт с
чистого состояния.
afterEach используется для действий
после выполнения теста. Обычно это освобождение ресурсов, сброс
глобальных переменных или очистка DOM.
describe('Манипуляции с DOM', () => {
let container;
beforeEach(() => {
container = document.createElement('div');
document.body.appendChild(container);
});
afterEach(() => {
document.body.removeChild(container);
container = null;
});
it('вставляет элемент в контейнер', () => {
const child = document.createElement('span');
container.appendChild(child);
expect(container.children.length).toBe(1);
});
});
Использование afterEach гарантирует, что DOM не
будет загрязнён предыдущими тестами, что критично при
тестировании фронтенда.
Jasmine поддерживает вложенные блоки
describe, и хуки работают с учётом иерархии:
describe('Внешний блок', () => {
beforeEach(() => console.log('Внешний beforeEach'));
describe('Внутренний блок', () => {
beforeEach(() => console.log('Внутренний beforeEach'));
it('тест', () => {});
});
});
Последовательность вызова:
beforeEachbeforeEachitafterEachafterEachЭта модель позволяет строить сложные сценарии подготовки и очистки, минимизируя дублирование кода.
В тестах с промисами, таймерами или асинхронными операциями важно
корректно очищать состояние после завершения асинхронных действий.
beforeEach и afterEach поддерживают
колбэк done или возврат промиса.
describe('Асинхронная работа', () => {
let value;
beforeEach((done) => {
setTimeout(() => {
value = 42;
done();
}, 100);
});
afterEach(() => {
value = null;
});
it('значение установлено асинхронно', () => {
expect(value).toBe(42);
});
});
Если используется async/await, хуки могут быть
асинхронными функциями:
beforeEach(async () => {
value = await fetchData();
});
Это обеспечивает надёжную очистку и инициализацию, даже при сложной асинхронной логике.
Иногда тесты модифицируют глобальные объекты, например
window, localStorage или конфигурации
библиотек. В таких случаях важно восстанавливать исходное
состояние, чтобы другие тесты не ломались.
describe('Изменение глобальных настроек', () => {
let originalTimeout;
beforeEach(() => {
originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
});
afterEach(() => {
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
});
it('тест с изменённым таймаутом', () => {
expect(jasmine.DEFAULT_TIMEOUT_INTERVAL).toBe(5000);
});
});
Без afterEach изменение таймаута повлияло бы на все
последующие тесты.
beforeEach.afterEach для сложных объектов и
ресурсов: DOM, таймеры, подписки на события.done для гарантии корректного завершения.Использование этих подходов обеспечивает надёжность и предсказуемость тестов, предотвращает трудноуловимые ошибки и делает код тестов чистым и поддерживаемым.