В JavaScript closures (замыкания) представляют собой функцию, которая имеет доступ к переменным из своей внешней области видимости даже после того, как эта область завершила выполнение. В контексте Cypress это особенно важно, так как тесты часто строятся на цепочках асинхронных команд, и понимание того, какие значения доступны в момент выполнения кода, критично для корректного написания сценариев.
Замыкание возникает, когда внутренняя функция «помнит» окружение внешней функции. Пример:
function createCounter() {
let count = 0;
return function() {
count += 1;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
Переменная count продолжает существовать в памяти
благодаря замыканию. В Cypress подобная концепция проявляется при работе
с переменными внутри cy.then() или колбэков в командах, где
значение должно сохраняться между асинхронными вызовами.
Cypress использует цепочки команд, каждая из которых асинхронна. Важно понимать, что:
cy.get().then()) — локальны для этого колбэка, но могут
использоваться через замыкания.this в тестах Mocha (используемых Cypress) ссылается на
контекст теста, что позволяет хранить значения между хуками
before, beforeEach, it и
after.Пример использования this и замыканий:
describe('Пример замыканий с Cypress', function() {
before(function() {
this.token = null;
});
it('Получение токена', function() {
cy.request('POST', '/api/login', { username: 'user', password: 'pass' })
.then((response) => {
this.token = response.body.token; // Сохраняем в контексте
});
});
it('Использование токена', function() {
cy.request({
method: 'GET',
url: '/api/data',
headers: { Authorization: `Bearer ${this.token}` } // Используем замыкание
}).then((response) => {
expect(response.status).to.eq(200);
});
});
});
Здесь this.token хранит значение между тестами благодаря
механизму контекста Mocha и замыканиям.
Cypress не поддерживает прямое присваивание результатов асинхронных команд обычным переменным вне замыканий. Например, код:
let value;
cy.get('#input').type('text').then(() => {
value = 'текст';
});
console.log(value); // undefined
вернёт undefined, так как console.log
выполняется раньше, чем Cypress завершит команду
cy.get().type(). Решение — использовать then
или замыкания:
cy.get('#input').type('text').then(() => {
const value = 'текст';
cy.log(value); // корректное использование внутри замыкания
});
Иногда возникает необходимость хранить значения из нескольких
асинхронных вызовов для дальнейшей проверки. В Cypress это делается
через cy.wrap() и then():
cy.get('.item').then(($items) => {
const texts = [];
$items.each((index, el) => texts.push(el.innerText));
cy.wrap(texts).as('textsArray'); // сохраняем в алиас
});
cy.get('@textsArray').then((texts) => {
expect(texts).to.include('Нужный элемент');
});
Использование алиасов и cy.wrap создаёт собственное
замыкание, в котором данные безопасно передаются между асинхронными
шагами.
this внутри стрелочных функций в
Mocha приведёт к потере контекста, так как стрелочные функции наследуют
this из внешнего лексического окружения.then() или замыканий не работает, из-за асинхронного
характера Cypress.forEach с
Cypress-командами. Это не работает корректно, лучше использовать
cy.wrap(array).each() для соблюдения цепочек и
замыканий.then() для работы с результатами команд и
локальных переменных.this).cy.wrap().each(), чтобы сохранить асинхронность и избежать
утечек переменных.this контекста теста.Понимание замыканий и контекста позволяет писать надёжные Cypress-тесты, избегать неожиданных ошибок с асинхронными данными и строить сложные цепочки проверок без потери значений между шагами.