Step definitions

Step definitions — это ядро автоматизированного тестирования в связке Protractor и Cucumber. Они представляют собой конкретные реализации шагов, описанных в Gherkin-файлах (.feature), и обеспечивают связь между естественно-языковым описанием сценариев и действиями в браузере.

Структура Step Definition

Каждый step definition файл обычно создается в директории step_definitions и содержит один или несколько методов, соответствующих ключевым словам Gherkin: Given, When, Then, And, But.

const { Given, When, Then } = require('@cucumber/cucumber');

Given('открыта страница {string}', async function (url) {
    await browser.get(url);
});

When('пользователь вводит {string} в поле {string}', async function (value, field) {
    const input = element(by.name(field));
    await input.sendKeys(value);
});

Then('отображается сообщение {string}', async function (expectedMessage) {
    const message = element(by.css('.alert'));
    const text = await message.getText();
    if (text !== expectedMessage) {
        throw new Error(`Ожидалось "${expectedMessage}", но получено "${text}"`);
    }
});

Ключевые моменты:

  • Каждый шаг должен быть асинхронным, поскольку действия с браузером возвращают промисы.
  • Аргументы шага передаются через {string}, {int} и регулярные выражения.
  • Ошибки внутри шага приводят к падению теста, что обеспечивает точное выявление проблем.

Аргументы и регулярные выражения

Step definitions поддерживают гибкую передачу данных из сценариев. Помимо стандартных {string} и {int}, можно использовать регулярные выражения для более сложных совпадений:

When(/^пользователь вводит (\d+) в поле "(.+)"$/, async function (number, field) {
    const input = element(by.name(field));
    await input.sendKeys(number);
});

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

Взаимодействие с элементами

Protractor предоставляет мощные селекторы для поиска элементов на странице. В step definitions чаще всего используются:

  • element(by.css('selector')) — поиск по CSS-селектору.
  • element(by.id('id')) — поиск по ID.
  • element(by.name('name')) — поиск по атрибуту name.
  • element.all(by.css('selector')) — коллекции элементов.

Примеры:

When('пользователь кликает по кнопке {string}', async function (buttonText) {
    const button = element(by.buttonText(buttonText));
    await button.click();
});

Then('отображается {int} элементов с классом {string}', async function (count, className) {
    const elements = element.all(by.css(`.${className}`));
    const actualCount = await elements.count();
    if (actualCount !== count) {
        throw new Error(`Ожидалось ${count} элементов, но найдено ${actualCount}`);
    }
});

Повторное использование шагов

Step definitions можно организовывать так, чтобы одни и те же шаги использовались в разных сценариях. Для этого создаются универсальные функции:

async function login(user, password) {
    await element(by.name('username')).sendKeys(user);
    await element(by.name('password')).sendKeys(password);
    await element(by.css('button[type="submit"]')).click();
}

Given('пользователь вошел с логином {string} и паролем {string}', async function (user, password) {
    await login(user, password);
});

Такой подход повышает читаемость и снижает дублирование кода.

Обработка ожиданий

Protractor интегрирован с WebDriver и поддерживает ожидания (ExpectedConditions), что критично для надежных тестов:

const EC = protractor.ExpectedConditions;

Then('кнопка {string} становится кликабельной', async function (buttonText) {
    const button = element(by.buttonText(buttonText));
    await browser.wait(EC.elementToBeClickable(button), 5000, 'Кнопка не стала кликабельной');
    await button.click();
});

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

Локализация и многоязычные сценарии

Step definitions можно локализовать, создавая файлы с переводами или используя регулярные выражения для поддержки нескольких языков:

Given(/^(?:открыта|opened) страница (.+)$/, async function (url) {
    await browser.get(url);
});

Это позволяет использовать один и тот же набор step definitions для сценариев на разных языках.

Организация и структура файлов

  • Каждый логический блок функционала рекомендуется помещать в отдельный файл step definitions.
  • В проекте может быть несколько файлов: login_steps.js, cart_steps.js, checkout_steps.js.
  • Важно избегать дублирования шагов, чтобы поддерживать DRY-принцип (Don’t Repeat Yourself).

Асинхронность и промисы

Все действия с браузером должны использовать async/await. Прямое использование промисов с .then() в современных версиях Protractor считается устаревшим и усложняет код.

When('пользователь очищает поле {string}', async function (field) {
    const input = element(by.name(field));
    await input.clear();
});

await гарантирует последовательное выполнение шагов и корректное завершение теста.


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