Ранее мы уже разбирали Playwright в связке с Java.
В этой статье мы создадим с нуля автоматизированные тесты для демо-сайта Sauce Demo, используя Playwright для Java и лучшие инженерные практики.
Проектирование тестов: ️Page Object Model (POM)
Первый шаг к созданию поддерживаемых тестов — правильная архитектура. Page Object Model (POM) — это ключевой паттерн, который позволяет отделить логику тестов от деталей взаимодействия с элементами страницы. Каждая страница веб-приложения представляется в виде отдельного класса, который:
- Содержит локаторы элементов на этой странице.
- Инкапсулирует методы для действий пользователя (клик, ввод текста).
Это значительно снижает дублирование кода и упрощает поддержку: если изменится дизайн страницы, правки нужно будет внести только в одном классе Page Object.
Структура проекта для нашего примера с Sauce Demo будет выглядеть так:
src
├── main/java/com/saucedemo/pages/
│ ├── LoginPage.java // Страница логина
│ └── ProductsPage.java // Главная страница после входа
└── test/java/com/saucedemo/tests/
└── LoginTest.java // Наши тестовые сценарии
Реализация Page Objects для Sauce Demo
Вот как выглядят классы Page Object для сайта Sauce Demo. Этот код является рабочим и может быть скопирован в ваш проект.
1. LoginPage.java (Страница авторизации)
java:
package com.saucedemo.pages;
import com.microsoft.playwright.Page;
public class LoginPage {
private final Page page;
// 1. Объявляем локаторы элементов страницы
private final String inputUsername = "#user-name";
private final String inputPassword = "#password";
private final String buttonLogin = "#login-button";
private final String errorMessageContainer = ".error-message-container";
// Конструктор получает объект Page от Playwright
public LoginPage(Page page) {
this.page = page;
}
// 2. Метод для навигации на страницу логина
public void navigate() {
page.navigate("https://www.saucedemo.com/");
}
// 3. Основной метод для выполнения логина
public ProductsPage login(String username, String password) {
page.fill(inputUsername, username);
page.fill(inputPassword, password);
page.click(buttonLogin);
return new ProductsPage(page); // Возвращаем объект следующей страницы
}
// 4. Метод для получения текста ошибки (для негативных тестов)
public String getErrorMessage() {
return page.textContent(errorMessageContainer);
}
}
2. ProductsPage.java (Страница с товарами после успешного входа)
java:
package com.saucedemo.pages;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Locator;
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
public class ProductsPage {
private final Page page;
private final String labelTitle = ".title";
private final String buttonMenu = "#react-burger-menu-btn";
private final String linkLogout = "#logout_sidebar_link";
public ProductsPage(Page page) {
this.page = page;
}
// Проверяем, что заголовок страницы отображается корректно
public void verifyTitleIs(String expectedTitle) {
Locator title = page.locator(labelTitle);
assertThat(title).hasText(expectedTitle); // Используем умные ассерты Playwright
}
// Метод для выхода из системы
public void logout() {
page.click(buttonMenu);
page.click(linkLogout);
}
// Пример добавления товара в корзину
public void addFirstProductToCart() {
page.click("button:has-text('Add to cart'):near(#item_4_title_link)");
}
}
Пишем тесты с использованием JUnit 5
Playwright отлично интегрируется с популярными тестовыми фреймворками. Мы используем JUnit 5. Следующий тестовый класс демонстрирует как позитивные, так и негативные сценарии.
java:
package com.saucedemo.tests;
import com.microsoft.playwright.*;
import com.saucedemo.pages.LoginPage;
import com.saucedemo.pages.ProductsPage;
import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.*;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class LoginTest {
// Общие ресурсы для всех тестов в классе
static Playwright playwright;
static Browser browser;
// Изолированные ресурсы для каждого теста
BrowserContext context;
Page page;
LoginPage loginPage;
@BeforeAll
static void launchBrowser() {
playwright = Playwright.create();
browser = playwright.chromium().launch(
new BrowserType.LaunchOptions().setHeadless(false) // Установите true для CI
);
}
@AfterAll
static void closeBrowser() {
playwright.close();
}
@BeforeEach
void createContextAndPage() {
context = browser.newContext(); // Новый контекст для изоляции теста
page = context.newPage();
loginPage = new LoginPage(page);
loginPage.navigate();
}
@AfterEach
void closeContext() {
context.close();
}
@Test
@DisplayName("Успешный вход с валидными учетными данными")
void successfulLoginWithStandardUser() {
// Шаги теста, организованные через Page Objects
ProductsPage productsPage = loginPage.login("standard_user", "secret_sauce");
// Проверка (Assertion)
productsPage.verifyTitleIs("Products");
// Дополнительное действие
productsPage.addFirstProductToCart();
}
@Test
@DisplayName("Вход заблокированным пользователем показывает ошибку")
void loginWithLockedOutUserShowsError() {
// Выполняем действие, которое должно привести к ошибке
loginPage.login("locked_out_user", "secret_sauce");
// Проверяем, что сообщение об ошибке содержит ожидаемый текст
String errorText = loginPage.getErrorMessage();
assertTrue(errorText.contains("Sorry, this user has been locked out"));
}
}
Продвинутые техники и интеграция
Современный стиль с аннотацией @UsePlaywright
Playwright предлагает экспериментальную, но очень удобную интеграцию с JUnit, которая автоматически управляет жизненным циклом браузера и страницы.
import com.microsoft.playwright.junit.UsePlaywright;
import com.microsoft.playwright.Page;
import org.junit.jupiter.api.Test;
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
@UsePlaywright
public class ModernLoginTest {
@Test
void shouldLoginAndSeeProducts(Page page) { // Page инжектируется автоматически
LoginPage loginPage = new LoginPage(page);
loginPage.navigate();
ProductsPage productsPage = loginPage.login("standard_user", "secret_sauce");
// Использование встроенных ассертов Playwright
assertThat(page.locator(".title")).hasText("Products");
}
}
Параллельный запуск тестов
Чтобы ускорить прогон тестов, их можно запускать параллельно. Для этого в файл src/test/resources/junit-platform.properties нужно добавить конфигурацию:
junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.mode.default=same_thread
junit.jupiter.execution.parallel.mode.classes.default=concurrent
Настройка проекта (pom.xml)
Для сборки проекта необходим pom.xml файл.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.saucedemo</groupId>
<artifactId>playwright-java-demo</artifactId>
<version>1.0</version>
<dependencies>
<!-- Playwright -->
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<version>1.56.0</version> <!-- Актуальную версию смотрите на сайте -->
</dependency>
<!-- JUnit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.11.4</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Заключение и лучшие практики
- Всегда используйте POM: Это инвестиция в будущее, которая окупится при первом же изменении вёрстки сайта.
- Полагайтесь на auto-wait Playwright: Не используйте Thread.sleep(). Встроенные ожидания элемента — одна из сильнейших сторон фреймворка.
- Изолируйте тесты с помощью BrowserContext: Создание нового BrowserContext для каждого теста — залог их независимости и стабильности.
- Пишите атомарные тесты: Каждый тест должен проверять одну конкретную функциональность и быть независимым от других.
- Используйте продвинутые локаторы: Отдавайте предпочтение стабильным локаторам, таким как page.getByRole() или page.getByTestId(), вместо хрупких XPath.
Приведённые в статье примеры кода являются полноценными и готовыми к запуску. Они демонстрируют, как сочетание мощного API Playwright и правильных архитектурных решений позволяет создавать быстрые, надёжные и легко поддерживаемые автоматизированные тесты для современных веб-приложений.
Быстро изучить Playwright от "А" до "Я" на профессиональном уровне можно в этом курсе.