Cypress использует асинхронный подход к выполнению команд, что
напрямую влияет на работу с переменными. В отличие от синхронного
JavaScript, где значение переменной можно присвоить и сразу
использовать, в Cypress прямое присваивание значений из команд, таких
как cy.get() или cy.request(), часто приводит
к неожиданным результатам.
Пример ошибки:
let text;
cy.get('h1').then($el => {
text = $el.text();
});
cy.log(text); // Выведет undefined
Это происходит потому, что cy.get() и другие команды
Cypress выполняются асинхронно в цепочке команд, а присвоение
text = $el.text() происходит после того, как
cy.log(text) уже был вызван.
.then() для работы с переменнымиПравильный способ сохранить и использовать данные — использовать
цепочку .then(), которая обеспечивает доступ к значению
после выполнения команды:
cy.get('h1').then($el => {
const text = $el.text();
cy.log(text); // Выведет корректное значение
});
В этом случае переменная text доступна только внутри
функции .then(). Для дальнейшего использования данных в
последующих командах можно передавать их через возвращаемое значение или
использовать замыкания.
cy.wrap()Для сохранения данных и их последующего использования в разных частях
теста применяются алиасы через .as() и
cy.get('@alias'):
cy.get('input[name="username"]').type('admin').as('usernameInput');
cy.get('@usernameInput').should('have.value', 'admin');
Алиасы особенно удобны для работы с объектами и элементами DOM, которые используются несколько раз в тесте.
Если требуется сохранить простое значение (например, текст или
число), используется cy.wrap():
cy.get('h1').then($el => {
cy.wrap($el.text()).as('headerText');
});
cy.get('@headerText').then(text => {
cy.log('Текст заголовка: ' + text);
});
cy.wrap() позволяет превратить обычное значение в
Cypress chainable, что обеспечивает корректное асинхронное
выполнение.
Переменные можно определять в пределах describe или
it. При этом важно помнить, что простое присваивание вне
цепочки команд не синхронизируется с Cypress:
describe('Тест с переменными', () => {
let token;
it('Получение токена', () => {
cy.request('POST', '/api/login', { user: 'admin', pass: '123' })
.then(response => {
token = response.body.token;
});
});
it('Использование токена', () => {
cy.request({
method: 'GET',
url: '/api/data',
headers: { Authorization: `Bearer ${token}` }
}).then(response => {
expect(response.status).to.eq(200);
});
});
});
Такой код может привести к проблемам, если Cypress выполнит второй
it до завершения первого. Для передачи данных между тестами
рекомендуется использовать алиасы или ссылку на
Cypress.env:
cy.request('POST', '/api/login', { user: 'admin', pass: '123' })
.then(response => {
Cypress.env('token', response.body.token);
});
cy.request({
method: 'GET',
url: '/api/data',
headers: { Authorization: `Bearer ${Cypress.env('token')}` }
});
Использование Cypress.env() гарантирует корректную
доступность значения на протяжении всего тестового набора.
it и доступны только в рамках этого блока.describe и могут использоваться в нескольких
it. Но их присвоение должно быть аккуратным из-за
асинхронного характера Cypress.Для динамических значений, получаемых в ходе теста (токены, ID, текст
элементов), часто применяется комбинация cy.wrap() и
алиасов, что позволяет безопасно хранить состояние между командами без
риска гонок асинхронности.
cy.get('#item').invoke('text').then(text => {
cy.wrap(text).as('itemText');
});
cy.get('@itemText').then(text => {
cy.log('Сохранённый текст: ' + text);
});
При работе с объектами и массивами важно помнить, что Cypress не клонирует объекты автоматически. Изменение объекта, сохранённого через алиас, повлияет на все последующие ссылки:
const data = { count: 0 };
cy.wrap(data).as('counter');
cy.get('@counter').then(obj => {
obj.count += 1;
});
cy.get('@counter').then(obj => {
cy.log(obj.count); // 1
});
Для безопасного копирования можно использовать
Cypress._.cloneDeep() из встроенной библиотеки Lodash.
.then() или
cy.wrap().Cypress.env().Эти правила обеспечивают стабильность тестов и предотвращают ошибки, связанные с асинхронностью и порядком выполнения команд.