Follow Us on Twitter

Testing ADF with Selenium: Accessing elements through multiple regions

by Mike Heeren on November 2, 2015 · 18 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

Testing ADF with Selenium: Accessing elements through multiple regions, 5.0 out of 5 based on 1 rating
Ratings:
VN:D [1.9.22_1171]
Rating: 5.0/5 (1 vote cast)

{ 18 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

Egor Eremeev August 1, 2018 at 6:11 pm

Wilfred,
thank you for you work under SeleniumTools!

Recently began using it in my project and faced with a question how to manage ?

I follow Page Object pattern and use findAdfComponent() method from SeleniumTools. It wotks great for elementa outside iframe.

The problem with iframe is similar as described in this post, it is unable to locate elements inside iframe.

Could you suggest a way how to extend the SeleniumTools for working with ?

Thank you

Reply

Egor Eremeev August 1, 2018 at 6:14 pm

somewhy words was cutted from the post…

Question is how to manage af:inlineFrame

Reply

Egor Eremeev October 24, 2018 at 3:47 pm

I wanna describу solution concernig af:inlineFrame for all whom maybe interested in.
Actually, af:inlineFrame tag should be managed in other way than af:region.
In a whole, to managed inlineFrame you need to use Selenium API methods and no special things from SeleniumTools or other libs. After webdriver switches to frame all other things from SeleniumTools concerning location ADF Components works perfectly. They performs locating just relatively to document in you frame.

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

ElishaGrace April 28, 2018 at 9:02 am

Your very own commitment to getting the message throughout came to be rather powerful and have consistently enabled employees just like me to arrive at their desired goals.

Reply

zasi May 2, 2018 at 3:05 pm

Thanks a lot very much for the high quality and results-oriented help. I won’t think twice to endorse your blog post to anybody who wants and needs support about this area.

Reply

lenin September 7, 2018 at 5:52 pm

Thanks a lot very much for the high quality and results-oriented help. I won’t think twice to endorse your blog post to anybody who wants and needs support about this area.

Reply

varshini October 12, 2018 at 11:45 am

Nice post. Thank you for sharing a good post.

Reply

Anonymous Hosting October 17, 2018 at 1:44 pm

Wow, Nice blog. Thank you so much for the efforts of this blog.

Reply

AWS Training in Chennai October 24, 2018 at 11:58 am

Informative post, thanks for sharing.

Reply

CCNA course in Chennai October 25, 2018 at 2:13 pm

Excellent and useful blog admin, I would like to read more about this topic.

Reply

UiPath Training in Chennai October 26, 2018 at 1:33 pm

Thanks for taking time to share this page admin. I learned a lot from your page, keep sharing more like this.

Reply

ReactJS Training in Chennai November 14, 2018 at 1:56 pm

I have to thank for sharing this blog, really helpful.

Reply

Blue Prism Training in Chennai November 15, 2018 at 10:50 am

Awesome post, share more like this.

Reply

Data Science Training in Chennai November 16, 2018 at 1:52 pm

Great and informative post, keep sharing.

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