Stewart Moon
Stewart Moon

Reputation: 279

Identifying the same Web Elements with Selenium

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:

//*[@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

enter image description here enter image description here

Upvotes: 2

Views: 1936

Answers (7)

Jeni
Jeni

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

becixb
becixb

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

Moshisho
Moshisho

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

Jakub Obstarczyk
Jakub Obstarczyk

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

Jakub Obstarczyk
Jakub Obstarczyk

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

Mahipal
Mahipal

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

Andersson
Andersson

Reputation: 52665

You can simplify your XPathto 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

Related Questions