В своих текущих проектах я следую подходу Разработка на основе поведения (BDD) для автоматизированного сквозного тестирования. Раньше я довольно скептически относился к синтаксису Дано-Когда-То, но сейчас активно его использую. Основная причина — я генерирую BDD-сценарии с помощью ChatGPT, а не пишу их вручную 😎

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

Для демонстрации я буду использовать приложение TodoList, созданное командой Playwright. Это веб-страница со списком задач. Пользователи могут создавать, заполнять и фильтровать элементы. Конечная цель — покрыть это приложение сквозными тестами, написать минимум кода вручную и делегировать максимум функций ChatGPT. В идеале сгенерированные тесты должны запускаться и проходить без каких-либо изменений. Давайте разберемся, возможно ли это!

План

Мой список задач для руководства следующий:

  1. Определение пользовательской истории
  2. Создать определения шагов
  3. Создание сценариев BDD
  4. Выполнение тестов
  5. Резюме

1. Определите пользовательскую историю

Пользовательская история — краеугольный камень 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.

2. Создайте определения шагов

Определение шага — это реализация действия пользователя. Например:

Given I open TodoApp page

преобразуется в команду браузера:

await page.goto('https://demo.playwright.dev/todomvc/');

Or

When I click the button

преобразуется в:

await page.getByTestId('button').click();

Несколько определений шагов можно сгруппировать в Объектную модель страницы — класс, представляющий определенную страницу в тестовых сценариях.

Для списка дел мне нужен один класс TodoPage с методами для создания, завершения и фильтрации элементов. Проблема здесь в том, что определения шагов сильно зависят от структуры HTML страницы, поэтому я бы не стал делегировать это ИИ. Но... ChatGPT — идеальный кандидат для создания шаблона для класса.

В качестве результата я ожидаю, что код TypeScript, использующий пакеты NPM @playwright/test и playwright-bdd, позволит позже запускать эти тесты с помощью Playwright.

Первоначальное приглашение создать класс 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 и жду ответа... Я всегда чувствую себя немного загипнотизированным, пока генерируется код 😍

Полный ответ 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 сгенерировал правильные методы класса, пометил их декораторами и передал параметры там, где это необходимо.

Теперь я хочу упростить ответ. Вместо четырех отдельных методов утверждения я хочу использовать один, который сравнивает весь список. Это чище, чем проверять каждый элемент по отдельности. Я просто отправляю этот запрос в чат и получаю то, что мне нужно.

Второе приглашение:

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 может выдавать разные ответы, как человек! Я использую следующую стратегию:

  1. получить первоначальный ответ
  2. улучшить его с помощью последующих команд
  3. завершить его вручную

Это особенно актуально для генерации класса TodoPage — в любом случае мне еще нужно выполнить реализацию шагов.

2.1 Заполнение ступенчатых тел

Я могу писать тела шагов вручную, проверяя HTML с помощью инструментов разработчика. Однако моя цель — сгенерировать как можно больше кода. К счастью, в Playwright есть функция под названием codegen. Он записывает все действия на веб-странице и автоматически преобразует их в команды браузера.

Запуск режима кодирования:

npx playwright codegen https://demo.playwright.dev/todomvc

Браузер открывает предоставленный URL-адрес, и я выполняю необходимые действия. Например:

  1. создать несколько задач
  2. отметить их как выполненные
  3. фильтр

Сгенерированный код:

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.

В некоторых случаях требуется ручное редактирование. Например, заменю селектор page.locator('li') на более надежный page.getByTestId('todo-title').

Финальный TodoPage класс со всеми корректировками:

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 предлагает специальную команду CLI bddgen export. Эта команда собирает определения шагов из всех файлов и отображает их в текстовом формате в терминале.

Запустите команду и получите список шагов:

> 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:

Я выбираю и копирую эти шаги в свою подсказку.

Запрос для создания сценариев 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 правильно использует синтаксис Дано-Когда-То, генерирует осмысленные сценарии и применяет только предусмотренные шаги.

Как и раньше, я хочу улучшить результат:

  1. Используйте ключевое слово Background для общих шагов — оно работает как beforeEach().
  2. Удалите [x] из текста элемента — иначе утверждение текста не удастся.
  3. Удалите заголовок Todo Text — он лишний, так как столбец только один.

Я просто прошу ChatGPT сделать это.

Второе приглашение:

* 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 со всеми файлами из статьи. Вы можете попросить ChatGPT создать собственные сценарии BDD для TodoList и запустить их в примере.

Конфигурация драматурга следующая:

// playwright.config.ts
import { defineConfig } from '@playwright/test';
import { defineBddConfig } from 'playwright-bdd';

const testDir = defineBddConfig({
  paths: ['./features/todopage.feature'], // <- points to BDD scenarios
  importTestFrom: 'steps/fixtures.ts',    // <- points to step definitions
});

export default defineConfig({
  testDir,
  reporter: 'html',
});

Файл Fixtures, импортирующий класс 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 оказывается идеальным форматом для создания с помощью ИИ. Он понятен и читабелен для человека. ChatGPT выстраивает шаги в правильные логические цепочки, и человек легко проверяет результат и находит ошибку. В то же время сценарии BDD достаточно техничны, чтобы их можно было выполнять в реальном браузере с помощью Playwright и других инструментов.

Я считаю, что есть много способов улучшить этот процесс. Не стесняйтесь поделиться своим опытом в комментариях!

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

Эта статья изначально была опубликована на dev.to