Основы Cypress: Переменные |
04.03.2022 00:00 |
Автор: Филип Рик (Filip Hric) Если вы оказались здесь через Google-поиск, то, возможно, недоумеваете, почему подобный код не работает в Cypress: it('stores value in variable', () => { Если вам нужно только решение, промотайте вниз до раздела Возможные решения. Если вы хотите разобраться, что происходит, читайте дальше. Почему же ID не определен? Копаясь в документации, можно слегка запутаться. Есть статья про асинхронность команд в Cypress, а также можно прочитать про обращение с переменными и попробовать async/await, но это тоже не сработает. Что же происходит? Добавим несколько функций console.log() к нашему тесту и посмотрим, как он себя поведет. Можете ли вы, просто смотря на код, догадаться, что будет выведено в консоли браузера? it('stores value in variable', () => { Возможно, вы верно угадали. Но я думаю, вам любопытно, почему ответ таков: >>> first log Как я сказал ранее, ответ есть в документации, но там можно слегка запутаться. Я, по крайней мере, запутался. Поэтому вот как можно в этом разобраться другим путем. Cypress-цепочка VS все остальное Команды Cypress запускаются цепочкой. Каждое звено цепочки привязано к предыдущему и к последующему. Так Cypress убеждается, что вы не попадаете в условия гонки, и будет автоматически ждать завершения предыдущей команды. Приведу пример. cy Повторюсь, команда запускается только после того, как завершена предыдущая. Если любая из них не завершается вовремя (обычно в течении четырех секунд), тест падает. Что же происходит с кодом, который находится вне цепочки? Так как он не часть цепочки, ничто не заставляет его ждать, и он запускается мгновенно. Посмотрим на пример свежими глазами: it('stores value in variable', () => { Надеюсь, что функции console.log() теперь понятнее. Но что насчет этой переменной id? Вроде как она используется внутри цепочки. Так ли это? Вообще-то нет. Она передается как аргумент, и технически не находится внутри цепочки команд, а передана "извне". Мы объявили эту переменную в начале теста. Внутри теста мы говорим Cypress, что хотим выполнить команду .visit() с нужными '/board/' + id. Это начинает приобретать смысл, когда мы пристально рассматриваем наш принцип "внутри цепочки и вне цепочки". Снова взглянем на код. it('stores value in variable', () => { Теперь, когда проблемы яснее, разберемся, как можно передавать значения в тесте, используя разные методы. Для этого есть множество решений, рассмотрим хотя бы некоторые из них. Возможные решения Решение 1: Переместите нужный код внутрь цепочки команд Самое простое решение – убедиться, что мы все включаем в цепочку команд. Для использования нового значения нужно вызвать нашу функцию .visit() внутри цепочки команд. В этом случае id будет передан с новым значением. Конечно, несколько функций .then() могут потенциально вызвать "пирамиду смерти", поэтому это решение лучше подходит для ситуаций, когда вы хотите немедленно передать одну переменную. it('stores value in variable', () => { Решение 2: Разделение логики на несколько тестов Так как Cypress запускает блоки it() один за другим, вы можете разделить логику на несколько тестов и использовать "настроечную" функцию it() для присваивания значений переменным, а затем блок выполнения it() для использования этой переменной. Однако этот подход довольно ограничен, так как вам понадобится отдельный блок для каждого изменения переменной. Это также не лучший тест-дизайн, так как не каждая функция it() теперь тест. Это также может создать странный эффект домино, когда падение теста вызвано предыдущим тестом. let id // объявление переменной Решение 3: Использование хуков Способ получше – разделить тесты, используя хуки before() или beforeEach(). Таким образом вы более логично разделяете тест. У вас есть фаза подготовки, которая не будет частью теста, фаза и выполнения – сам тест. Другое преимущество этого подхода в том, что при падении хука у вас будет внятная информация об этом в логе ошибок. let id // объявление переменной Решение 4: Использование алиасов Мы можем вообще пропустить создание переменной и использовать алиасы. Они не сильно отличаются от переменных, но живут непосредственно в контексте нашего теста. Преимущество этого подхода в том, что нам не нужно сразу же использовать алиас – мы можем воспользоваться им позднее в ходе теста. it('use alias', () => { Решение 5: Использование алиасов и хуков Алиасы на самом деле часть Mocha – фреймворка, объединенного с Cypress и использующегося для запуска тестов. Когда вы применяете команду .as(), это создает алиас в контексте Mocha, к которому можно получить доступ по ключевому слову, как показано в примере. Это будет обычная переменная, и ими можно делиться между тестами в спеке. Однако это ключевое слово нельзя использовать в стрелочных функциях () => {} – только с традиционными выражениями функций, function() {}. См. пример. beforeEach( () => { Существуют еще примеры, помогающие хранить переменные в Cypress, я привел лишь несколько из них. В более старой статье я приводил более продвинутые примеры по взаимодействию с данными из API, ее можно посмотреть здесь. |