Создание своего элемента

Пример 11

Теперь можно рассмотреть создание своего собственного элемента.

Допустим, нам нужно проверить форму, в которой определённые поля являются обязательными. Таким полем является поле "Login" в уже рассмотренной выше форме. В нашем примере требуется проверить, что пустое поле после нажатия Submit выводит под самим полем сообщение "This field is required."

Создание элемента с обязательным полем

1. Создание класса RequiredTextField

Первое, что нужно сделать — создать класс RequiredTextField и отнаследоваться от нативного класса TextField. Таким образом, мы получим доступ сразу ко всем свойствам и автоматически логирующимся шагам оригинального поля.

public class RequiredTextField extends TextField {

    protected By errorMessageLocator;

    // Default конструктор обязателен для создания экземпляров с помощью аннотации '@Locator'
    public RequiredTextField() {
        super();
        setUiElementType("required input text field");
    }

    public RequiredTextField(By rootLocator) {
        super(rootLocator);
        // Если не указать custom type name, будет использовано значение "input text field"
        setUiElementType("required input text field");
    }

    public boolean isErrorMessageShown() {
        return getRoot().parent().$(".error-message").isDisplayed();
    }

    @Step("Assert that, the requited field message '{message}' shown")
    public void assertWarningIsShown(String message) {
        Assertions.assertThat(isErrorMessageShown()).as("Requited field message").isTrue();
        Assertions.assertThat(getRoot().parent().$(".error-message").text())
                  .as("Error Message").isEqualTo(message);
    }
}

Объявление в классе формы

При объявлении элемента можно задать локатор через конструктор или через аннотацию @Locator. Например:

@Name("Login")
protected RequiredTextField fieldLogin = new RequiredTextField(By.cssSelector("#login"));

Либо с аннотацией:

@Name("Login")
@Locator(css = "#login")
protected RequiredTextField fieldLogin;

Метод setUiElementType позволяет переопределить имя типа элемента, которое будет отображаться в отчёте. Если этого не сделать, будет использовано унаследованное имя "input text field".

При вызове унаследованных шагов (например, write, clear, assertCurrentValue) отчёт логирует шаги, а новый кастомный ассерт assertWarningIsShown(String message) логируется через аннотацию @Step.

Сценарий теста

@Test
@DisplayName("Create custom 'Required' text field")
public void makeNewElementRequitedField() {
    UiSteps.openBrowser(formPageUrl);
    formPage.fieldEmail().write("john.doe@gmail.com");
    formPage.fieldPassword().write("Password12345!");
    formPage.fieldRank().write("10");
    formPage.fieldDate().clearAndWrite("11.11.2011");
    formPage.fieldTelephone().write("199887688");
    formPage.radioBtnMale().click();
    formPage.ddExperience().select("2 years");
    formPage.btnSubmit().click();
    formPage.fieldLogin().assertWarningIsShown("This field is required.");
    formPage.fieldLogin().write("John");
    formPage.btnSubmit().click();
}

Запускаем тест, ждём и смотрим отчёт:

Отчёт: Required TextField

Наследование от AbstractRequiredTextField

Выше мы рассмотрели самый универсальный метод создания нового элемента путём наследования от уже существующего. Помимо этого, фреймворк содержит набор абстрактных классов, которые можно назвать шаблонами для построения элементов и виджетов. Таким образом можно создать новый элемент, наследуясь от абстрактного класса AbstractRequiredTextField, который содержит набор абстрактных методов. И уже содержит частично или почти всю необходимую логику. Пример абстрактного класса:

public abstract class AbstractRequiredTextField extends TextField {

    public AbstractRequiredTextField() {
        setUiElementType(ElementType.REQUIRED_TEXTFIELD.getType());
    }

    public abstract boolean isMarked();

    public void assertMarkedAsRequired() {
        Assertions.assertThat(isMarked()).as("Requited field message").isTrue();
    }

    public void assertNotMarkedAsRequired() {
        Assertions.assertThat(isMarked()).as("Requited field message").isFalse();
    }
}

Создадим новый класс ReqTextField, отнаследованный от AbstractRequiredTextField:

public class ReqTextField extends AbstractRequiredTextField {

    public ReqTextField() {
        super();
    }

    public ReqTextField(String selenideLocator) {
        super(selenideLocator);
    }

    @Override
    public boolean isMarked() {
        return getRoot().parent().$(".error-message").isDisplayed();
    }
}

Теперь в тесте вызовем метод assertMarkedAsRequired() вместо assertWarningIsShown:

@Test
@DisplayName("Create custom 'Required' text field")
public void makeNewElementRequitedField() {
    UiSteps.openBrowser(formPageUrl);
    formPage.fieldEmail().write("john.doe@gmail.com");
    formPage.fieldPassword().write("Password12345!");
    formPage.fieldRank().write("10");
    formPage.fieldDate().clearAndWrite("11.11.2011");
    formPage.fieldTelephone().write("199887688");
    formPage.radioBtnMale().click();
    formPage.ddExperience().select("2 years");
    formPage.btnSubmit().click();
    formPage.fieldLogin().assertMarkedAsRequired();
    formPage.fieldLogin().write("John");
    formPage.btnSubmit().click();
}

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