Page Object – поширений design pattern, під час написання автоматичних тестів для WEB UI. Суть полягає у відокремленні коду низькорівневої логіки взаємодії зі сторінками тестованого додатку, від коду логіки тестів:

  • для кожної сторінки створюється окремий клас, котрий інкапсулює опис елементів (локатори) та методи для взаємодії з елементами
  • тести взаємодіють зі сторінками тільки через об’єкти класів сторінок
  • завдяки тому, що сторінка описується тільки в одному місці, зменшується дублювання коду, полегшується підтримка, в разі зміни локатора або логіки взаємодії зі сторінкою

В цій нотатці я створю простий приклад Page Object з використанням бібліотеки Selenide. Ознайомлювальна з бібліотекою нотатка доступна за посиланням:

Selenide – простий приклад написання автотесту

Кроки тесту:

  1. Відкрити сторінку авторизації на демо сайті за адресою https://demoqa.com/login
  2. Ввести коректні дані користувача та натиснути Login
  3. Після авторизації, на сторінці профілю перевірити відображення username (в цьому вигаданому тесті, саме це буде вважатися успішною авторизацією)

Реалізація

Клас User, звичайний Value Object, з полями username та password, значення котрих будуть використовуватись для авторизації:

package wiki.it.notes.selenide.pageobject.bookstore.models;

public record User(String username, String password) {}

Клас LoginPage, містить поля з локаторами елементів форми для авторизації та метод loginToProfile:

package wiki.it.notes.selenide.pageobject.bookstore.pages;

import wiki.it.notes.selenide.pageobject.bookstore.models.User;

import static com.codeborne.selenide.Selenide.*;

public class LoginPage {

    public final static String URL = "login";

    private final String USERNAME_FIELD = "#userName";
    private final String PASSWORD_FIELD = "#password";
    private final String LOGIN_BUTTON = "#login";

    public ProfilePage loginToProfile(User user) {
        $(USERNAME_FIELD).setValue(user.username());
        $(PASSWORD_FIELD).setValue(user.password());
        $(LOGIN_BUTTON).click();
        
        return page(ProfilePage.class);
    }
}

Слід звернути увагу, що метод loginToProfile, після виконання котрого ми повинні опинитися на сторінці профілю, одразу повертає об’єкт сторінки ProfilePage.

Клас ProfilePage містить метод getUsername, для отримання тексту з елементу, котрий відображає username користувача:

package wiki.it.notes.selenide.pageobject.bookstore.pages;

import static com.codeborne.selenide.Selenide.$;

public class ProfilePage {

    public final static String URL = "profile";
    
    private final String USERNAME_VALUE = "#userName-value";

    public String getUsername() {
        return $(USERNAME_VALUE).text();
    }
}

Базовий тестовий клас містить метод setupSuite, де задається базовий url:

package wiki.it.notes.selenide.pageobject.bookstore;

import com.codeborne.selenide.Configuration;
import org.testng.annotations.BeforeSuite;

public abstract class BaseTest {

    @BeforeSuite
    void setupSuite() {
        Configuration.baseUrl = "https://demoqa.com/";
    }
}

Клас LoginTest з тестом successLoginTest:

package wiki.it.notes.selenide.pageobject.bookstore;

import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import wiki.it.notes.selenide.pageobject.bookstore.models.User;
import wiki.it.notes.selenide.pageobject.bookstore.pages.LoginPage;

import static com.codeborne.selenide.Selenide.open;
import static org.assertj.core.api.Assertions.assertThat;

public class LoginTest extends BaseTest {

    private User user;

    @BeforeClass
    void setupClass() {
        user = new User("it-notes", "Aqa12345*");
    }

    @Test
    void successLoginTest() {
        var profilePage = open(LoginPage.URL, LoginPage.class).loginToProfile(user);

        assertThat(profilePage.getUsername())
                .as("Check username on profile page")
                .isEqualTo(user.username());
    }
}

Взаємодія тесту зі сторінками сайту відбувається через об’єкти Page класів. В якості assert використовується бібліотека assertJ.

Код з нотатки можна також побачити на GitHub:

Selenide page object simple example