В текущих проектах я применяю подход Behavior Driven Development (BDD) для написания end‑to‑end тестов. Хотя раньше я скептически относился к Given‑When‑Then синтаксису, теперь часто его использую. Главная причина — я больше не пишу BDD‑сценарии вручную, а генерирую их с помощью ChatGPT.
В статье расскажу, как вы можете генерировать AI-тесты в своем проекте и запускать их в реальном браузере с помощью Playwright.
Для примера я буду использовать демо‑приложение TodoList, разработанное командой Playwright. Это веб‑страница со списком, в который можно добавлять записи, помечать их выполненными и фильтровать по статусу. Конечная цель — покрыть это приложение end‑to‑end тестами, при этом написать минимум кода вручную и делегировать максимум работы ChatGPT. В идеале тесты запускаются и проходят вообще без дополнительных правок. Ниже проверим, насколько это возможно.
План
А мой список дел для статьи следующий:
Сформулировать требования (user story)
Сгенерировать описания шагов
Сгенерировать BDD сценарии
Запустить тесты
Подвести итог
1. Сформулировать требования (user story)
Пользовательская история (user story) — важнейший элемент BDD. Это описание действий пользователя для достижения конкретной цели в приложении. Для тестирования TodoList возьмём следующие требования:
As a user I want to manage items in todo list:
create items, complete items and filter to see only completed items.
Все тексты, относящиеся к запросам в ChatGPT, будут на английском — прим. переводчика.
Дальше я буду использовать этот текст в запросах к ChatGPT.
2. Сгенерировать описания шагов
Описание шага (step definition) — это конкретная реализация действия пользователя. Например:
Given I open TodoApp page
превращается в команду для браузера:
await page.goto('https://demo.playwright.dev/todomvc/');
Или
When I click the button
становится:
await page.getByTestId('button').click();
Набор описаний шагов можно объединить в Page Object Model — класс, соответствующий определенной странице приложения в тестовых сценариях.
Для списка дел потребуется один класс TodoPage
с методами для создания, маркировки и фильтрации записей. Сложность в том, что реализация шагов сильно зависит от структуры HTML, поэтому я не буду делегировать это искусственному интеллекту. Но... ChatGPT отлично справится с генерацией шаблона для такого класса.
На выходе я хочу получить код на TypeScript с использованием пакетов @playwright/test и playwright-bdd — чтобы потом запустить эти тесты на Playwright.
Запрос к ChatGPT для генерации шаблона TodoPage
:
Create Page Object Model 'TodoPage' in Typescript
for the following feature:
As a user I want to manage items in todo list:
create items, complete items and filter to see only completed items.
* Use page from '@playwright/test' as constructor parameter.
* Use Given, When, Then from 'playwright-bdd/decorators' as BDD decorators, for example: @Given('pattern {string}').
* Don't fill methods body.
Отправляю запрос в чат и жду результат. Меня всегда немного гипнотизирует процесс авто-генерации кода ?
Полный код из ответа ChatGPT
import { Page } from '@playwright/test';
import { Given, When, Then } from 'playwright-bdd/decorators';
export class TodoPage {
private page: Page;
constructor(page: Page) {
this.page = page;
}
@Given('I am on the Todo page')
async navigateToTodoPage() {
// Implement navigation to the Todo page here
}
@When('I create a new todo item with text {string}')
async createTodoItem(text: string) {
// Implement creating a new todo item here
}
@When('I complete the todo item with text {string}')
async completeTodoItem(text: string) {
// Implement completing a todo item here
}
@When('I filter to see only completed items')
async filterCompletedItems() {
// Implement filtering completed items here
}
@Then('I should see the todo item with text {string}')
async verifyTodoItemVisible(text: string) {
// Implement verification logic here
}
@Then('I should not see the todo item with text {string}')
async verifyTodoItemNotVisible(text: string) {
// Implement verification logic here
}
@Then('I should see only completed todo items')
async verifyOnlyCompletedItemsVisible() {
// Implement verification logic here
}
@Then('I should see all todo items')
async verifyAllItemsVisible() {
// Implement verification logic here
}
}
Получилось неплохо: ChatGPT сгенерировал необходимые методы, пометил их правильными декораторами и прокинул параметры там, где это нужно.
Теперь я хочу улучшить результат. Вместо 4-х методов верификации оставить один, который сверяет список целиком. Это удобнее, чем проверять записи по одной. Отправляю запрос в чат обычным текстом и получаю исправленный ответ.
Уточняющий запрос:
Replace all verify methods with single method
that verifies list of visible items
Ответ ChatGPT (обратите внимание на последний метод)
import { Page } from '@playwright/test';
import { Given, When, Then } from 'playwright-bdd/decorators';
export class TodoPage {
private page: Page;
constructor(page: Page) {
this.page = page;
}
@Given('I am on the Todo page')
async navigateToTodoPage() {
// Implement navigation to the Todo page here
}
@When('I create a new todo item with text {string}')
async createTodoItem(text: string) {
// Implement creating a new todo item here
}
@When('I complete the todo item with text {string}')
async completeTodoItem(text: string) {
// Implement completing a todo item here
}
@When('I filter to see only completed items')
async filterCompletedItems() {
// Implement filtering completed items here
}
@Then('I should see the following todo items:')
async verifyTodoItemsVisible(itemList: string[]) {
for (const itemText of itemList) {
// Implement verification logic for each itemText here
}
}
}
Все исправлено. ChatGPT заменил часть методов, а остальные оставил нетронутыми.
Важно заметить, если вы отправите такие же запросы в ChatGPT, вы получите другие результаты, лучше ли хуже. Я специально провёл несколько экспериментов на чистых сессиях. Вот примеры команд, которые помогут улучшить ответ:
make all methods async
— иногда ChatGPT генерирует синхронные методыuse {string} for string pattern parameters
— использовать корректный синтакс Cucumber Expression для параметровcreate todo items inside scenario "xxx"
— исправить сценарии, которые используют данные других сценариев, тесты должны быть изолированыdon't start method names with given/when/then
— для более лаконичных имён методов
Важно не пытаться получить идеальный результат. ChatGPT, как и человек, может отвечать по-разному. Для меня наиболее эффективной стратегией стало:
получить первичный ответ
улучшить его дополнительными командами
финально подправить вручную
Для примера с генерацией TodoPage
это особенно релевантно, т.к. в любом случае требуется дописать реализацию методов.
2.1 Реализация методов
Реализацию методов можно писать вручную, изучая HTML-код страницы через инструменты разработчика. Но изначальная цель — сгенерировать максимум кода автоматически. К счастью, Playwright предоставляет инструмент codegen, который записывает все действия на странице в виде команд для браузера.
Режим codegen запускается через терминал:
npx playwright codegen https://demo.playwright.dev/todomvc
После этого на заданном URL открывается окно браузера, в котором достаточно выполнить необходимые действия. Например:
добавить пару записей
пометить выполненными
отфильтровать
Сгенерированный код:
test('test', async ({ page }) => {
await page.goto('https://demo.playwright.dev/todomvc/#/');
await page.getByPlaceholder('What needs to be done?').fill('feed the dog');
await page.getByPlaceholder('What needs to be done?').press('Enter');
await page.getByPlaceholder('What needs to be done?').fill('feed the cat');
await page.getByPlaceholder('What needs to be done?').press('Enter');
await page.locator('li').filter({ hasText: 'feed the cat' }).getByLabel('Toggle Todo').check();
await page.getByRole('link', { name: 'Completed' }).click();
});
Из этого кода я выбираю нужные фрагменты и вставляю их в шаблон от ChatGPT.
В некоторых местах ручных правок не избежать. Например, получение DOM элементов через селектор page.locator('li')
я заменю на более надежный page.getByTestId('todo-title')
.
Финальный класс TodoPage
со всеми доработками:
TodoPage.ts
import { Page, expect } from '@playwright/test';
import { Given, When, Then, Fixture } from 'playwright-bdd/decorators';
import { DataTable } from '@cucumber/cucumber';
export @Fixture('todoPage') class TodoPage {
private page: Page;
constructor(page: Page) {
this.page = page;
}
@Given('I am on the Todo page')
async navigateToTodoPage() {
await this.page.goto('https://demo.playwright.dev/todomvc/#/');
}
@When('I create a new todo item with text {string}')
async createTodoItem(text: string) {
await this.page.getByPlaceholder('What needs to be done?').fill(text);
await this.page.getByPlaceholder('What needs to be done?').press('Enter');
}
@When('I complete the todo item with text {string}')
async completeTodoItem(text: string) {
await this.page.getByTestId('todo-item').filter({ hasText: text }).getByLabel('Toggle Todo').check();
}
@When('I filter to see only completed items')
async filterCompletedItems() {
await this.page.getByRole('link', { name: 'Completed' }).click();
}
@Then('I should see the following todo items:')
async verifyTodoItemsVisible(itemList: DataTable) {
await expect(this.page.getByTestId('todo-title')).toHaveText(itemList.raw().flat());
}
}
3. Сгенерировать BDD сценарии
Теперь всё готово для генерации BDD сценариев из созданных шагов. Важно указать ChatGPT использовать только конкретные шаги, чтобы в последующем запускать полученные сценарии без дополнительных правок.
Можно зайти и с другой стороны: сначала генерировать сценарии, а потом реализовывать шаги. Но в этом случае, если вы решите пересоздать сценарии, то придётся обновлять описания шагов в коде
Для получения списка доступных шагов в playwright-bdd
есть специальная команда bddgen export
. Она собирает описания шагов из всех файлов и выводит их в текстовом виде.
Запуск команды и вывод списка шагов из TodoPage
:
> npx bddgen export
List of all steps found by config: playwright.config.ts
* Given I am on the Todo page
* When I create a new todo item with text {string}
* When I complete the todo item with text {string}
* When I filter to see only completed items
* Then I should see the following todo items:
Полученный список шагов я вставляю в запрос к ChatGPT.
Запрос для генерации BDD сценариев:
Generate BDD scenarios as a single Gherkin file strictly using
only the following steps:
* Given I am on the Todo page
* When I create a new todo item with text {string}
* When I complete the todo item with text {string}
* When I filter to see only completed items
* Then I should see the following todo items:
Ответ ChatGPT
Feature: Todo List Management
Scenario: Create a new todo item
Given I am on the Todo page
When I create a new todo item with text "Buy groceries"
Then I should see the following todo items:
| Todo Text |
| Buy groceries |
Scenario: Complete a todo item
Given I am on the Todo page
When I create a new todo item with text "Read a book"
And I complete the todo item with text "Read a book"
Then I should see the following todo items:
| Todo Text |
| [x] Read a book |
Scenario: Filter completed items
Given I am on the Todo page
When I create a new todo item with text "Walk the dog"
And I create a new todo item with text "Water the plants"
And I complete the todo item with text "Walk the dog"
And I filter to see only completed items
Then I should see the following todo items:
| Todo Text |
| [x] Walk the dog |
Scenario: Filter completed items with multiple completed items
Given I am on the Todo page
When I create a new todo item with text "Go for a run"
And I create a new todo item with text "Write code"
And I complete the todo item with text "Go for a run"
And I complete the todo item with text "Write code"
And I filter to see only completed items
Then I should see the following todo items:
| Todo Text |
| [x] Go for a run |
| [x] Write code |
Результат снова неплох. ChatGPT корректно использует Given-When-Then синтаксис, генерирует осмысленные сценарии и применяет только указанные шаги.
Как и в предыдущий раз, можно улучшить ответ:
Использовать ключевое слово
Background
для повторяющихся действий — это аналогbeforeEach()
Удалить
[x]
из названий в таблицах — иначе сравнение записей будет выдавать ошибкуУдалить заголовок
Todo Text
в таблицах — он тут лишний, т. к. всего одна колонка
Уточняющий запрос:
* Use "Background" for common steps.
* Don't use "[x]"
* Don't use "Todo Text" header
Обновленный ответ ChatGPT
Feature: Todo List Management
Background:
Given I am on the Todo page
Scenario: Create a new todo item
When I create a new todo item with text "Buy groceries"
Then I should see the following todo items:
| Buy groceries |
Scenario: Complete a todo item
When I create a new todo item with text "Read a book"
And I complete the todo item with text "Read a book"
Then I should see the following todo items:
| Read a book |
Scenario: Filter completed items
When I create a new todo item with text "Walk the dog"
And I create a new todo item with text "Water the plants"
And I complete the todo item with text "Walk the dog"
And I filter to see only completed items
Then I should see the following todo items:
| Walk the dog |
Scenario: Filter completed items with multiple completed items
When I create a new todo item with text "Go for a run"
And I create a new todo item with text "Write code"
And I complete the todo item with text "Go for a run"
And I complete the todo item with text "Write code"
And I filter to see only completed items
Then I should see the following todo items:
| Go for a run |
| Write code |
Необходимые правки внесены. Настал момент запустить это в браузере!
4. Запустить тесты
Запуск BDD тестов не поддерживается в Playwright из коробки, хотя это один из самых популярных запросов. Для данной задачи я использую интеграцию playwright-bdd
. Все шаги и сценарии уже написаны, поэтому осталось добавить конфигурацию.
Для краткости я опущу установку зависимостей. Вы можете посмотреть готовый репозиторий на GitHub со всеми файлами из статьи. Попробуйте сгенерировать свои BDD сценарии для TodoList и запустить их на шагах из примера.
Конфигурация для Playwright следующая:
playwright.config.ts
import { defineConfig } from '@playwright/test';
import { defineBddConfig } from 'playwright-bdd';
const testDir = defineBddConfig({
paths: ['./features/todopage.feature'], // <- BDD сценарии
importTestFrom: 'steps/fixtures.ts', // <- описания шагов
});
export default defineConfig({
testDir,
reporter: 'html',
});
Файл fixtures.ts
подключает созданный ранее TodoPage
в виде фикстуры:
steps/fixtures.ts
import { test as base } from 'playwright-bdd';
import { TodoPage } from './TodoPage';
export const test = base.extend<{ todoPage: TodoPage }>({
todoPage: async ({ page }, use) => use(new TodoPage(page)),
});
Запускаем тесты:
npx bddgen && npx playwright test
Результат:
Running 4 tests using 1 worker
4 passed (2.7s)
To open last HTML report run:
npx playwright show-report
Все тесты прошли! Ура ?
HTML отчёт содержит детали по каждому сценарию:
5. Подвести итог
Я доволен полученным результатом. Да, пришлось корректировать ответы ChatGPT, но на это ушло гораздо меньше времени, чем если бы я писал этот код вручную. Мне нравится такой способ написания тестов — не тот монотонный процесс, про который в некоторых командах иногда забивают забывают. Это современный вариант парного программирования, когда твой партнёр — нейросеть. Она не идеальная и может ошибаться, зато очень исполнительная, невероятно начитанная и готова с энтузиазмом браться за любые задачи!
BDD-формат отлично подходит для AI-генерации. Он понятный и легко читаемый. Нейросеть собирает шаги в логически правильные цепочки, а человек быстро валидирует результат и находит ошибки. При этом формат технический, сценарии можно сразу запускать в реальном браузере, используя Playwright и другие инструменты.
Уверен, есть еще много способов улучшения этого процесса. Поделитесь вашим опытом в комментариях.
Благодарю за внимание и зелёных вам тестов ❤️