Cucumber в Cypress: пошаговое руководство |
29.11.2023 12:39 |
Автор: Филип Рик (Filip Hric) Один из наиболее частых вопросов на вебинарах и стримах – это «Как мне применить Х в Cucumber?». Cucumber, по ощущениям, обязателен для множества команд – речь может идти о тестировании API, cy.session() или какой-либо иной функциональности. Главное преимущество использования Cucumber – это возможность пользоваться синтаксисом Gherkin для определений тестов. Все тесты пишутся как поведенческие сценарии, а следовательно, тест не только проверяет функциональность, но и служит живой документацией. Цель такого подхода – повысить видимость тестируемого. Плюс тут в том, что не только инженеры, но и другие заинтересованные лица в компании могут проверить, удовлетворяются ли приемочные критерии. Я наблюдал, как хорошо работает этот подход в медицинской и банковской отраслях – тесты не только проверяли функциональность, но и применялись для генерации документации или высокоуровневых отчетов. Что я думаю о применении Cucumber Я известный в прошлом критик синтаксиса Gherkin. В основном я возражаю против применяемого им подхода «черного ящика» в тестировании. Считаю, что это не очень эффективно, особенно в Cypress. Тесты Cypress выполняются в браузере, давая возможность забраться во внутренности приложения, получить доступ к API, кэшировать сессии, менять состояние приложения, имитировать сеть. Хорошо спроектированные тесты Cypress могут дать вам хорошее покрытие при небольшом количестве проверок. При использовании черного ящика вся мощь Cypress испаряется, и это просто инструмент тест-автоматизации. Встают также вопросы поддержки и читабельности. Команды Cypress читабельны из коробки, и при применении хороших практик тесты будут гибкими и простыми в поддержке, даже если приложение регулярно меняет свое поведение. Cucumber использует определения на основе шагов, которые выводят каждую серию команд в отдельный файл. Это тоже может быть очень читабельным, но любое изменение в приложении может потребовать повторного определения или добавления множества шагов. Чем больше становится система, тем труднее внедрять изменения. Глеб Бахмутов отлично объяснил, как сложно может быть изменить Cucumber-тест. Несмотря на это, я создал руководство, чтобы вы смогли эффективно настроить Cypress с Cucumber, если это требуется в вашей компании. Все еще убежден, что успеха можно добиться даже с этой абстрактной моделью, поэтому приступим. УстановкаДля начала вам нужно установить плагин cypress-cucumber-preprocessor. В наличии сейчас множество различных версий, но эта кажется мне наилучшей, и она активно поддерживается. Установить ее можно так: 1 npm i @badeball/cypress-cucumber-preprocessor Помимо установки препроцессора, документация плагина рекомендует установить упаковщик esbuild от Глеба Бахмутова, что значительно ускорит прогон. 1 npm i @bahmutov/cypress-esbuild-preprocessor После установки этих пакетов нужно настроить их использование в Cypress. Финальная конфигурация будет выглядеть примерно так: cypress.config.ts 1 import { defineConfig } from "cypress"; Тут много всякого, пройдемся пошагово. Файл конфигурации написан на TypeScript. Файл JavaScript может быть чуть проще, но будет содержать по сути те же части. Мы импортируем различные пакеты и добавляем их в функцию setupNodeEvents(). Атрибут specPattern говорит Cypress, что мы будем искать файлы .feature в папке e2e. Это значит, что мы будем игнорировать все прочие форматы и использовать для тестов только файлы .feature. Функция addCucumberPreprocessorPlugin() занимается получением файлов .feature и их конвертацией в JavaScript. Так как Cypress работает в браузере, надо убедиться, что все, что мы запускаем (неважно, .ts, .jsx или иные файлы), будет скомпилировано в чистый JavaScript. Этим и занимаются препроцессоры. Часть on("file:preprocessor") занимается комбинированием плагинов esbuild и cucumber, чтобы они дружно играли вместе. Финальная строка return config проверяет, что все, что мы настроили, действительно внедрено в конфигурацию. Про этот шаг часто забывают, поэтому если плагины ведут себя так, как будто их вообще не устанавливали, проверьте наличие этой строчки. Так как компиляция в JavaScript – важная часть работы с файлами .feature, то первичная настройка – как правило, самый сложный этап. Я считаю настройку согласно документации наиболее простой в работе, но если вы работаете с другим упаковщиком вроде Webpack или Browserify, то примеры можно найти здесь. Теперь, когда плагин установлен и настроен, посмотрим, как писать тесты. Тест-сценарии и шагиНачнем с простого сценария с синтаксисом Gherkin. Создайте новый файл cypress/e2e/board.feature и добавьте в него вот что: cypress/e2e/board.feature 1 Feature: Board functionality Теперь нужно создать определения для каждого шага сценария. Простейший способ определить шаги – создать новый файл board.ts в папке cypress/e2e, который будет выглядеть примерно так: cypress/e2e/board.ts 1 import { When, Then, Given } from "@badeball/cypress-cucumber-preprocessor"; Файл определения board.ts можно разместить в папке cypress/e2e folder, или же выбрать другое имя и положить его в папку cypress/e2e/board или cypress/support/step_definitions – препроцессор cucumber автоматически их подберет. О пользовательском пути нужно явно заявить в конфигурации – к этому мы вернемся чуть позже. Для удобства создания тестов в VS Code рекомендую установить расширение Александра Кречика. Оно будет правильно подсвечивать файлы .feature и предоставит удобный доступ к определениям шагов. Добавление параметров к определениям шаговОпределения шагов могут принимать параметры – это позволяет создавать более гибкие, повторно используемые тест-сценарии. Перепишем наш файл определения шагов, чтобы передавать собственное имя доски в тест. cypress/e2e/board.ts 1 import { When, Then, Given } from "@badeball/cypress-cucumber-preprocessor"; Параметры автоматически передаются в соответствующие функции определения шагов, как аргументы. Посмотрите на {string} в определении шага. Тут будет проверяться, передаем ли мы в шаг правильный тип. Теперь создадим в файле cypress/e2e/board.feature сценарий, принимающий boardName как параметр. Он будет выглядеть так: cypress/e2e/board.feature 1 Feature: Board functionality Тестирование, управляемое через данныеЕще одна важная концепция Cucumber, о которой надо знать – это таблицы данных. DataTable в синтаксисе Gherkin позволяет передавать таблицу данных в шаг – это упрощает работу с множеством наборов данных в тест-сценариях. Особенно это полезно для тестирования, управляемого через данные, когда один и тот же сценарий нужно проверять на разных наборах входных данных. Таблицы данных определяются в разделе Examples файла .feature. Продолжим работу над нашим файлом: cypress/e2e/board.feature 1 Feature: Board functionality Когда шаги Examples определены, тест будет прогоняться несколько раз с разными данными на каждом шаге. Заметьте, мы создали переменные boardName и listName, и обернули их в <>, чтобы они передавались в определения шагов, как параметры. Работа с массивом данныхТаблицы данных можно также использовать для передачи данных в один шаг, как видно на примере ниже: cypress/e2e/board.feature 1 Feature: Creating cards functionality Шаг, однако, должен уметь работать с таблицей данных. Это делается так: cypress/e2e/cards.ts 1 When("I create cards with names", (table: DataTable) => { Функция table.raw()[0] вернет первую строчку ([0]) таблицы, как массив. Внутри определения шага мы проходим по этому массиву, создавая элементы списка. Группировка тестовВ дополнение к ключевым словам Given, When, Then, And есть и другие способы организовать множество тестов в едином файле .feature. Наш тест пока что создает новую доску и новый список – изменим его слегка, создав тест, который просто создает еще одну доску, и поставим его перед существующим тестом: cypress/e2e/board.feature 1 Feature: Board functionality Это похоже на блоки describe(), context() и it() в Mocha – мы можем организовать наши тесты, сгруппировав их в логические кластеры. Ключевое слово Feature работает, как блок describe(), и служит группой верхнего уровня. В пространстве Feature можно добавить блок Rule – он разделит ваши сценарии на подгруппы. Тестируя разные сценарии, можно добавить шаг Background – он работает похоже на хук beforeEach() в Mocha и запускает последовательность шагов перед каждым сценарием. Можно абстрагировать шаги Given и When из текущего файла .feature, сделав тест почище. Совместно с ключевым словом Rule тест станет выглядеть так: cypress/e2e/board.feature 1 Feature: Board functionality Использование хуковНесмотря на возможность добавления Background, мы все еще можем задать шаги Before и After – они ведут себя, как хуки beforeEach() и afterEach() в Mocha. Их падение не заставит тесты падать – они запускаются внутри ваших тестов. Шаги Before и After – это часть файла определения шагов, поэтому добавлять в файл .feature их не нужно. cypress/e2e/board.ts 1 import { When, Then, Given, Before } from "@badeball/cypress-cucumber-preprocessor"; Теги тестовТеги – мощная функция синтаксиса Cucumber, позволяющая разбивать сценарии на категории и фильтровать их. Теги можно использовать для прогона конкретных сценариев или исключения их из прогона. Для добавления тегов к сценариям просто добавьте к сценарию или фиче префикс @, а затем имя тега. К примеру, добавим тег @regression в сценарий успешной авторизации файла cypress/e2e/board.feature: cypress/e2e/board.feature 1 Feature: Board functionality Для прогона тестов с конкретным тегом нужна команда: 1 npx cypress run --env tags="@smoke" Теперь тесты без тега @smoke будут пропущены.
Это можно также протестировать в открытом режиме, используя ту же самую команду с open вместо run. Помимо прогона тестов с определенным тегом, можно передавать ключевое слово для прогона всех тегов, кроме заданных. 1 npx cypress run --env tags="not @smoke" Можно также прогнать все тесты, содержащие хотя бы один тег из списка: 1 npx cypress run --env tags="@smoke or @regression" Или тесты, содержащие оба тега: 1 npx cypress run --env tags="@smoke and @regression" Для ускорения прогона тестов можно воспользоваться опциями filterSpecs и omitFiltered – они работают похоже на плагин @cypress/grep. Эту функциональность можно добавить через добавление специальных опций в файл cypress.config.ts: 1 import { defineConfig } from "cypress"; НастройкаИзменить настройку препроцессора Cucumber по умолчанию можно двумя способами. Первый – создать конфигурационный файл .cypress-cucumber-preprocessorrc.json, примерно такой: .cypress-cucumber-preprocessorrc.json 1 { Второй – настроить все прямо в package.json, добавив эквивалент: package.json 1 // для краткости остаток файла пропущен Настройки из примеров – это настройки по умолчанию. Если вам не нужно ничего менять, добавлять это в проект нет необходимости. ОтчетностьПлагин Cucumber для Cypress имеет множество опций для настройки отчетов. Покажу вам самую простую – отчет HTML. Все, что нужно делать – это настроить конфигурацию: 1 { После прогона теста вы получите красивый HTML-отчет:
Если нужны более продвинутые варианты, которые впоследствии будут распознаваться и загружаться в вашу собственную систему отчетности, взгляните на json-formatter, созданный авторами Cucumber. Его нужно устанавливать отдельно и настроить его запуск в конфигурационном файле. ЗаключениеКак я упоминал в начале, есть более эффективные способы применения Cypress. Выполнение всего на свете в end-to-end тестах через UI – это уже через край, а учитывая дизайн Cypress, куда эффективнее использовать его для того, для чего он задуман. Однако я надеюсь, что статья будет вам полезной, если вам необходимо применять Cucumber в Cypress. |