Таблицы данных в scenarios

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

Основы работы с таблицами данных

В Protractor таблицы данных обычно реализуются в виде массивов объектов JavaScript или внешних файлов (JSON, CSV, Excel), которые затем импортируются в тесты. Такой подход обеспечивает отделение данных от логики теста, что упрощает поддержку и расширение сценариев.

Пример простой таблицы данных:

const loginData = [
  { username: 'user1', password: 'pass1', expectedResult: 'success' },
  { username: 'user2', password: 'wrongpass', expectedResult: 'failure' },
  { username: '', password: '', expectedResult: 'failure' }
];

Каждый объект в массиве соответствует одной комбинации данных для теста.

Интеграция таблиц данных с it и forEach

Для применения таблиц данных в сценариях используется перебор массива с генерацией тестов динамически. Это позволяет создавать параметризованные тесты без дублирования кода.

loginData.forEach(data => {
  it(`should login with username: ${data.username}`, async () => {
    await element(by.id('username')).sendKeys(data.username);
    await element(by.id('password')).sendKeys(data.password);
    await element(by.id('loginButton')).click();

    if (data.expectedResult === 'success') {
      expect(await element(by.id('welcomeMessage')).isPresent()).toBe(true);
    } else {
      expect(await element(by.id('errorMessage')).isPresent()).toBe(true);
    }
  });
});

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

Использование внешних файлов

Для больших проектов часто применяются внешние файлы с данными. Наиболее популярны форматы JSON и CSV.

JSON пример:

loginData.json

[
  { "username": "user1", "password": "pass1", "expectedResult": "success" },
  { "username": "user2", "password": "wrongpass", "expectedResult": "failure" }
]

Импорт в тест:

const loginData = require('./loginData.json');

loginData.forEach(data => {
  it(`should login with username: ${data.username}`, async () => {
    await element(by.id('username')).sendKeys(data.username);
    await element(by.id('password')).sendKeys(data.password);
    await element(by.id('loginButton')).click();

    if (data.expectedResult === 'success') {
      expect(await element(by.id('welcomeMessage')).isPresent()).toBe(true);
    } else {
      expect(await element(by.id('errorMessage')).isPresent()).toBe(true);
    }
  });
});

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

Организация сложных сценариев

Таблицы данных применяются не только для простых форм, но и для комплексных сценариев, где требуется несколько шагов с разными входными данными.

Пример сценария с формой регистрации:

const registrationData = [
  { name: 'Alice', email: 'alice@example.com', password: '12345', role: 'admin' },
  { name: 'Bob', email: 'bob@example.com', password: 'abcde', role: 'user' }
];

registrationData.forEach(data => {
  it(`should register user ${data.name} with role ${data.role}`, async () => {
    await element(by.id('name')).sendKeys(data.name);
    await element(by.id('email')).sendKeys(data.email);
    await element(by.id('password')).sendKeys(data.password);
    await element(by.id('role')).sendKeys(data.role);
    await element(by.id('registerButton')).click();

    const successMessage = await element(by.id('successMessage')).getText();
    expect(successMessage).toContain(data.name);
  });
});

Преимущество: один сценарий охватывает множество комбинаций данных, сокращая количество повторяющихся тестов и повышая читаемость кода.

Динамическая генерация данных

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

function generateRandomUser() {
  const id = Math.floor(Math.random() * 1000);
  return { username: `user${id}`, password: `pass${id}`, expectedResult: 'success' };
}

const dynamicData = Array.from({ length: 5 }, generateRandomUser);

dynamicData.forEach(data => {
  it(`should login with dynamically generated user: ${data.username}`, async () => {
    await element(by.id('username')).sendKeys(data.username);
    await element(by.id('password')).sendKeys(data.password);
    await element(by.id('loginButton')).click();

    expect(await element(by.id('welcomeMessage')).isPresent()).toBe(true);
  });
});

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

Связь таблиц данных с Page Object

Для улучшения структуры тестов таблицы данных часто комбинируются с Page Object Model (POM). Это позволяет отделить логику взаимодействия с интерфейсом от данных теста.

Пример использования Page Object с таблицей данных:

loginPage.js

class LoginPage {
  constructor() {
    this.usernameField = element(by.id('username'));
    this.passwordField = element(by.id('password'));
    this.loginButton = element(by.id('loginButton'));
    this.welcomeMessage = element(by.id('welcomeMessage'));
    this.errorMessage = element(by.id('errorMessage'));
  }

  async login(username, password) {
    await this.usernameField.sendKeys(username);
    await this.passwordField.sendKeys(password);
    await this.loginButton.click();
  }

  async isSuccess() {
    return this.welcomeMessage.isPresent();
  }

  async isFailure() {
    return this.errorMessage.isPresent();
  }
}

module.exports = new LoginPage();

login.spec.js

const loginData = require('./loginData.json');
const loginPage = require('./loginPage');

loginData.forEach(data => {
  it(`should login with username: ${data.username}`, async () => {
    await loginPage.login(data.username, data.password);

    if (data.expectedResult === 'success') {
      expect(await loginPage.isSuccess()).toBe(true);
    } else {
      expect(await loginPage.isFailure()).toBe(true);
    }
  });
});

Использование POM вместе с таблицами данных делает код чистым, читаемым и легко расширяемым.

Практические рекомендации

  • Для небольших наборов данных достаточно массивов объектов внутри тестового файла.
  • Для крупных проектов следует использовать внешние файлы JSON или CSV, чтобы облегчить поддержку.
  • Для сложных сценариев с множеством шагов рекомендуется объединять таблицы данных с Page Object.
  • Динамическая генерация данных подходит для нагрузочного тестирования или случаев, когда уникальные данные обязательны.
  • Всегда следить за корректной обработкой ошибок и исключений, чтобы тесты не ломались при некорректных данных.

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