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.

- 14,121
- 6
- 34
- 66

- 176
- 2
- 2
- 14
-
By the phrase `better approach` you you mean **Artificial Intelligence**? – undetected Selenium Apr 23 '18 at 08:19
-
For eg :- a save button would be more or less in the same position if there is a small change in DOM structure. Tracking the sequence of events and adding a metadata to the click events would help. So in case of failure I can check for alternate buttons and continue my execution. – vaishakh Apr 23 '18 at 09:07
-
`a save button would be more or less in the same position if there is a small change in DOM` apparently **True** but logically/functionally/factually **False** – undetected Selenium Apr 23 '18 at 09:09
3 Answers
Are you following the orders of locators suggested by Selenium contributors: if not then please follow this order :
- ID
- name
- className
- linkText
- partialLinkText
- tagName
- cssSelector
- 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

- 28,520
- 6
- 20
- 38
My suggestion would be: 1. Try using different locators for particular element[https://api.jquery.com/multiple-selector/] 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

- 308
- 1
- 4
- 18
-
We already using multiple selectors in some places , but the issue is most of the elements don't have id and sometimes in xpath there is a small change in DOM Structure which causes the test case to fail. – vaishakh Apr 23 '18 at 07:33
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.

- 454
- 4
- 12