Ответ
Я бы разбил страницу на главный класс YandexMainPage и, при необходимости, вложенные классы для компонентов. Вот реализация с использованием Selenide (более лаконичный аналог Selenium для Java), который я часто применяю в проектах.
1. Базовый класс страницы:
import com.codeborne.selenide.SelenideElement;
import static com.codeborne.selenide.Selenide.*;
import static com.codeborne.selenide.Condition.*;
public class YandexMainPage {
// Локаторы элементов страницы
private SelenideElement searchInput = $("input[name='text']");
private SelenideElement searchButton = $("button[type='submit']");
private SelenideElement imagesLink = $x("//a[contains(text(),'Картинки')]");
private SelenideElement suggestPopup = $("div[role='listbox']");
// Компонент: блок сервисов (можно вынести в отдельный класс)
private ServicesBlock servicesBlock = new ServicesBlock();
// Методы для взаимодействия с элементами
public YandexMainPage open() {
open("https://ya.ru");
return this;
}
public YandexSearchResultsPage searchFor(String query) {
searchInput.setValue(query);
searchButton.click();
// Возвращаем объект следующей страницы (Page Object)
return page(YandexSearchResultsPage.class);
}
public YandexImagesPage goToImages() {
imagesLink.click();
return page(YandexImagesPage.class);
}
public void verifySuggestIsVisible() {
suggestPopup.shouldBe(visible);
}
// Внутренний класс для компонента "Сервисы"
public class ServicesBlock {
private SelenideElement marketLink = $("a[data-id='market']");
private SelenideElement mapsLink = $("a[data-id='maps']");
public void goToMarket() {
marketLink.click();
switchTo().window(1); // Переключение на новую вкладку
}
public void goToMaps() {
mapsLink.click();
}
}
// Геттер для доступа к компоненту из тестов
public ServicesBlock services() {
return servicesBlock;
}
}
2. Пример теста, использующего этот Page Object:
import org.junit.jupiter.api.Test;
import static com.codeborne.selenide.Condition.*;
public class YandexSearchTest {
@Test
public void userCanSearchFromMainPage() {
YandexMainPage mainPage = new YandexMainPage().open();
// Используем метод поиска, который возвращает следующую страницу
YandexSearchResultsPage resultsPage = mainPage.searchFor("Selenium testing");
// Проверяем результаты на новой странице
resultsPage.getFirstResult().shouldHave(text("Selenium"));
}
@Test
public void userCanNavigateToServices() {
YandexMainPage mainPage = new YandexMainPage().open();
// Взаимодействуем с компонентом через геттер
mainPage.services().goToMarket();
// ... дальнейшие проверки на странице Маркета
}
}
Ключевые принципы, которые я соблюдаю:
- Инкапсуляция: Все локаторы и низкоуровневые методы взаимодействия (
click,setValue) скрыты внутри класса страницы. - Возвращение других Page Object: Методы, ведущие на другую страницу (например,
searchFor), возвращают объект этой новой страницы. - Композиция: Сложные повторяющиеся блоки (хедер, футер, виджеты) выносятся в отдельные классы-компоненты.
- Удобство для тестов: API Page Object должен быть читаемым и отражать действия пользователя (
mainPage.searchFor("query")).