Структурирование тестов

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

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

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

  • tests/ – директория, в которой находятся все тесты.
  • tests/example.spec.ts – отдельный тестовый файл, описывающий конкретный сценарий.
  • tests/pages/ – директория для страниц, которые используются в тестах.
  • tests/utils/ – утилитарные функции и вспомогательные скрипты.
  • tests/data/ – тестовые данные.

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

Использование Page Object Model (POM)

Page Object Model (POM) — это шаблон проектирования, который способствует упрощению тестов, делая их более читаемыми и поддерживаемыми. В рамках POM каждый экран или компонент приложения представляется отдельным объектом, что помогает централизовать взаимодействие с элементами страницы.

Каждый Page Object содержит методы для взаимодействия с элементами на странице и представление состояния страницы. Например, для страницы входа можно создать класс с методами для ввода данных в поля и клика по кнопке “Войти”.

Пример структуры для POM:

  • pages/ — директория для файлов, представляющих страницы.

    • LoginPage.ts — объект страницы для входа.
    • DashboardPage.ts — объект страницы для главного экрана после входа.
// LoginPage.ts
class LoginPage {
  constructor(page) {
    this.page = page;
    this.usernameField = page.locator('#username');
    this.passwordField = page.locator('#password');
    this.loginButton = page.locator('#loginButton');
  }

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

module.exports = LoginPage;

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

Разделение тестов по функциональности

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

  • tests/auth.spec.ts — тесты для функционала аутентификации.
  • tests/cart.spec.ts — тесты для корзины товаров.
  • tests/profile.spec.ts — тесты для страницы профиля.

Этот подход позволяет локализовать ошибки и быстро понять, в какой части приложения произошла ошибка.

Параметризация тестов

Параметризация тестов позволяет запускать один и тот же тест с разными входными данными, что значительно повышает покрытие тестами и улучшает их повторяемость. В Playwright для этого можно использовать функцию test.each(), которая позволяет передавать набор данных в каждый запуск теста.

Пример параметризированного теста:

test.describe('Login tests', () => {
  test.each([
    ['user1', 'password1', 'Welcome user1'],
    ['user2', 'password2', 'Welcome user2']
  ])('should login with %s and show message %s', async (username, password, expectedMessage) => {
    const loginPage = new LoginPage(page);
    await loginPage.login(username, password);
    const message = await page.locator('#welcomeMessage').textContent();
    expect(message).toBe(expectedMessage);
  });
});

Этот подход уменьшает дублирование кода и делает тесты более гибкими и универсальными.

Использование beforeAll, afterAll, beforeEach, afterEach

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

  • beforeAll и afterAll выполняются до и после всех тестов в блоке, соответственно. Эти хуки полезны для настройки и очистки, которая должна быть выполнена только один раз.
  • beforeEach и afterEach выполняются до и после каждого теста в блоке, соответственно. Эти хуки полезны для настройки состояния перед каждым тестом.

Пример использования хуков:

let page;

beforeAll(async () => {
  const browser = await chromium.launch();
  page = await browser.newPage();
});

afterAll(async () => {
  await page.close();
});

test('should load login page', async () => {
  await page.goto('https://example.com/login');
  const title = await page.title();
  expect(title).toBe('Login - Example');
});

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

Организация тестовых данных

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

Например, можно хранить тестовые данные для входа в систему в формате JSON:

// tests/data/loginData.json
[
  { "username": "user1", "password": "password1" },
  { "username": "user2", "password": "password2" }
]

И затем использовать их в тестах:

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

test.each(loginData)('should login as %s', async (data) => {
  const loginPage = new LoginPage(page);
  await loginPage.login(data.username, data.password);
  const message = await page.locator('#welcomeMessage').textContent();
  expect(message).toBe(`Welcome ${data.username}`);
});

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

Использование асинхронных операций

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

Кроме того, важно правильно обрабатывать ошибки. Playwright предоставляет механизмы для работы с исключениями, что помогает избежать неявных сбоев в тестах.

try {
  await page.locator('#loginButton').click();
} catch (error) {
  console.error('Login button not found', error);
  throw error;
}

Логирование и отчеты

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

Пример простого логирования:

test('should display login page', async () => {
  console.log('Navigating to login page...');
  await page.goto('https://example.com/login');
  const title = await page.title();
  expect(title).toBe('Login - Example');
});

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

Поддержка различных сред

Если приложение поддерживает несколько сред (например, разработка, тестирование, продакшн), важно тестировать его в каждой из них. Playwright поддерживает настройку различных браузеров и конфигураций для работы с несколькими средами. Это можно реализовать с помощью переменных окружения или параметров в конфигурационных файлах.

test('should work in different environments', async () => {
  const baseUrl = process.env.BASE_URL || 'https://dev.example.com';
  await page.goto(baseUrl);
  const title = await page.title();
  expect(title).toBe('Example');
});

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

Заключение

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