skip to Main Content

I am currently working on a project where the xpath of the elements changes continuously. At the UI display level there is not much visible change in UI, however the DOM elements changes continuously.
I am thinking of a better approach to handle failures in test case due to minor changes in DOM structure. I am currently using Selenium with TestNg framework for UI Automation Testing.
Any suggestions or directions on alternate approach would be helpful.

3

Answers


  1. My suggestion would be:
    1. Try using different locators for particular element[https://api.jquery.com/multiple-selector/%5D
    something like selector1, selector2, selectorN. If selector1 is not available in DOM, control will not throw an error instead, it will search selector2 and so on
    2. Use Explicit waits

    Login or Signup to reply.
  2. Are you following the orders of locators suggested by Selenium contributors: if not then please follow this order :

    1. ID
    2. name
    3. className
    4. linkText
    5. partialLinkText
    6. tagName
    7. cssSelector
    8. XPath.

    Note : Most of the time a cssSelector can replace Xpath, However Xpath has its own advantages which cssSelector do not provide.

    For more reference you can go through this SO Link : Css vs Xpath

    Login or Signup to reply.
  3. I use By.CSS selectors rather than by xpath, as these are less prone to changes in the DOM.

    So for this example dom:

    <div class="smc-login-container">
    <form role="form" action="/login.html" method="POST" name="login" class="ng-pristine ng-valid">
        <!-- Username -->
        <label for="username">User ID:</label>
        <input type="text" class="smc-login-control aftLoginUsernameField" id="username" name="username">
    
        <!-- Password -->
        <label for="password">Password:</label>
        <input type="password" class="smc-login-control aftLoginPasswordField" id="password" name="password">
    
        <!-- Cross site scripting token -->
        <input type="hidden" id="_csrf" name="_csrf" value="efaa05c4-77a8-443d-9484-51e8c9795c28">
    
        <!-- Sign In Button -->
        <button id="signIn" class="btn btn-lg btn-block smc-login-button aftLoginSignInButton">
            Sign In
        </button>
    </form>
    

    These selectors work:

    Example 1. Find Button, element type and class

    WebElement element = webDriver.findElement(By.cssSelector("button.btn"));
    

    Example 2. Find Button, direct child rather than descendent

    Uses full DOM and thus form element:

    WebElement element = webDriver.findElement(By.cssSelector("div > form > button"));
    

    Doesn’t use form element:

    WebElement element = webDriver.findElement(By.cssSelector("div button"));
    

    Example 3. Find Input following the username label, attribute with value then it’s sibling (+)

    WebElement element = webDriver.findElement(By.cssSelector("label[for='username'] + input"));
    

    Example 4. Find Password input and Button, OR’d (comma) returning more than one element

    List<WebElement> elements;
    elements = webDriver.findElements(By.cssSelector("input.smc-login-control.aftLoginPasswordField , .btn"));
    elements.get(0).sendKeys("my password");
    elements.get(1).click();
    

    Example 5. Find username input, has class attribute, but not attribute name = ‘password’:

    WebElement element = webDriver.findElements(By.cssSelector("input[class]:not([name='password'])"));
    

    Another thing I do is use a more generic pattern, which finds multiple items. I’ve found the items are always found in the same sequence and thus I can access the one I want by just using the array index (like in example 4).

    Finally, if the DOM has dynamic values I’ve found that I can use a specific stable pattern to find a parent element which has the same dynamic value, thus extract it and then reuse it to find the other element I actually want.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search