Переходы по выпадающему меню навигации

Пример 3

Теперь давайте рассмотрим, как можно реализовать переходы по меню навигации с несколькими выпадающими саб-меню. На этом примере мы разберём, как работать с группами элементов, объединёнными в виджеты.

Нам понадобится описать меню навигации, располагающееся вверху страницы, и поместить его в уже созданный PageObject FormPage.

Переходы по выпадающему меню навигации

Работающая навигация в Iframe ниже



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

Вариант на Selenide

1. Описываем панель меню навигации в классе TopBar:

@Getter
@Accessors(fluent = true)
public class TopBar {

    protected SelenideElement mainItem1 = $x("//ul[@class='menu']/li[1]").as("Main Item 1");
    protected SelenideElement mainItem2 = $x("//ul[@class='menu']/li[2]").as("Main Item 2");
    protected SelenideElement mainItem3 = $x("//ul[@class='menu']/li[3]").as("Main Item 3");
    protected SelenideElement mainItem4 = $x("//ul[@class='menu']/li[4]").as("Main Item 4");
    protected Level1SubMenu level1SubMenu = new Level1SubMenu();

    @Getter
    @Accessors(fluent = true)
    public static class Level1SubMenu {
        ElementsCollection items = $$x("//ul[@class='menu']/li[4]/ul/li")
                .as("Level 1 sub menu items");
        Level2SubMenu level2SubMenu = new Level2SubMenu();
    }

    @Getter
    @Accessors(fluent = true)
    public static class Level2SubMenu {
        ElementsCollection items = $$x("//ul[@class='menu']/li[4]/ul/li[3]/ul/li")
                .as("Level 2 sub menu items");
        Level3SubMenu level3SubMenu = new Level3SubMenu();
    }

    @Getter
    @Accessors(fluent = true)
    public static class Level3SubMenu {
        ElementsCollection items = $$x("//ul[@class='menu']/li[4]/ul/li[3]/ul/li[3]/ul/li")
                .as("Level 3 sub menu items");
        Level4SubMenu level4SubMenu = new Level4SubMenu();
    }

    @Getter
    @Accessors(fluent = true)
    public static class Level4SubMenu {
        ElementsCollection items = $$x("//ul[@class='menu']/li[4]/ul/li[3]/ul/li[3]/ul/li[3]/ul/li")
                .as("Level 4 sub menu items");
        Level5SubMenu level5SubMenu = new Level5SubMenu();
    }

    @Getter
    @Accessors(fluent = true)
    public static class Level5SubMenu {
        ElementsCollection items = $$x("//ul[@class='menu']/li[4]/ul/li[3]/ul/li[3]/ul/li[3]/ul/li[3]/ul/li")
                .as("Level 5 sub menu items");
    }
}

2. Создаём экземпляр в Page Object:

@PageObject
@Getter
@Accessors(fluent = true)
public class FormPage extends Page {

    protected TopBar topBar = new TopBar();
    protected SelenideElement fieldLogin = $("#login").as("Login");
    protected SelenideElement fieldEmail = $("#email").as("Email");
    protected SelenideElement fieldPassword = $("#password").as("Password");
    protected SelenideElement fieldRank = $("#rank").as("protected");
    protected SelenideElement fieldDate = $x("//input[@id='date']").as("Date");
    protected SelenideElement fieldTelephone = $("#tel").as("Telephone");
    protected SelenideElement uploadAvatar = $("#file").as("Avatar");
    protected SelenideElement radioBtnMale = $("#male").as("Gender Male");
    protected SelenideElement ckbMorning = $("#checkbox1").as("Preferable time - Morning");
    protected SelenideElement ckbEvening = $("#checkbox2").as("Preferable time - Evening");
    protected SelenideElement ddExperience = $("#experience").as("Experience");
    protected SelenideElement selectWorkingDays = $("#multiple-select").as("Working Days");
    protected SelenideElement btnReset = $(".btn-secondary").as("Reset");
    protected SelenideElement btnSubmit = $(".btn-primary").as("Submit");
}

3. Пишем тестовый сценарий:

@Test
@Feature("Multilevel top menu")
@DisplayName("User explores top multilevel menu")
public void multiLevelMenuNavigation() {
    Selenide.open(formPageUrl);
    formPage.topBar().mainItem4().hover();
    formPage.topBar().level1SubMenu().items().filter(Condition.text("Level 1 Item 3")).first().hover();
    formPage.topBar().level1SubMenu().level2SubMenu().items().filter(Condition.text("Level 2 Item 3")).first().hover();
    formPage.topBar()
            .level1SubMenu()
            .level2SubMenu()
            .level3SubMenu()
            .items().filter(Condition.text("Level 3 Item 3")).first().hover();
    formPage.topBar()
            .level1SubMenu()
            .level2SubMenu()
            .level3SubMenu()
            .level4SubMenu()
            .items().filter(Condition.text("Level 4 Item 3")).first().hover();
    formPage.topBar()
            .level1SubMenu()
            .level2SubMenu()
            .level3SubMenu()
            .level4SubMenu()
            .level5SubMenu()
            .items().filter(Condition.text("Level 5 Item 3")).first().hover();
}

Неочень красиво, но терпимо. Смотрим отчёт Allure:

Отчёт Selenide: Multilevel Menu

Вариант на Allurium

Теперь сделаем то же самое с Allurium.

1. Описываем класс панели TopBar:

@Widget
@Getter
@Accessors(fluent = true)
public class TopBar extends AbstractWidget {

    @Name("Main Item 1")
    @Locator(xpath = "//ul[@class='menu']/li[1]")
    protected MenuItem mainItem1;

    @Name("Main Item 2")
    @Locator(xpath = "//ul[@class='menu']/li[2]")
    protected MenuItem mainItem2;

    @Name("Main Item 3")
    protected MenuItem mainItem3 = MenuItem.$menuItem("//ul[@class='menu']/li[3]");

    @Name("Main Item 4")
    protected MenuItem mainItem4 = _$menuItem("//ul[@class='menu']/li[4]");

    @Name("Level 1 sub menu")
    protected Level1SubMenu level1SubMenu = new Level1SubMenu();

    @Widget
    @Getter
    @Accessors(fluent = true)
    public static class Level1SubMenu extends AbstractWidget {

        @Name("Level 1 sub menu items")
        @ListLocator(xpath = "//ul[@class='menu']/li[4]/ul/li")
        protected ListWC items = new ListWC<>();

        @Name("Level 2 sub menu")
        protected Level2SubMenu level2SubMenu = new Level2SubMenu();
    }

    @Widget
    @Getter
    @Accessors(fluent = true)
    public static class Level2SubMenu extends AbstractWidget {

        @Name("Level 2 sub menu items")
        @ListLocator(xpath = "//ul[@class='menu']/li[4]/ul/li[3]/ul/li")
        protected ListWC items = new ListWC<>();

        @Name("Level 3 sub menu")
        protected Level3SubMenu level3SubMenu = new Level3SubMenu();
    }

    @Widget
    @Getter
    @Accessors(fluent = true)
    public static class Level3SubMenu extends AbstractWidget {

        @Name("Level 3 sub menu items")
        @ListLocator(xpath = "//ul[@class='menu']/li[4]/ul/li[3]/ul/li[3]/ul/li")
        protected ListWC items = new ListWC<>();

        @Name("Level 4 sub menu")
        protected Level4SubMenu level4SubMenu = new Level4SubMenu();
    }

    @Widget
    @Getter
    @Accessors(fluent = true)
    public static class Level4SubMenu extends AbstractWidget {

        @Name("Level 4 sub menu items")
        @ListLocator(xpath = "//ul[@class='menu']/li[4]/ul/li[3]/ul/li[3]/ul/li[3]/ul/li")
        protected ListWC items = new ListWC<>();

        @Name("Level 5 sub menu")
        protected Level5SubMenu level5SubMenu = new Level5SubMenu();
    }

    @Widget
    @Getter
    @Accessors(fluent = true)
    public static class Level5SubMenu extends AbstractWidget {

        @Name("Level 5 sub menu items")
        @ListLocator(xpath = "//ul[@class='menu']/li[4]/ul/li[3]/ul/li[3]/ul/li[3]/ul/li[3]/ul/li")
        protected ListWC items = new ListWC<>();
    }
}

2. Создаём экземпляр в Page Object:

@PageObject
@Getter
@Accessors(fluent = true)
public class FormPage extends Page {

    @Name("Top Bar")
    protected TopBar topBar = new TopBar();

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

    @Name("Email")
    @Locator(css = "#email")
    protected TextField fieldEmail;

    @Name("Password")
    @Locator(css = "#password")
    protected TextField fieldPassword;

    @Name("Rank")
    protected TextField fieldRank = $textField("#rank");

    // ... остальные поля ...
}

3. Пишем тестовый сценарий для Allurium:

@Test
@Feature("Multilevel top menu")
@DisplayName("User explores top multilevel menu")
public void multiLevelMenuNavigation() {
    UiSteps.openBrowser(formPageUrl);
    formPage.topBar().mainItem4().hover();
    formPage.topBar().level1SubMenu().items().get("Level 1 Item 3").hover();
    formPage.topBar().level1SubMenu().level2SubMenu().items().get("Level 2 Item 3").hover();
    formPage.topBar().level1SubMenu().level2SubMenu().level3SubMenu().items().get("Level 3 Item 3").hover();
    formPage.topBar().level1SubMenu().level2SubMenu().level3SubMenu().level4SubMenu().items().get("Level 4 Item 3").hover();
    formPage.topBar().level1SubMenu().level2SubMenu().level3SubMenu().level4SubMenu().level5SubMenu().items().get("Level 5 Item 3").click();
}

Смотрим отчёт Allure:

Отчёт Allurium: Multilevel Menu

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