Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pros/cons for using multiple locators per element in Selenium?

I am testing a website which is still in development.

Often an element's id, class, text, or position in the DOM will change. And then the locator I've been using will no longer be able to find the element.

But the features are still functioning properly. I don't want several tests to fail when there is no actual regression.

So instead of having a single locator for each element, I have a collection of locators.

public static final ArrayList<By> LOGIN_ANCHOR_LOCATORS = new ArrayList<By>();

static {
     LOGIN_ANCHOR_LOCATORS.add(By.id("loginLink"));
     LOGIN_ANCHOR_LOCATORS.add(By.linkText("Login"));
     LOGIN_ANCHOR_LOCATORS.add(By.xpath("/html/body/div[5]/a"));         
}

My method for finding the element looks like this:

public WebElement locateElement(ArrayList<By> locators){

    // create an element to return
    WebElement element = null;

    // until the desired element is found...
    while (element == null){

        // loop through the locators
        for (By locator : locators){

            // try to find by locator
            element = customWait.until(ExpectedConditions.presenceOfElementLocated(locator));

            // if not found...
            if (element == null){

                // log the failure
                logFailingLocator(locator);
            }
        }
    }
    return element;
}

It tries to find the element with the first locator in the collection, and only if it fails, try the next locator.

The collection is an ArrayList (order is defined by insertion order), which means my for loop will try each locator in the order which they were added to the List.

I initialized the list above by adding the locators in a particular order. Id is first, because I figure if the element's position in the DOM changes, but it retains its id, then that will be the way I'll be most likely to locate the correct element. Xpath is last because even if the id/class/text changes, but there is still the same type of element in the DOM at that position, it's probably the right element, but maybe less certain than other locators would be.

I'm using a fluent wait which ignores NoSuchElementException:

// Wait 5 seconds for an element to be present on the page, checking
// for its presence once every quarter of a second.
Wait<WebDriver> customWait = new FluentWait<WebDriver>(driver)
        .withTimeout(5L, TimeUnit.SECONDS)
        .pollingEvery(250L, TimeUnit.MILLISECONDS)
        .ignoring(NoSuchElementException.class);

So when one locator fails, it won't break the loop - it just logs the failure and then still goes on to try the next locator.

If all the locators fail, then the element will remain null, the test will fail, and it's far more likely the reason is actual regression of features/functionality.

I periodically check my logs for any element with 1 or 2 failing locators, and update them in my pageObject in the meantime, while tests continue running smoothly.

What are pros or cons to setting up my project this way?

like image 562
Dingredient Avatar asked Jun 06 '13 18:06

Dingredient


1 Answers

It's an interesting approach, but I'm concerned you might be masking other issues. I'd prefer to work more closely with the developers to avoid breaking UI issues in the first place.

Are the changing IDs dynamically produced? If that's the case, look to see if you can't get a suffix on the IDs, something like _loginlink. You might also have to work with an XPath that starts from a nearby static ID: "//div[@id='login_link_container'/a". (Starting from the root of the document like your example shows is a recipe for pain! :) )

like image 101
Jim Holmes Avatar answered Nov 09 '22 05:11

Jim Holmes