Playwright + Cucumber необычная связка. Практические примеры написания авто тестов

fb07668bd9df580fdab0a4e2991f6bd5.png

1. Введение

Cucumber уже не молодой и вероятно не самый популярный инструмент для разработки, ориентированной на BDD, но он все еще используется некоторой популярностью так как фокусируется на определении и тестировании ожидаемого поведения системы с точки зрения пользователей.

Я решил использовать связку из этих двух инструментов исходя из того что BDD тесты — это простой текст, на человеческом языке, написанный в форме истории (сценария), описывающей некоторое поведение, значит Cucumber прост для понимания как начинающему специалисту с небольшим опытом тестирования так и для лица технически не подкованным. При этом мощная сердцевина playwright дает большие возможности для написания авто тестов. Градация фреймворка на части позволит опытному специалисту создавать базовую часть функций (в данном примере на Playwright + TypeScript), а начинающему специалисту покрывать тестами приложение с использованием готовой базы и знаниями (Cucumber, X-path). PS возможно это станет более понятным в конце статьи.

Используемые фреймворки/инструменты:

  • Playwright

  • Cucumber

  • Typescript

  • NodeJS

2. Подготовительные работы

Для практики нам понадобиться простенькое web приложение / сайт. На пример это будет тестирование UI части некой signup/registration формы.
Оптимальный вариант запуск данного web приложения локально.
Вы можете как самостоятельно создать похожую страницу так и воспользоваться примером созданным мною. Желательно Чтобы сильно не загружать статью файлами, необходимый комплект файлов добавлен в git репозиторий -https://github.com/QaitkenQ/test_signup_form/tree/start_files

Шаги установки/настройки web приложения

  1. Установите Node JS.

  2. Создайте папку/каталог, например test_server.

  3. Распакуйте скачанные файлы в созданный каталог или загрузите файлы через консоль посредством git.
    Корневой каталог с web приложением будет выглядеть так: (*readme.md файл не обязателен)

    Web приложение

    Web приложение

  4. Откройте командную строку и перейдите в рабочий каталог или откройте каталог редактором кода (например VSC).

  5. Выполните следующие команды через терминал.

  6. Запустите сервер командой

    • node server.js

  7. Убедитесь в работоспособности сервера открыв страницу http://localhost:3000 в браузере.

da6a380a8cc9c841520ada48a8a56b28.png

Сайт готов для выполнения тестирования.

3. Установка/настройка Playwright и Cucumber

  1. Создайте корневой каталог для фреймворка со следующей структурой (например Cucuwright):

    Структура фреймворка

    Структура фреймворка

    Папка feature — содержит файл сценариев Cucumber.
    Папка src — содержит 3 папки с файлами:
    1. step_defenitions — здесь находятся файлы c детальным описанием шагов cucumber.
    2. page_objects — здесь находятся файлы с описанием элементов страницы и действия выполняемые с ними.
    3. utils — здесь находится файл BaseFunctions содержащий базовые операции/действия, которые могут быть применимы для любой страницы.
    Файл cucumber.js — содержит некоторые настройки для фреймворка Cucumber.
    Файл tsconfig.json — содержит настройки TypeScript.

    Стартовый комплект файлов так же доступен в репозитории на другой ветке https://github.com/QaitkenQ/test_signup_form/tree/cucuwright
    В них уже имеются предварительно созданные данные для начала тестирования страницы с singup form, которая уже запущена на http://localhost:3000 (Например файл шагов уже содержит хуки BeforeAll и AfterAll для корректного открытия и закрытия страницы браузера, необходимые зависимости между файлами уже описаны).

  2. Откройте командную строку и перейдите в рабочий каталог или откройте каталог редактором кода (например VSC).

  3. Установите фреймворк Playwright выполнив команду npm init playwright@latest и выбрав необходимые опции (язык typescript, каталог для тестов и т.п.)

  4. Установите фреймворк Cucumber выполнив команду npm i @cucumber/cucumber .

  5. Установите дополнительные библиотеки при необходимости
    npm install typescript
    npm install ts-node

  6. Созданные каталоги tests и tests-examples можно удалить.

  7. Проверьте работоспособность запустив команду npx cucumber-js

В консоль должно вывести сообщение о том что для текущего сценария шаги не определены. Файл singup_page.feature имеет один сценарий с 2 шагами. Значит все инструменты корректно установлены и зависимости работают.

Результат в консоли после выполнения всех подготовительных операций

Результат в консоли после выполнения всех подготовительных операций

  1. По желанию можно установить несколько расширений Cucumber для VSC.
    Cucumber (Gherkin)
    Cucumber Reference Support

4. Написание авто теста

Открываем файл сценариев signup_page.feature По умолчанию в нем уже присутствует 1 сценарий с 2 шагами. При создании нового файла .feature создайте аналогичный сценарий.

singup_page.feature

singup_page.feature

Сценарий 1

Шаг 1 — открытие страницы

Откроем файл signup_page_steps.ts и создадим основное описание для первого шага Given SignupPage open page

singup_page_steps.ts

singup_page_steps.ts

Откроем файл signup_page.ts, добавим url нашей страницы и создадим функцию openPage () для выполнения операции открытия страницы.

singup_page.ts

singup_page.ts

Все стандартные операции действия которые возможно выполнять с различными элементами вынесены в отдельный файл BaseFunctions.ts в папке utils.
Функция openPage () включает в себя базовую функцию openUrl () и передает параметр url.

Откроем файл BaseFunctions.ts и создадим базовую функцию openUrl (), финальным действием является метод goto ().

BaseFunctions.ts

BaseFunctions.ts

Для выполнения данной операции можно было описать все в одной функции openPage (), но мы соблюдаем структуру разделения на операции которые относятся только для данной страницы и операциям которые могу быть применимы к любой другой.

Проверим на работоспособность шаг 1 — запускаем тест npx cucumber-js

Результат в консоли - Шаг 1 выполнен успешно.

Результат в консоли — Шаг 1 выполнен успешно.

Шаг 2 — проверка заголовка

Заголовок Sign Up page

Заголовок Sign Up page

Перейдем в файл signup_page_steps.ts и создадим описание для второго шага

When SignupPage verify the header "Sign Up page"

Добавление шага 2 signup_page_steps.ts

Добавление шага 2 signup_page_steps.ts

В данном случаи мы передаем значение (название заголовка) как строку {string}. При любых изменениях текста потребуется только изменить значение в .feature файле.

В файле signup_page.ts, добавим локатор (X-path, или атрибут элемента) для заголовка и создадим функцию isHeadingVisible () для выполнения операции поиска элемента.

Добавление шага 2 singup_page.ts

Добавление шага 2 singup_page.ts

В базовую функцию findElement () мы передаем значение селектора уже с замененным текстом из первоначального шага When SignupPage verify the header «Sign Up page». Посредством .replace значение %s становится равным Sign Up page.

Добавление функции findElement () в файл BaseFunctions.ts

BaseFunctions.ts

BaseFunctions.ts

Для данной операции был выбран метод waitForSelector ().

Запускаем наш тест еще раз npx cucumber-js

Результат в консоли - Сценарий 1, 2 шага выполнено успешно

Результат в консоли — Сценарий 1, 2 шага выполнено успешно

Проверим точно ли мы тест выполняется, действительно ли нужная страница загрузилась и тест проверяет название заголовка — изменим значение в шаге 1 «Sign Up page» → «Sign Up page Fail»

ab977c772cbefeebd4e0249f3b93e13f.png

Получаем в консоли ошибку при выполнении шага 2 — Error: function timed out...

Результат - ошибка на шаге 2.

Результат — ошибка на шаге 2.

Похоже на правду, но хотелось бы получить больше информации в данном случае.

Перепишем функцию findElement () в файле BaseFunctions.ts. Добавим дополнительную функцию erifyElementExists (), которая будет выводить в консоль более детализированное описание об ошибке. Так же можно добавить значение таймаута.

BaseFunction.ts

BaseFunction.ts

Перезапускаем тест npx cucumber-js

Получаем в консоли другой результат — Error: Can't find the element '//h2[text()='Sign Up page Fail']' within the specified timeout

Результат в консоли - ошибка с подробностями

Результат в консоли — ошибка с подробностями

Теперь можно сразу проверить верный ли locator для элемента. Легко проверить скопировав этот путь из лога и вставив его в devtools.

1fc2648bbc6371edb8d2e8157684863e.png

Совпадений 0.
Но если удалить лишний текст, который мы добавили ранее, то будет найдет необходимый элемент.

справляем значение — возвращаем изначальное в шаге 1.
Перезапускаем тест — 1 scenario (1 passed), 2 steps (2 passed). Получаем желаемый результат.

Сценарий 2 — Проверка ярлыков (labels)

377dfa84e6dee670914c7cc3b61f32e2.png

Шаг 1 остается прежним открытие страницы.

Шаг 2 — проверка названия поля элемента

Создаем новый шаг в singup_page.feature файле. Так как в форме много однотипных элементов, то желательно создать шаг с использованием таблицы. Позже когда он будет выполнен успешно, мы добавим остальные ярлыки которые есть в форме. Для начала возьмем ярлык от первого поля First Name

954bf267a561d29b06d8b1fdcaaf3737.png

В файле singup_page_steps.ts описываем шаг 2 с учетом передачи значений из таблицы.

7f6d20a9212a6951477c3f78cd7ee1ff.png

В файле singup_page.ts создаем функцию verifyLabels () и добавляем селектор для элемента label.

8121a453f3e28ed56ea3a65c0bcc8bc1.png

Данная функция использует уже имеющуюся базовую функцию findElement () из BaseFunctions.ts.

Так как у нас теперь 2 сценария, то запускаем только второй сценарий по тегу @test2 npx cucumber-js --tags=@test2

Результат тест пройден.

78cc70bc276861eb78c5b1d6dd22c062.png

Добавим в таблицу остальные ярлыки которые есть в форме

singup_page.feature

singup_page.feature

Перезапускаем сценарий 2 npx cucumber-js --tags=@test2

Результат — мы получили ошибку. Последний ярлык из таблицы «Accept learning the Cucuwright» — не может быть найден.

Результат в консоли - ошибка поиска элемента.

Результат в консоли — ошибка поиска элемента.

Выполнив небольшой анализ видно что ярлык для элемента checkbox имеет другую структуру в DOM дереве. Значит придется создать отдельный шаг для данного элемента.

2b8bea913d5df270bbe5b5125872c7dc.png

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

singup_page.feature

singup_page.feature

В файле singup_page_steps.ts добавим описание шага

c2e3d7e631f54d04eb0f342e4ee46ef4.png

В файле singup_page.ts создаем функцию verifyCheckbox () и добавляем селектор для элемента checkbox_label. В селекторе мы использовали X-path для более детального уточнения элемента — элемент должен иметь тип checkbox с необходимым текстом.

64514aab9b5da7a1368a42242df6170a.png

Запускаем тест npx cucumber-js --tags=@test2
Результат — сценарий выполнен успешно.

Результат Сценарий 2.

Результат Сценарий 2.

Для перепроверки можно выполнить быстрый дебаг добавив ошибку в значение (название) ярлыка — Accept learning the Cucuwright → Accept learning th Cucuwright
В результате мы получим ошибку что элемент checkbox с данным текстом не может быть найден.

Результат - ошибка выполнения последнего шага.

Результат — ошибка выполнения последнего шага.

Сценарий 3 — Проверка введенных значений в поле ввода

56f6e27f00b7104d70586726434913ff.png

Новый сценарий и шаг в файле .feature

singup_page.feature

singup_page.feature

В файле singup_page_steps.ts добавим описание шага.

singup_page_steps.ts

singup_page_steps.ts

В файле singup_page.ts добавим локатор для поля First Name и создадим функцию enterUserName (). Данная функция будет передавать данные в виде string базовой функции enterText ().

ab141ae4d9bb751548f9d29dc543d3e3.png

Создадим базовую функцию enterText () в файле BaseFunctions.

9f4bf8d8116d350d043790ba6a9a4181.png

Проверим работоспособность теста npx cucumber-js --tags=@test3

Результат - тест выполнен успешно

Результат — тест выполнен успешно

Добавим следующий шаг к сценарию №3, проверка значения в поле ввода.
Новый шаг в фалйе .feature

singup_page.feature

singup_page.feature

В файле singup_page_steps.ts добавим описание шага.

2b8d7356e5f071b51e4797da2aaac296.png

Для примера сделаем этот шаг универсальным и применимым к другим полям ввода. К дополнению к основной функции verifyFieldValue () создадим дополнительную функцию determineField () определяющую поле ввода. Так же необходимо добавить локаторы для остальных полей из формы в singup_page.ts файле.

46665d5b80feba0c19fcfa044ca9070e.png

В зависимости от значения в шаге .feature файла будет определено поля для проверки и в случаи отсутствия его в списке для проверки будет выведена ошибка.

Далее в в файле BaseFunctions необходимо создать функцию verifyValue ().

BaseFunctions.ts

BaseFunctions.ts

Запускаем тест еще раз npx cucumber-js --tags=@test3
Результат — тест выполнен успешно.

Результат

Результат

Небольшой дебаг — попробуем ввести ошибочное название поля First Name → Fail Name

singup_page.feature

singup_page.feature

В результате мы получим ошибку с описанием, которое добавили немного ранее.
Unknown field 'Fail Name', please check the name

Результат

Результат

Сценарий 4 — проверка radio button элемента

c1c8b32f783439a2a67bd106133bc1fe.png

Новый сценарий и шаг в файле .feature

singup_page.feature

singup_page.feature

Файл singup_page_steps.ts — описание шага.

00c6fe7824fe8de7f09d20d37a6b7e1f.png

Файл singup_page.ts — добавление локатора radio_btn и создание функции selectRadioButton ().

singup_page.ts

singup_page.ts

Файл BaseFunctions — cоздание базовой функции selectItem ().

BaseFunctions.ts

BaseFunctions.ts

Запуск теста npx cucumber-js --tags=@test4
Результат — тест выполнен успешно.

Результат

Результат

Добавим следующий шаг для проверки выбранного значения.

singup_page.feature

singup_page.feature

Файл singup_page_steps.ts — описание шага.

443824d329f7a012d97e2e8cad17277a.png

Файл singup_page.ts — создание функции isRadioChecked ().

singup_page.ts

singup_page.ts

Файл BaseFunctions — cоздание базовой функции isChecked ().

BaseFunctions.ts

BaseFunctions.ts

Повторный запуск теста npx cucumber-js --tags=@test4
Результат — тест выполнен успешно.

Результат

Результат

Для перепроверки добавим в шаг в табличное значение выбор следующего элемента radio button female.

singup_page.feature

singup_page.feature

В данном случае результатом будет ошибка сообщающая о том, что элемент radio button male не выбран.

Результат

Результат

Сценарий 5 — проверка dropdown поля

087001bcbf56bb57719b5c83b210b966.png

Новый сценарий и шаг в файле .feature

singup_page.feature

singup_page.feature

Файл singup_page_steps.ts — описание шага.

6e3acbd65eea3eac69c23108b80baa18.png

Файл singup_page.ts — создание функции selectDdlValue (). Локатор ddList уже был добавлен ранее.

singup_page.ts

singup_page.ts

Файл BaseFunctions — cоздание функции selectOption ()

BaseFunctions.ts

BaseFunctions.ts

Запуск теста npx cucumber-js --tags=@test5
Результат — тест выполнен успешно.

Результат

Результат

Добавление следующего шага для проверки выбранного значения в выпадающем списке.

Новый шаг в файле .feature. Так как ранее был создан универсальный шаг, который применим к нашему выпадающему списку, создавать дополнительно ничего не требуется

singup_page.feature

singup_page.feature

Повторный запуск теста npx cucumber-js --tags=@test5
Результат — сценарий выполнен успешно.

Результат

Результат

Сценарий 6 — выбор checkbox’a

c935b674a81781d57f447a706d22906b.png

Новый сценарий и шаг в файле .feature

singup_page.feature

singup_page.feature

Файл singup_page_steps.ts — описание шага.

6aee5fe946f000e83459afe84e5d0a33.png

Файл singup_page.ts — создание локатора checkbox и функции selectCheckbox ().

singup_page.ts

singup_page.ts

Базовая функция selectItem () уже была создана ранее.

Запуск теста npx cucumber-js --tags=@test6
Результат — тест выполнен успешно.

Результат

Результат

Добавление следующего шага для проверки был ли элемент выбран.

Новый сценарий и шаг в файле .feature

singup_page.feature

singup_page.feature

Файл singup_page_steps.ts — описание шага.

dd5491c97993f4d5411d4636d3c2e088.png

Файл singup_page.ts — создание локатора checkbox и функции selectCheckbox ().

singup_page.ts

singup_page.ts

Базовая функция isChecked () уже была создана ранее.

Повторный запуск сценария npx cucumber-js --tags=@test6
Результат — сценарий выполнен успешно.

Результат

Результат

Сценарий 7 — проверка ошибки валидации.

e41d5d26d156ef7da9345f51e32c60ae.png

Новый сценарий в файле .feature. Используем имеющиеся шаги и создаем новый шаг для нажатия кнопки Submit.

singup_page.feature

singup_page.feature

Файл singup_page_steps.ts — описание шага.

e53041bafaa8e4b558c9a5b3aa7585c2.png

Файл singup_page.ts — создание локатора btn и функции clickButton ().

singup_page.ts

singup_page.ts

Файл BaseFunctions — cоздание базовой функции clickBtn ().

BaseFunctions.ts

BaseFunctions.ts

Запуск теста npx cucumber-js --tags=@test7
Результат — тест выполнен успешно.

Результат

Результат

Добавление новых шагов — проверка ошибки валидации.

singup_page.feature

singup_page.feature

Файл singup_page_steps.ts — описание шага.

458db5cefe27025f3f91466d39eeabb6.png

Файл singup_page.ts — создание локатора valid_error и функции verifyError (). Так же как и в случае с проверкой значения в поле ввода в данной функции присутствует вспомогательная функция для распознавания пути — у какого элемента искать ошибку.

singup_page.ts

singup_page.ts

Файл BaseFunctions — cоздание базовой функции verifyText ().

b6c38bbbd1590498b32f852db4813954.png

Запуск сценария npx cucumber-js --tags=@test7
Результат — тест выполнен успешно.

Результат

Результат

Добавим в данный сценарий проверку ошибки валидации для поля Last Name — «Required field»

singup_page.feature

singup_page.feature

Повторный запуск теста npx cucumber-js --tags=@test7
Результат — тест выполнен успешно.

Результат

Результат

Изменим текст ошибки для выполнения негативного сценария и перепроверки созданного теста

singup_page.feature

singup_page.feature

В результате получим ожидаемую ошибку. Фактический результат "Please use only alphabetical characters"

Результат

Результат

Заключение

В итоге мы настроили запустили простенький сервер, установили и настроили фреймворк и написали несколько авто тестов. В начале статьи я писал, что обьясню как в моем понимании связка cucumber + playwright может помочь в написании авто тестов начинающему специалисту. При использовании данной структуры и работе в команде опытный специалист может создать основной костяк на основе небольшой части приложения и описав основные операции в файле BaseFunctions. В случаи большого веб приложения и схожих его частей и использовании шагов с универсальными способами, второму специалисту, с меньшим опытом написания авто тестов, будет не сложно покрыть тестами остальную часть приложения на основе имеющегося задела. Как результат это будут созданные фалы для других страниц с дублированием имеющихся операций и минимальными изменениями. Хотелось показать на примере создания тестов для другой страницы, но статья уже получилась не маленькая и я думаю это будет лишним. Так же плюсом будет простота понимания написанных сценариев в файле .feature для технически не подкованного человека.

Это моя первая статья, прошу отнестись с пониманием если имеются неточности или ошибки. Буду рад любой критике. Надеюсь кому-то статья будет полезной. В будущем планирую создать другую статью с практическими тестами для БД или API.

© Habrahabr.ru