Retry-ability — одна из ключевых особенностей Cypress, которая отличает его от других инструментов тестирования и делает автоматизацию стабильной и предсказуемой. Этот механизм позволяет тестам повторно проверять действия и утверждения до тех пор, пока они не выполнятся успешно или не истечет таймаут. Понимание его работы критично для эффективного написания тестов в реальных приложениях с асинхронным поведением.
В Cypress каждый командный вызов автоматически повторяется до тех пор, пока:
defaultCommandTimeout,
стандартно 4 секунды).Механизм работает только на уровне команд и
утверждений, а не произвольного кода внутри then
или JavaScript-функций. Это позволяет тестам быть устойчивыми к
динамическим изменениям DOM, задержкам сети и асинхронной загрузке
данных.
Пример базового использования:
cy.get('button.submit').should('be.visible').click();
В этом коде cy.get('button.submit') будет повторяться до
тех пор, пока элемент не станет доступен в DOM и видимым. Аналогично,
should('be.visible') проверка повторяется, что
предотвращает падение теста из-за кратковременной задержки рендеринга
кнопки.
Не все действия в Cypress повторяются автоматически. Ключевые команды с поддержкой механизма:
cy.get(),
cy.contains(), cy.find()should(),
and()click(),
type(), check() при использовании совместно с
should()Пример использования should() с retry:
cy.get('.notification')
.should('have.text', 'Успешно сохранено');
Cypress будет повторять проверку текста .notification до
тех пор, пока содержимое не станет 'Успешно сохранено' или
не закончится таймаут.
Каждая команда и утверждение имеют таймаут, после которого retry прекращается:
Cypress.config('defaultCommandTimeout', 8000)cy.get('.loader', { timeout: 10000 }).should('not.exist');
{timeout: ...}:cy.get('.status', { timeout: 5000 }).should('contain', 'Готово');
Умелое управление таймаутами повышает стабильность тестов, особенно при проверке динамически изменяющихся элементов.
Retry-ability особенно полезна при тестировании приложений с асинхронной загрузкой данных, например:
Пример для асинхронного запроса:
cy.intercept('GET', '/api/users').as('getUsers');
cy.visit('/users');
cy.wait('@getUsers');
cy.get('.user-list li').should('have.length.greaterThan', 0);
Здесь .should('have.length.greaterThan', 0) будет
повторяться до тех пор, пока список пользователей не загрузится,
несмотря на возможные задержки сети.
Важно понимать, что retry работает на уровне каждой команды, а не всей цепочки. Если цепочка состоит из нескольких команд, каждая проверка повторяется отдельно:
cy.get('.form')
.find('input[name="email"]')
.should('be.visible')
.type('test@example.com')
.should('have.value', 'test@example.com');
cy.get('.form') повторяется до появления формыfind('input[name="email"]') повторяется пока элемент не
станет видимымshould('have.value', ...) повторяется после ввода
текста, пока значение поля не совпадетНесмотря на удобство, retry-ability имеет ограничения:
then() или обычного
JavaScript-кода не повторяются автоматически:cy.get('button').then($btn => {
if ($btn.text() === 'Submit') {
// Этот код выполнится только один раз, retry не применяется
}
});
Команды без утверждений не используют retry.
Например, cy.log() или cy.visit() выполняются
один раз.
Сложные условия на несколько элементов могут
потребовать явного использования should или вспомогательных
функций.
then(),
если она должна повторяться — лучше вынести в should.Механизм retry-ability в Cypress упрощает тестирование асинхронных
приложений, повышает устойчивость тестов и снижает вероятность ложных
падений. Грамотное использование should, таймаутов и
правильной цепочки команд позволяет создавать надежные и предсказуемые
тестовые сценарии.