Reputation: 279
I am an Automation Engineer, I am currently trying to create test cases for a webpage that are sustainable ( that I can run at a later time and have still pass)
Here is my problem:
I am trying to select multiple web buttons that have the same exact class name. Now I can 'select' these buttons but these are only temporary x paths that are subject to change.
I need UNIQUE ID's (or some way of distinguishing them) for the same web elements. The only difference in the x paths are:
HTML format code that I can find each button, however if one button is moved my tests will fail.
HTML code that is the class name + nth of the button. But again my tests will fail if a button is taken out of the webpage.
//*[@id="tenant-details-accordion"]/div[1]/div[2]/div/div[2]/div[1]/div/a/div
//*[@id="tenant-details-accordion"]/div[1]/div[2]/div/div[2]/div[2]/div/a/div
//*[@id="tenant-details-accordion"]/div[1]/div[2]/div/div[2]/div[3]/div/a/div
^^The above code is how I currently find each button with Selenium
If I copy each classes x path this is what I get
<div class="src-js-components-DateControl-___DateControl__dateControl___2nYAL"><a tabindex="0"><div class="src-js-components-DateControl-___DateControl__icon___2z6Ak null"></div><!-- react-text: 392 -->Set +<!-- /react-text --></a></div>
<div class="src-js-components-DateControl-___DateControl__dateControl___2nYAL"><a tabindex="0"><div class="src-js-components-DateControl-___DateControl__icon___2z6Ak null"></div><!-- react-text: 386 -->Set +<!-- /react-text --></a></div>
<div class="src-js-components-DateControl-___DateControl__dateControl___2nYAL"><a tabindex="0"><div class="src-js-components-DateControl-___DateControl__icon___2z6Ak null"></div><!-- react-text: 398 -->Set +<!-- /react-text --></a></div>
I have talked to the Development team about this issue however they tell me that assigning Unique ID's to these web elements is a big no-no. (something to do with globalization of the project when we go to production) Even if they did assign Unique Id's they tell me that they would have to strip them before the project can be sent to production. Which ultimately would render my tests useless in the end...
I now come to Stack Overflow for help, everything I look up online cannot give me an answer, however this does seem to be a valid question between QA and Development departments.
Is there a way to assign Id's to a web element so that a tester using selenium can identify them and yet it will not affect a Developers ability to use that element through an entire project?
Edit: With the framework that my company uses, I am not actually writing any code in selenium. I save the Xpath to an object and then later in a manual test call that object with a pre-existing method. I can ONLY select Xpaths to be saved in an object.
I'll talk to Dev later to have them explain the big 'no-no' so that I may be able to communicate that with all of you..Thank you for your time and input
For example:
BirthDateSet= someXpath
Click() using {BirthDateSet}
Here are some pictures to help give you a visual
Upvotes: 2
Views: 1936
Reputation: 1118
I understand you want to select the "Set +" buttons, correct?
If so you can try to find all buttons under the @id="tenant-details-accordion" element with a specific text like that:
//*[@id="tenant-details-accordion"]//*[text()='Set +']
Upvotes: 0
Reputation: 373
EDIT:
Thanks for the code.. So if you look at your code, you can see that although what you're after have similar attributes, there are elements in the page that would allow you to identify what you're after. So let's say you want the SET link after Birth Date, then use:
//div[contains(text(),'Birth Date')]/div/a/div
So to reuse this xpath, just replace the text String.format("//div[contains(text(),'%s')]/div/a/div", labelName);
OLD: if you want to temporarily assign the elements an attribute, I believe you can do that through javascript element.setAttribute() which you can run through the executeScript() function.
Don't the buttons have text? Are you saying that the buttons swap places with one another? or don't you want to use the index of the buttons?
Upvotes: 1
Reputation: 2981
You can go with the nth
approach to find your unique element or with another, that won't solve your real problem which is that your colleague developers aren't cooperating with you. The automated tests are supposed to be (among other things) a service for the developers to know they haven't broken anything as fast as possible, but if they aren't giving any effort, then WHY should you invest in it at all..?
They probably won't even look at the results. Especially when your locators are in the form of div[2]/div[3]...
which would break very often and you'll lose their trust in the automation.
I'm no front-end expert but I've seen enterprise products in production with G10N and L10N and other long words, that have id's in their HTML, so if I were you I'd dig deeper to understand why? that big no-no, which sounds very odd to me...
So you asked the wrong question, it should be something like ~ How to add unique id's to the HTML using React in a global web application? and the ones who should be asking it are the developers.
As a side note, as many people tend to think, automation is not mainly about moving manual tests to automated it also finds "bugs" in the communication inside the company. To quote a great blog post on this subject:
Counter-intuitively, the bigger obstacles when developing automation are either low priority bugs or even things that are not bugs whatsoever. These obstacles can be symptoms of a bad design, bad development practices and even symptoms of inefficient communication patterns in the organization (that are usually caused by the organizational structure! Conway’s law is a classic example for this).
Good luck!
Upvotes: 1
Reputation: 90
if devs doesnt want to add unique IDs or attributes (it's weird why they don't want to do that) you could try something like this:
//return div class 'col-sm-4' which contain text 'Activation Date'
var parentDiv = driver.FindElement(By.XPath("//div[contains(@class, 'col-sm-4') and contains(., 'Activation Date')]"));
//should return div with icon you want e.g. Click
var childElement = parentDiv.FindElement(By.CssSelector(".DateControl__icon"));
childElement.Click();
Upvotes: 1
Reputation: 90
you can ask devs to add attribute to those buttons so instead of:
<button class="common_class_name">
<button class="common_class_name">
<button class="common_class_name">
for each button you will see
<button class="common_class_name" test-id="uniqueAttributeForButton1">
<button class="common_class_name" test-id="uniqueAttributeForButton2">
<button class="common_class_name" test-id="uniqueAttributeForButton3">
etc
And in your tests you can find those buttons using css selector e.g. C# code:
var buttonLocator = "[test-id=\"uniqueAttributeForButton1\"]";
WebElement button = driver.FindElement(By.CssSelector(buttonLocator));
Upvotes: 1
Reputation: 910
Another way of reaching to the required button using xpath is following:
//*[@id='tenant-details-accordion']/descendant::div[contains(@class, 'DateControl__icon')][1]
Above xpath should be able to select the first occurring button. Similarly, for the second occurring button, the xpath will become:
//*[@id='tenant-details-accordion']/descendant::div[contains(@class, 'DateControl__icon')][2]
Hence, you can continue to replace the predicate([2]) based on occurrence level of the required button on page.
Upvotes: 1
Reputation: 52665
You can simplify your XPath
to make it less sensitive to possible changes in DOM
:
//div[@class="src-js-components-DateControl-___DateControl__icon___2z6Ak null"][N] # Where N is button index
If this part 2z6Ak
of class name is dinamically generated, try:
//div[starts-with(@class, "src-js-components-DateControl-___DateControl__icon___")][N] # Where N is button index
Upvotes: 1