Оптимизация автотестов Cypress с помощью  циклов JavaScript

Привет, Хабр!

За последние несколько лет работы с командами тестировщиков ПО в России и США мне довелось столкнуться с различными подходами к организации тестирования, разнообразными паттернами построения тестовых сценариев и разработки автоматических тестов. При этом нередко случалось, что приходя на проект и анализируя имеющуюся тестовую базу выяснялось, что существующие автотесты нуждались в серьезной доработке или вовсе переработке в целях обеспечения их надежности и сокращения времени на их выполнение. Преимущественно это касалось этапа сквозного (e2e) тестирования, и по моим наблюдениям очень часто причиной тому было не столько незнание тестировщиками встроенных команд тестового фреймворка, сколько неумение применить в тестах базовые возможности языка программирования.

Это побудило меня написать пару статей, в которых я хотел бы поделиться с вами некоторыми наработками по оптимизации автотестов Cypress, основываясь на простых и в основном известных возможностях JavaScript. Изначально статьи были опубликованы на английском языке в моем блоге «Testing with Cypress» на Medium.

Итак, почему же Cypress?

Cypress — это современный фреймворк сквозного (e2e) тестирования на основе JavaScript, разработанный для автоматизации веб-тестирования путем запуска тестов непосредственно в браузере. Cypress стал популярным инструментом веб-приложений благодаря ряду отличительных преимуществ, таких как удобный интерфейс, быстрота выполнения тестов, удобство отладки, простота написания тестов и т.д.

Те, кто уже имел какой-либо опыт работы с этим тестовым фреймворком, наверняка знают о его преимуществах, позволяющих обеспечить покрытие проектов качественными и надежными автотестами. Особо стоит отметить то, что Cypress имеет хорошо проработанную документацию c полезными рекомендациями для начинающих, которая постоянно совершенствуется, а также обширное комьюнити пользователей. Однако несмотря на удобство и сравнительную простоту для быстрого старта, все же не стоит забывать, что говоря про тесты Cypress в первую очередь мы имеем ввиду код. В этой связи для эффективной работы с Cypress от тестировщика требуется не только понимание тестирования ПО как такового и основ программирования, но и более-менее уверенное владение JavaScript/TypeScript.

Переходя к сути статьи, отмечу, что среди наиболее распространенных ошибок при написании автотестов Cypress в отдельную группу можно выделить случаи, при которых в тестах многократно воспроизводятся одни и те же или похожие по смыслу действия, проверки, условия и т.д. При этом в зависимости от тестируемых элементов или производимых действий зачастую они выделяются тестировщиками в отдельные автотесты. Это приводит к значительному увеличению количества тестов, что усугубляется наличием нескольких дополнительных условий, помещенных в beforeEach и afterEach хуки, которые воспроизводятся перед/после каждого теста по мере выполнения тест-сьютов.

В целом такого рода ситуации не соответствуют принципу DRY, усложняют поддержку тестов, замедляют их выполнение, повышают вероятность появления ошибок и flaky тестов. В некоторых случаях подобные ошибки в конечном итоге приводят к кратному увеличению общего времени прогона тестов.

С учетом этого, в данной статье я бы хотел рассмотреть вопрос, когда и каким образом можно использовать простейшие JavaScript циклы при написании автотестов Cypress, чтобы избежать вышеописанных ситуаций.

Проанализировав наиболее часто встречающиеся случаи воспроизведения итерируемых действий при тестировании веб-приложений я выделил 9 наиболее общих кейсов, когда использование циклов в автотестах наиболее эффективно. Безусловно это не исчерпывающий список, возможны другие случаи в зависимости от существующих тестовых сценариев. Давайте детально рассмотрим каждый из них и на конкретных примерах узнаем, как циклы могут существенно помочь оптимизировать ваши автотесты Cypress.

1. Перебор набора/списка элементов

Циклы могут быть полезны в ходе перебора внутри набора элементов или списка объектов для выполнения повторяющихся задач. Например, если на веб-странице есть несколько элементов типа checkbox, то цикл может быть использован для выбора или снятия выбора с каждого из них. Цикл может быть контролируемым, устанавливая начальные и конечные значения. Использование циклов в подобном сценарии гарантирует, что все элементы или объекты будут перебраны при необходимости.

В данном примере мы используем метод Array.from () для преобразования значения, возвращаемого командой Cypresscy.get (), в стандартный массив. Затем мы используем цикл forEach (), чтобы перебрать каждый элемент и далее выполнить некоторое действие.

2. Повторение теста с разными входными данными или ожидаемыми результатами

Если на странице есть несколько форм, каждая из которых требует разных входных данных, можно использовать цикл для выполнения одного и того же теста с каждой формой. Циклом можно управлять с помощью условных операторов, которые проверяют ожидаемый результат для каждого входного значения. Такой подход экономит время и уменьшает количество кода, необходимого для тестирования нескольких сценариев.

1f3dece9dcb55cb211a596636343253c.png

В этом примере мы используем цикл for…of с деструктуризацией для повторения теста с разными входными данными и ожидаемыми результатами. Мы определяем массив объектов, каждый из которых имеет свойства input и expectedoutput, и используем цикл для перебора каждого объекта в ходе выполнения теста.

3. Навигация по нескольким страницам  

В одном автотесте Cypress можно реализовать навигацию по нескольким страницам веб-приложения с помощью цикла, который проверяет содержимое каждой страницы. Значение цикла может быть регулируемым с помощью условных операторов, которые подтверждают наличие следующей или предыдущей страницы. Такая техника не только улучшает организацию кода, но и повышает его читабельность.

В приведенном примере показано, как использовать цикл forEach для навигации по нескольким страницам. Код создает массив URL-адресов страниц, а затем использует цикл forEach для посещения каждого URL-адреса и проверки того, что страница загрузилась корректно с помощью Cypress метода should ().

4. Тестирование нескольких учетных записей или ролей пользователя  

Если в веб-приложении есть несколько учетных записей или ролей пользователя, цикл может быть использован для тестирования каждой роли или записи, обеспечивая вход в систему с различными наборами учетных данных. Цикл может быть управляем через условные операторы, которые подтверждают ожидаемые результаты для каждой роли пользователя или учетной записи.

Смысл использования цикла for…of в приведенном тесте Cypress заключается в том, чтобы перебрать массив пользователей и выполнить один и тот же тестовый сценарий с разными наборами данных. В данном случае, сценарий тестирования включает вход в систему с конкретными учетными данными пользователя, выполнение действий, специфичных для их роли, и выход из системы. Это экономит время и усилия при написании отдельных тестов для каждой пользовательской учетной записи или роли.

5. Запуск одного и того же теста с различными конфигурациями  

Если веб-приложение имеет несколько конфигураций для различных сред выполнения, то можно использовать циклы для тестирования приложения в каждой из указанных сред.
 


Использование цикла for…of в этом тесте позволяет оптимизировать выполнение теста, уменьшив повторение кода. Перебирая config массив и используя данные конфигурации для настройки тестовой среды, мы можем избежать повторения одного и того же кода при написании тестов для каждой конфигурации.

Это делает код теста более лаконичным и понятным, а также уменьшает риск возможных ошибок. Кроме того, разделяя данные конфигурации от кода теста, мы можем легко добавлять или удалять конфигурации без необходимости изменения кода самого теста.

6. Динамическая генерация тестовых данных  

Циклы могут использоваться для динамической генерации тестовых данных. Например, если требуется создать несколько учетных записей пользователей, цикл может быть использован для генерации набора данных пользователя на каждой итерации. Цикл может быть управляемым путем задания начальных и конечных значений, а также указанием количества создаваемых пользователей.

В указанном примере используется цикл forEach для итерации по каждому ключу в объекте testData и выполнения теста для каждого ввода. Этот цикл позволяет избежать дублирования одного и того же тестового случая для каждого ввода за счет выполнения одного и того же теста динамически для каждого ввода, а также легко добавлять новые тестовые случаи. Это делает код более эффективным и уменьшает вероятность ошибок при добавлении новых тестов.

7. Итерация по набору тестовых шагов  

Если в ходе тестирование веб-приложения тест-кейс включает нескольких шагов, цикл может быть использован для повторения этих шагов на каждой итерации. При этом цикл может быть управляем при помощи условных операторов, которые указывают ожидаемый результат для каждого шага.
 

В этом тесте каждый шаг по сути является объектом, который содержит информацию о действии, которое должно быть выполнено во время тестирования, например нажатие кнопки или ввод определенного текста в поле ввода. Используя цикл forEach для итерации через массив шагов, тест может выполнять каждое действие последовательно и с меньшим количеством повторяющегося кода.

Внутри цикла тест проверяет свойство action для каждого шага, чтобы определить, какое действие должно быть выполнено. В зависимости от значения свойства, тест будет использовать различную Cypress команду для выполнения действия. Например, если действие — type, тест будет использовать команду cy.get ().click (), чтобы имитировать нажатие кнопки.

8. Тестирование одной и той же функциональности или поведения в разных окружениях

Если веб-приложение должно быть протестировано на разных браузерах или разрешениях экрана, цикл может быть использован для тестирования приложения в каждой конфигурации. Цикл может быть управляем с помощью условных операторов, которые проверяют ожидаемые результаты для каждого окружения.
 

Так, в приведенном примере внутри цикла forEach устанавливается размер области просмотра с помощью команды cy.viewport () с изменяемыми параметрами ширины и высоты. Использование цикла в этом случае позволяет запустить тест несколько раз с разными конфигурациями, не дублируя код теста. Это делает тест более эффективным и удобным для изменения, особенно когда требуется протестировать множество разных окружений.

9. Ожидание появления элемента

Циклы могут использоваться для ожидания появления элемента на веб-странице в течении n-го количества попыток. Например, если на веб-странице есть спиннер загрузки, который появляется несколько раз во время различных взаимодействий, можно использовать цикл для ожидания исчезновения счетчика каждый раз, когда он появляется. Циклом можно управлять, установив максимальное время ожидания или указав условие, сигнализирующее об окончании цикла.
 


В этом примере мы используем цикл while, чтобы повторно проверять, существует ли элемент с идентификатором elementна странице. Цикл будет продолжать работу до тех пор, пока элемент не будет найден или не будет достигнуто максимальное количество повторных попыток. Использование цикла важно, потому что это позволяет нам обрабатывать ситуации, когда элемент может не появиться на странице сразу же или когда задержки сети или сервера могут вызвать появление элемента только после определенного времени. Без цикла наш тест может завершиться неудачно, если элемент не будет найден с первой попытки, даже если элемент в конечном итоге появится на странице. Однако при этом не буду утверждать, что использование цикла в приведенном кейсе является лучшей практикой из возможных вариантов решения.

Заключение

Таким образом, JavaScript циклы являются важным инструментом автоматизации тестирования в Cypress. Как вы могли убедиться, существуют различные кейсы оптимизации автотестов Cypress с помощью циклов, значительно повышающих эффективность тестирования и сокращающих общее время выполнения тестов, а также время и усилия на их разработку и обслуживание. В следующей статье мы рассмотрим различные варианты использования рекурсии, которая также может быть крайне полезна для оптимизации автотестов Cypress.Исходный код всех представленных примеров размещен в GitHubрепозитории.

Спасибо за внимание и удачного тестирования!

© Habrahabr.ru