Follow Us on Twitter

Testing ADF with Selenium: Accessing elements through multiple regions

by Mike Heeren on November 2, 2015 · 5 comments

During the project where I am currently working on, we use Selenium for (unit)testing the ADF user interfaces of the application. Most pages of our application contain multiple (nested) regions with elements that need to be filled or clicked using Selenium. One of the problems we ran into was that ADF does not always generate the exact same ID for an element at runtime, especially when the element is a child of multiple nested regions. In our case it was not possible to search the elements using a “simple” XPath expression like “//input[contains(@id,’it1′)]” because some IDs can be used in multiple active regions.

We were eventually able to solve our issues not by trying to access the elements by their IDs, but using XPath expressions that search through the multiple layers of the generated HTML elements. I have written a Java utility class that can be used to achieve this. This Java utility class uses the DIV components generated for each region. The IDs of this DIV end with a colon and the ID given in the ADF page/fragment for the region. With this knowledge it is possible to generate an XPath expression which “steps through” the different layers of regions in the ADF page. The final problem that occurred was that XPath does not contain an ends-with function. The private constructEndsWithXpath method in the utility class can be used to achieve the same result as expected from an ends-with function.

package nl.whitehorses.selenium;
	 
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
	 
public class AdfComponentUtils {
	 
    private AdfComponentUtils() {
        super();
    }
	 
    public static WebElement findWebElement(WebDriver driver, String elementId, String... parentIds) {
        return driver.findElement(By.xpath(constructFindElementXpath("@id", new StringBuilder(":").append(elementId).toString(), parentIds)));
    }
	 
    private static String constructFindElementXpath(String locatorType, String locatorValue, String... parentIds) {
        reverseStringArray(parentIds);
	
        StringBuilder xpathBuilder = new StringBuilder();
	 
        if (parentIds != null) {
            for (String regionId : parentIds) {
                xpathBuilder.append("//*[").append(constructEndsWithXpath("@id", new StringBuilder("':").append(regionId).append("'").toString())).append("]");
            }
        }
	 
        xpathBuilder.append("//*[").append(constructEndsWithXpath(locatorType, new StringBuilder("'").append(locatorValue).append("'").toString())).append("]");
	
        return xpathBuilder.toString();
    }
	 
	 
    private static String constructEndsWithXpath(String string, String suffix) {
        return new StringBuilder("substring(").append(string).append(", string-length(").append(string).append(") - string-length(").append(suffix).append(") + 1) = ").append(suffix).toString();
    }
	 
    private static void reverseStringArray(String... array) {
        for (int i = 0; i < array.length / 2; i++) {
            String temp = array[i];
            array[i] = array[array.length - 1 - i];
            array[array.length - 1 - i] = temp;
        }
    }
}

The findWebElement method can be used to find the ADF elements in the Selenium tests:

  • Driver: The WebDriver instance that has to be used to find the elements.
  • ElementId: The ID that is assigned in the ADF pages/fragments to the element, e.g. soc1, it1, cb1.
  • ParentIds: Optional parameter(s) for providing the parent element(s) of the element you are looking for.

The method “AdfComponentUtils.findWebElement(<driver>, “select”, “soc1”, “r3”, “r2”, “r1″);” could be used when the structure of the ADF page is something like:

<page>
    <region id="r1">
        <region id="r2">
            <region id="r3">
                <select id="soc1">
                    <option value="1">Test 1</option>
                    <option value="2">Test 2</option>
                    <option value="3">Test 3</option>
                </select>
            </region>
        </region>
    </region>
</page>

Note: One last tip, for some ADF components, such as SelectBooleanCheckbox components, a suffix is appended to the ID generated at runtime. ::content will be appended to SelectBooleanCheckbox components for example. Because we are using ­­ends-with, you should keep this in mind while using the findWebElement method. When this is the case, a statement like the following can be used: “AdfComponentUtils.findWebElement(<driver>,”input”, “sbc1::content”);”.

Good luck testing your ADF application using Selenium!

Update 05-11-2015: Like Wilfred van der Deijl mentions in the comments, is SeleniumTools an excellent toolkit for testing ADF applications using Selenium. However, we were not able to use the SeleniumTools in our project because SeleniumTools is developed for ADF 12c. In our project we have to test an ADF 11g application.

I have also made a few small modifications on the “AdfComponentUtils” class, which make it easier to use. The “elementType” parameter is removed so it is easier to write tests because you no longer have to know which HTML element is generated for a component.

Also check out my other related blogpost: Sorting ADF tables using Selenium

Ratings:
VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)

{ 5 comments… read them below or add one }

Wilfred November 2, 2015 at 10:07 pm

You might also be interested in the talk we gave at openworld last week: http://www.slideshare.net/WilfredvanderDeijl/automated-testing-adf-with-selenium
It introduces, among other things, SeleniumTools a toolkit for Selenium testing ADF applications that also solves this issue by being totally aware of ADF components. Here you would have a subclass of com.redheap.selenium.page.PageFragment that represents your page fragment being tested. It would now about the af:region it lives in which is represented by com.redheap.selenium.component.AdfRegion. These classes can locate other components in the page fragment with relative JSF selectors so you don’t have to know about the dynamic parts of a client-id. It offers a bunch of other useful methods for testing an ADF application. Feel free to browse the slides at slideshare.

Reply

alaskamary November 5, 2015 at 11:25 am

wow..it’s very interesting.it’s very useful to every one..

Reply

Vikash Kumar February 2, 2016 at 1:40 pm

Really nice blog!!

It is interesting and very useful to every one..

Reply

CREDO SYSTEMZ February 6, 2017 at 11:12 am

Thanks for sharing this informative blog. I have read your blog and I gathered some valuable information from this blog. Keep posting.
Regards.

Reply

Pandora August 16, 2017 at 9:06 am

This is really good information I have visited this blog to read something fresh and I really admire you efforts in doing so.

Reply

Leave a Comment

 

Previous post:

Next post:

About Whitehorses
Company profile
Services
Technology

Whitehorses website

Home page
Whitebooks
Jobs

Follow us
Blog post RSS
Comment RSS
Twitter