Handle Custom Dropdown With Selenium Java

Overview

Select item in Selenium Java is easy with support of three below methods:

+ selectByIndex (int index)

+ selectByValue (String value)

+ selectByVisibleText (String text)

In most cases, these methods are enough with default dropdown. But unfortunately, in real world application, the default select tag which browser renders is very ugly and developers will use their own define custom select. So how to handle this case?

Install

First create a MAVEN project with your favourite IDE (recommend Intelliji). Add below dependencies to your pom.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.tomatoqa</groupId>
    <artifactId>HowIsDisplayedWork</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>4.8.1</version>
        </dependency>

        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>7.7.1</version>
        </dependency>

        <dependency>
            <groupId>io.github.bonigarcia</groupId>
            <artifactId>webdrivermanager</artifactId>
            <version>5.3.2</version>
        </dependency>

    </dependencies>

</project>

Next, create a Demo.java file in src/test/java/ folder

Real Use Case

Let’s consider this example:

https://ericsson/en/blog

As we can see this custom select. They hide select tag and display custom dropdown instead. In this situation, there is hopeless if you try to interact with it as normal select.

How to handle custom dropdown

Let’s write a custom method for our use case:

protected void selectItemInCustomDropDown(WebDriver driver, String selectInput, String selectOption, String selectItem) throws InterruptedException {
    driver.findElement(By.cssSelector(selectInput)).click();
    Thread.sleep(1000);

    WebDriverWait explicitWait = new WebDriverWait(driver, Duration.ofSeconds(15));
    List<WebElement> elements = explicitWait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.cssSelector(selectOption)));

    for (WebElement element : elements)
    {
        if (element.getText().trim().equals(selectItem))
        {
            JavascriptExecutor jsExecutor = (JavascriptExecutor)driver;
            jsExecutor.executeScript("arguments[0].scrollIntoView({block: 'nearest', inline: 'nearest'})", element);
            Thread.sleep(1000);

            element.click();
            Thread.sleep(1000);
            break;
        }
    }
}

This method receives four params:

+ driver: instance of Web Driver

+ selectInput: the textbox of custom select.

+ selectOption: this is all options of the custom select. You will need to add explicit wait to wait for present of all these options in DOM

+ selectItem: the option you want to select.

Next, let’s break down our code:

driver.findElement(By.cssSelector(selectInput)).click();
Thread.sleep(1000);

=> As you can see, our custom dropdown has a textbox which need to be focused to make the dropdown list displayed

WebDriverWait explicitWait = new WebDriverWait(driver, Duration.ofSeconds(15));
List<WebElement> elements = explicitWait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.cssSelector(selectOption)));

=> Next, you will need to add a explicit wait to wait for all select option present in DOM. The until method will return a List collection contains all these select options as WebElement

or (WebElement element : elements)
{
    if (element.getText().trim().equals(selectItem))
    {
        JavascriptExecutor jsExecutor = (JavascriptExecutor)driver;
        jsExecutor.executeScript("arguments[0].scrollIntoView({block: 'nearest', inline: 'nearest'})", element);
        Thread.sleep(1000);

        element.click();
        Thread.sleep(1000);
        break;
    }
}

=> Lastly, you need a for loop to iterate through this collection. If there is any item have inner text matching to our **selectItem** params, you need to use javascript to scroll to this element and click to choose this element. Very simple, right?

Note that **scrollIntoView({block: ‘nearest’, inline: ‘nearest’})** is the trick here. In some situation, you may need to change this method to adapt to your requirements. Refer to this.

Now you only need to call it like below

  @Test
    public void TC_01() throws InterruptedException {
        String selectInput = "input[placeholder='Category']";
        String selectOption = "div#categoryList div.dropdown-option.multi";
        String selectItem = "6G";
        selectItemInCustomDropDown(driver, selectInput, selectOption, selectItem);

        Thread.sleep(5000);
    }

Let’s call it a day and have a full of example:

import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import java.time.Duration;
import java.util.List;

public class Demo {

    WebDriver driver;

    @BeforeClass
    public void setUp() throws InterruptedException {
        WebDriverManager.chromedriver().setup();

        driver = new ChromeDriver();
        driver.get("https://www.ericsson.com/en/blog");

        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(15));

        driver.findElement(By.cssSelector("a#CybotCookiebotDialogBodyLevelButtonLevelOptinAllowAll")).click();
    }

    @Test
    public void TC_01() throws InterruptedException {
        String selectInput = "input[placeholder='Category']";
        String selectOption = "div#categoryList div.dropdown-option.multi";
        String selectItem = "6G";
        selectItemInCustomDropDown(driver, selectInput, selectOption, selectItem);

        Thread.sleep(5000);
    }

    protected void selectItemInCustomDropDown(WebDriver driver, String selectInput, String selectOption, String selectItem) throws InterruptedException {
        driver.findElement(By.cssSelector(selectInput)).click();
        Thread.sleep(1000);

        WebDriverWait explicitWait = new WebDriverWait(driver, Duration.ofSeconds(15));
        List<WebElement> elements = explicitWait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(By.cssSelector(selectOption)));

        for (WebElement element : elements)
        {
            if (element.getText().trim().equals(selectItem))
            {
                JavascriptExecutor jsExecutor = (JavascriptExecutor)driver;
                jsExecutor.executeScript("arguments[0].scrollIntoView({block: 'nearest', inline: 'nearest'})", element);
                Thread.sleep(1000);

                element.click();
                Thread.sleep(1000);
                break;
            }
        }
    }

    @AfterClass(alwaysRun = true)
    public void tearDown() {
        if(driver != null) {
            driver.manage().deleteAllCookies();
            driver.close();
        }
    }
}

Conclusion

In real world application, Selenium default API for Select is not enough. Sometimes you may need to write your own custom method to deal with custom select/dropdown. Let’s consider it as a challenge in your road to become effective automation testing engineer.

Ask me anything