many buttons with the same id - selenium

I am using selenium to test a page with multiple portlets made by liferay.
Every portlet is having a save button with the same id, it use the iframe id of the portlet to differentiate between the buttons.
How can I write a code in selenium that can understand which button I mean??

You need to use driver.switchTo().frame(IFrameElement). Any kind of IFrame you need to switch in/out of.
https://stackoverflow.com/a/9943605/1769273

You can use xpath or css selectors to find children dependent on parents.
paste your html and we can provide examples

Does this mean your portlets are all embedding iframes? Typically portlets just render HTML snippets into the same documents. In this case, your implementation would be considered flawed: Portlets must not use IDs that can conflict. E.g. you should not render
<input type="submit" id="save"/>
but
<input type="submit" id="<portlet:namespace/>save"/>
or similar - make sure the id is unique, as it ends up in the same HTML-DOM which - by specification - assumes ids are unique.
There are other methods to create unique ids, but keep in mind: If you come up with the prefix yourself, per portlet, someone might add the same portlet to the page twice and you can end up with the same id even though all different portlets have unique ids.
If you are indeed rendering many different iframes from your portlets, you can disregard this answer or take it as a suggestion to make better use of the portal environment by changing the implementation.

Related

UI Automation - Elements on my UI have ember ids , which change frequently with addition of new UI elements. How to use the id for automation?

Example of the HTML of a dropdown element:
<div aria-owns="ember-basic-dropdown-content-ember1234" tabindex="0" data-ebd-id="ember1234-trigger" role="button" id="ember1235" class="ember-power-select-trigger ember-basic-dropdown-trigger ember-view"> <!---->
<span class="ember-power-select-status-icon"></span>
</div>
The xpath and CSS selector also contain the same ember id.
xpath : //*[#id="ember1235"]
css selector : #ember1235
The ember id would change from id="ember1235" to say, id="ember1265" when there is a change in the UI.
I am using id to locate the element. But every time it changes I need to modify the code. Is there any other attribute I could use for Ember JS UI elements?
There is quite a lot to discuss in your question but hopefully we will have a good answer for you #PriyaK
The first thing to mention is that Ember IDs may not be the best method to select an element in the DOM. As you have already mentioned, they can change from time to time and also it doesn't really give you a great semantic thing to select in your selenium test so it might seem a bit out of context when looking back.
One thing that you could try is to either pass a class to the ember-power-select component (the one that provides the HTML that you used in your example) and use that to select the element, something like:
<PowerSelect
#class="my-fancy-class"
as |name|
>
{{name}}
</PowerSelect>
Then you should be able to select the selected value by using the CSS selector .my-fancy-class span (because the component outputs the selected value in a span)
We just tried this in an example app but it didn't actually work 🤔 Never fear, you can also do something like this and it should work with the same selector as before:
<div class="my-fancy-class">
<PowerSelect as |name|>
{{name}}
</PowerSelect>
</div>
This is fine, but there are also a few issues using classes for selectors in tests. One example of a problem that might crop up is that your tests might all suddenly stop working if you did a style refactor and changed or removed some of the classes on your elements. One technique that has become popular in the Ember community is to use data-test- attributes on your DOM nodes like this:
<div data-test-my-fancy-select>
<PowerSelect
#class="my-fancy-class"
as |name|
>
{{name}}
</PowerSelect>
</div>
which can then be accessed by the following selector: [data-test-my-fancy-select] span. This is great for a few reasons! Firstly it separates the implementation of your application and tests from your styling and avoids the issue I described above. The second benefit of this method is that using what #Gokul suggested in the comments, the ember-test-selectors package, you can make use of these data-test- selectors in your development and test environments but they will be automatically removed from your production build. This is great to keep your DOM clean in production but also, depending on the size of your application, could save you a reasonable amount of size in your templates on aggregate.
I know you say that you are using selenium for your testing but it's also worth mentioning that if you're using the built-in Ember testing system you will be able to make use of some testing helpers that addons may provide you. ember-power-select is one of those addons that provides specific testing helpers and you can read more about it in their documentation: https://ember-power-select.com/docs/test-helpers
I hope this answers any questions you had!
This question was answered as part of "May I Ask a Question" Season 3 Episode 1. If you would like to see us discuss this answer in full you can check out the video here: https://www.youtube.com/watch?v=1DAJXUucnQU

Retrieving a element with multiple xpaths

This isn't much of a coding question but one about what options should I take next. I've just started using selenium about a week ago and started to get the hang of most of its function.
I was working on a work project to login into various websites until I ran into a issue where I was getting this error when I tried to find the password field
Exception in thread "main" org.openqa.selenium.ElementNotVisibleException: element not visible
I went ahead and double checked the name & id but I couldn't find the field using locators like .id, name, and xpath. I inspected the xpath with Firebug and noticed that it returned two results instead of one.
Current Xpath looks like this
.//*[#id='password']
I was wondering if anyone could point me to the right direct when dealing with something like this.
Normally, id attribute suppose to be unique value, but there are some cases when front-end developer just hide part of DOM, create similar and forget to remove hidden one.
In such case you can (if it possible) ask developer to get rid of redundant code or use index as
"(.//*[#id='password'])[2]"
In cases like this you need to use another unique DOM element (parent, ancestor, sibling, child) with connection to the element you are looking for. For example In those html snippets
<div id='a'>
<div id='password'></div>
</div>
And
<div id='b'>
<div id='password'></div>
</div>
.//*[#id='password'] will have two results
However
.//*[#id='b']/[#id='password']
Will have only one result
Let me try to answer your queries one by one:
error when I tried to find the password field : This is because the property which you have mentioned id/name/css/xpath was incorrect.
ElementNotVisibleException : I doubt it was for the password_field at all. Reason behind that is, normally login field & password field stays on the same container. Either those resides on the HTML DOM (which gets loaded completely once the page loading is complete) or they may reside within a frame/iFrame (there are other measures to handle them which I am not covering here). But those 2 elements stays on the same container. So if you have found out the login_field element, password_field is just a step away.
inspected the xpath with Firebug and noticed that it returned two results : That's because the xpath which you are using doesnot identifies an unique element. There can be multiple elements on the HTML DOM with the same id attribute set to "password". But definitely the xpathof those elements will be different and unique.
What you should do?
I will suggest you the following:
a. Try to identify each element on a webpage following the attributes in sequence: id, name, visibleText, css, xpath.
b. Try to identify a unique logical xpath for elements using the other properties of the elements defined within the HTML tag. Cross check your xpath through Firebug/Firepath. There are some other handy xpath checker available too. Take help of those.
Let me know if this answers your question.

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:
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
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
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.
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));
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();
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!
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?
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 +']

How to find XPath of an ExtJS element with dynamic ID

All the elements in the application which i am testing have dynanic ID's . The test always passes when i replay it without refreshing the page but as soon as i refresh the page, The Test Fails because Id's of all the elements changes randomly and selenium cannot match the recorded id's with the new ones .
I tried to use Xpath-position, It works for some objects but in case of Dropdown list and Buttons, it dosent work!
Can anyone please tell me how to find the Xpath (Meathods in JAVA or S*elence*) of an object OR How to create a new Locator Finder for Dropdown list and Buttons
I can show the properties (Inspected by Firebug) of the dropdown which is teasing me.
properties of Dropdown :
<div id="ext-gen1345" class="x-trigger-index-0 x-form-trigger x-form-arrow-trigger x-form-trigger-last x-unselectable" role="button" style="-moz-user-select: none;"></div>
properties of Dropdown*Choice*:
<ul>
<li class="x-boundlist-item" role="option">Rescue</li>
</ul>
Please search before posting, I have been answering this over and over.
ExtJS pages are hard to test, especially on finding elements.
Here are some of the tips I consider useful:
Don't ever use dynamically generated IDs. like (:id, 'ext-gen1345')
Don't ever use absolute/meaningless XPath, like //*[#class='someclass']/li/ul/li[2]/ul/li[2]/table/tbody/tr/td[2]/div
Take advantage of meaningful auto-generated partial ids and class names. (So you need show more HTML in your example, as I can make suggestions.)
For example, this ExtJS grid example: (:css, '.x-grid-view .x-grid-table') would be handy. If there are multiple of grids, try index them or locate the identifiable ancestor, like (:css, '#something-meaningful .x-grid-view .x-grid-table'). In your case, (:css, '#something-meaningful .x-form-arrow-trigger')
Take advantage of button's text.
For example, this ExtJS example: you can use XPath .//li[contains(#class, 'x-boundlist-item') and text()='Rescue']. However, this method is not suitable for CSS Selector or multi-language applications.
The best way to test is to create meaningful class names in the source code. If you don't have the access to the source code, please talk to your manager, using Selenium against ExtJS application should really be a developer's job. ExtJS provides cls and tdCls for custom class names, so you can add cls:'testing-btn-foo' in your source code, and Selenium can get it by (:css, '.x-panel .testing-btn-foo').
Other answers I made on this topic:
How to find ExtJS elements with dynamic id
How to find unique selectors for elements on pages with ExtJS for use with Selenium?
How to click on elements in ExtJS using Selenium?
Using class names in Watir
how to click on checkboxes on a pop-up window which doesn't have name, label
I would suggest you build a xpath from any of the parent of your DIV. you may get messed if there is no immediate parent node has such one.
example,
//*[#id='parentof div']/div
//*[#class='grand parent of div']/div/div
i did even something like this,
//*[#class='someclass']/li/ul/li[2]/ul/li[2]/table/tbody/tr/td[2]/div
But still, its not encouraged to do so.

Test Liferay portal using Selenium

I want to test a Liferay portlet with Selenium, but the problem is that element ids generated by Liferay are dynamic and seems that they change each time I enter portlet. Does anyone has any suggestion how I test the portlet?
thanks for your help.
It would depend on how your elements are structured. There are various ways to identify elements and not just fixed ids.
If you have dynamic element ids, then try using some other attributes of the elements to uniquely identify elements for eg, text() or name etc... At times, it also happens that ids are generated with a common pattern, in which case you can try using that for eg, //div[contains(#id,'fixedpart')]
or //div[starts-with(#id,'fixedpart')]
I would recommend to use new HTML5 attribute like data-*, for example for a certain
<div data-selenium-test = "foo"></div>
Then grab this element with selenium:
//div[#data-selenium-test='foo']