Navigation Through Multilevel Dropdown Menu

Example 3

Now let’s see how to implement navigation through a menu with multiple dropdown submenus. In this example we will show how to work with groups of elements combined into widgets.

We need to describe the navigation menu located at the top of the page and place it into the already created PageObject FormPage.

Navigation Through Dropdown Menu

A working navigation in the iframe below:



In the form example we looked at simple elements (fields and buttons) and methods of interacting with them. However, almost every page in modern applications consists of dynamic groups of elements that can be classified as widgets.

A Selenide Version

1. Describe the navigation menu panel in the TopBar class:

@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. Create an instance in the 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. Write the test scenario:

@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();
}

Let's view the Allure report:

Selenide Report: Multilevel Menu

Allurium Version

Now we do the same with Allurium.

1. Describe the TopBar widget class:

@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. Create an instance in the 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");

    // ... the rest of fields ...
}

3. Write the Allurium test scenario:

@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();
}

Let's view the Allure report:

Allurium Report: Multilevel Menu

Here we immediately obtain a well-structured, readable report with a description of each element and the action performed on it.