We are automating test cases for hardware devices like tv, raspberrypi etc which require to perform certain number of steps and check expected result at the end of each step. To automate these test cases we are using dom element attributes such as id, class,data-component-id etc to fetch the objects and perform actions.
The problem with this way of automation is every time UI changes we need to change the dom elements id, class etc and hence it is rework of the scripts.
I want to know if there is automation framework or any other way using which we can automate test cases independent of ui changes.
Instead of using the exact path, try to identify the element in a more generic way. Using "contains" will help you to identify the elements with the text attributes with out going into the way it is defined. So even the DOM structure changes but with the text being same, your tests will not fail.
Contains
It is very handy XPath Selenium locator and sometimes it saves the life of a test automation engineer. When an attribute of an element is dynamic, then you can use contains() for the constant part of the web element but also you can use contains() in any condition when you need.
Syntax: //tag[contains(#attribute, ‘value‘)]
Example: //input[contains(#id, ‘er-messa’)]
Examples:
Java
1
2
3
4
5
6
7
8
//*[contains(#name,'btnClk')]
--> It searches "btnClk" for all name attributes in the DOM.
//*[contains(text(),'here')]
--> It searches the text "here" in the DOM.
//*[contains(#href,'swtestacademy.com')]
--> It searches "swtestacademy.com" link in the DOM.
That's why you should use id selectors if possible. They are supposed to be unique and hence immune to UI changes. The name selector should work the same way.
If you are using Selenium, use the following list of object locators in (loosely) this order of preference:
id
name
tag name
class
CSS or Xpath
linktext or partial linktext
And if you really want the elements to be consistently identifiable, you might talk to the developers and ask them nicely to add the ids.
Related
I have had this question a while, but I had never done anything about it. When mapping some elements for UI tests I sometimes come across elements that return two identical results.
We have got around this in the past by using findelements and then using an index [1].
But I still don't understand why it returns two elements when I can only see one in the code that should be located.
An example would be the following. You can see this username field box below.
And if I use some XPath expression like,
//input[#name='username']
I'm expecting only to get one element in return, but using the tool Chropath I can see that I get two elements in return.
These elements look identical, one is not hidden, etc.
I have never understood why this is happening, because if I use a findelement, I get an element, not interactable error, as I guess the driver can’t decide which one to use? Or they are in the way of one another.
So the workaround I have always used is:
return self.browser.find_elements(by=By.XPATH, value="//input[#name='username']")[1]
when I realisticly should be able to use:
return self.browser.find_element(by=By.XPATH, value="//input[#name='username']")
Why is this?
Some excellent response and it has made me understand what’s going on now. Moving forward, I will use the following:
for e in self.browser.find_elements(by=By.XPATH, value="//input[#name='username']"):
if e.is_displayed():
return e
This seems to work for me.
I see this often when a website has both the "desktop" version and a mobile or smaller screen version. At full (or near full) screen, the desktop elements are visible while the small screen elements are hidden. Once you resize the browser small enough, the desktop elements are hidden and the small screen elements become visible.
To get around this in a generic way, filter the returned two elements based on visibility, e.g.
return [e in self.browser.find_elements(by=By.XPATH, value="//input[#name='username']") if e.is_displayed()]
That should always return the visible element of the two.
The answer is within the snapshot:
The following xpath
//input[#name='username']
Identifies 2 different elements within the HTML DOM. Among the two matching elements, the first matching element is for mobile displays which remains hidden while you access the DOM Tree in Desktop mode. In the given snapshot of the Chropath the classname as modal-content-mobile is the best hint.
Solution
In these cases there are different approaches to identify the desired element. While some users tends to use an index and some users tends to probe the displayedness, from a personal perspective I find it quite easier and handy to traverse up the DOM to find the difference in attribute values in any of their ancestors and then finally follow down till the desired element.
It is possible you can have more than one same element on the page with same name attribute. One must be hidden.
If you want to access the first one use following xpath.
return self.browser.find_element(by=By.XPATH, value="(//input[#name='username'])[1]")
If you want to access last one use following
return self.browser.find_element(by=By.XPATH, value="(//input[#name='username'])[last()]")
It's quite often occurs that multiple elements will match the same locator.
For example, several code blocks may be implemented for login: one for a computer browser, another for a mobile browser, etc. The proper elements will be presented according to what you use to browse that page.
Selenium find_element always returns the first element found matching the passed locator on the page.
So, in case the first matching element is hidden return self.browser.find_element(by=By.XPATH, value="//input[#name='username']") will always retunt that hidden element.
You will need to make your locator more precise to match the desired web element.
A locator like "(//input[#name='username'])[2]" may be good, but it's better to use a unique parent element here, something like "//div[#class='pc_modal']//input[#name='username']", so your code would be something like this:
return self.browser.find_element(By.XPATH, "//div[#class='pc_modal']//input[#name='username']")
Well, in the strictest sense of way, no two elements have the same XPath expression. If you look at the absolute path, you will find the difference. The key is to find a path which is unique. In many case, you will find a web page where you find many textboxes/labels/dropdowns that have the same ids but are only differentiated by their absolute path.
Most of the times, such things depend on the framework used to develop the webpage and also developer's preference. An application developed in React will have a different DOM structure than one developed using Angular, for instance.
Yes, you are correct that it becomes difficult to find out which is the element of interest in such situations. In such cases, do not only depend on the particular element but add either a parent/sibling or ancestor to access the element. Although it might take some time and will jot be straightforward but it will be possible to find a unique XPath most of the times.
There are some test automation tools, like Ranorex, that have an object browser (objext spy as it is called) that can be used to pin on any web element and access its properties like hidden, visible. enabled, etc. But such tools are not free :(
I am testing a site that has a dialog box with multiple text fields, some with datepickers, some without.
For some reason, when I attempt to locate the inputs by their XPath selenium finds the element, but when it comes time to input data, it send the keys to the top field. Here is an example of my selenium code:
DriverHelper.SendKeysByXpath("//input[#name='registrationStartDate']",CurrentDate);
DriverHelper.SendKeysByXpath("//input[#name='firstStartDate']",CurrentDate);
DriverHelper.SendKeysByXpath("//input[contains(#name,'lastStartDate')]","01/01/2018");
FYI, the DriverHelper is a class I call to save myself from typing the same selenium calls over and over again.
The XPath names are all unique and as far as I know there shouldn't be any confusion as to which input I'd like to send the keys to.
Has anyone run into similar situations before?
I'm trying to get an example up in jsfiddle but so far I'm unable to replicate the issue there.
It is sending keys to the top element probably because that is the one that he is selecting.
Try to use this:
List<WebElement> result = webDriver.findElements( by );
Debug your code and check how many elements your selector is retrieving.
Try to narrow and improve your search in such a way that you narrow the group os selected elements as possible.
Very personal opinion:
The code is easier to fix and to read if you avoid using xPaths as selectors. I prefer id's and classes whenever its possible.
Selenium best pratices source
I am new to test automation and I need help of experts who can help me in proceeding with the current difficulties.
Currently there is a web browser application which is tested manually based on the test cases in an excel.
There is also an automation framework also which uses Selenium and uses WebDriver and runs on Google Chrome.
The test cases(in excel) used for manual are taken up and another set of test cases(in excel) are written which is nothing but the div elements and the action which the framework should do like click or find which the framework will understand.
1.First I need to manually find out each div id for all the elements and put it in excel which the framework understands.How can I avoid this?
2.Also a new version of the application has come in which all the div id for the elements differ.Hence its pain to note the div id again and put them in excel.
How can I write the test cases only once for each case even if the div changes?
Please help.
Follow a design pattern, e.g. Page Objects
If ids will be changed try to use css and xpath selectors that do not stick to ids. The main idea is to specify such selectors that allow tests to find elements on the page using knowledge by their parents, tag names, other attributes that won't change (class and so on).
In my application, it has several tabs, say 'AAA','ABC','ADF'; I need to automate the click on tab 'ABC'.
Those tabs have ids and they are 'tab1','tab2','tab3'. I can done this easily by using ids. but i don't want to use this because those tabs will change time to time. so I need to use the name in the tab, because it is unique.
Below is my tag:
<a id="tab2" class="current" onclick="expandcontent('sc2', this);" href="#"> ABC </a>
If this is the case, you will probably need to fall back to XPath and perform text-based searches, for instance:
//a[text()='ABC']
Though, I'd advise you work with your development team to have consistent ID's. Text based matching is fine, but when you start to use older browsers you'll notice it really really slows down the tests.
However, you can also use the .LinkText and .PartialLinkText selectors in your language API's - there should be an implementation of those selectors in each API (C#, Ruby, Python etc). The catch here is this will be for a (anchor) elements only. However, providing that is the only type of elements this needs to be done by, you can get away with using this instead of XPath.
As Arran mentioned, you are likely best off searching for the tab names using XPath but, you can also use FindBy as well. An example of this would be:
#FindBy(css=<the CSS value for the tab>) private WebElement pageTab2;
#FindBy(id="tab2") private WebElement pageTab2;
I can only agree with what Arran also mentioned about your developers using more relevant naming conventions as well. The easier they make your job, the more you can do to make their lives easier too.
Simplest answer will be Use..."link=ABC" or link=" ABC " (it there are leading and trailing spaces).
The simplest approach would be to use X paths to find your tabs.
When you are starting out there are two helpful tools to help you find X paths. Download Mozilla Firefox and get these two add-ons:
Web Driver Element Locator-After downloading you can right click a web element and select X path.
Selenium IDE-This is a recorder and will give you the X paths or CSS of each web element you interact with.
I would recommend starting with these tools to help you out since you are just starting out.
As for your question:
I would recommend using what #Arran said...
//a[text()='ABC']
'a'-will search the entire page for whatever text you have in single quotes ''
If you Right Click the element or Tab and select Inspect. You will then be looking through the back-end of the page for classes or div that help you identify each different element.
xpath=//a[contains(#class,"current") and contains(#text,"ABC")]
When creating selenium tests using the #{selenium} tag, how do you use complex XPath locators? I've got some simpler examples that work but I'd really like to avoid having to give every element an id just to facilitate testing.
I've tried variations like these:
#{selenium 'Sitemap'}
...
// These work:
assertTitle('Site Map')
verifyTextPresent('Site Map')
verifyTextPresent('Login')
verifyText('id=test', 'Login')
verifyText('//ul', 'Login')
verifyText('//ul[2]', 'Login')
// this one results in "Element //ul[#class=sitemap] not found"
verifyText('Login','//ul[#class=sitemap]')
#{/selenium}
Has anyone gotten the more complex versions working? It looks like it should work according to the selenium docs. Also, is the creation of selenium tests in the context of Play documented anywhere? The only mention of it that I can find are these trivial examples.
I disagree to a degree. Badly constructed xpaths that search through the entire DOM will slow down tests but well constructed xpaths should have minimal effect on speed (unless you are using IE which has a horrific JavaScript rendering engine).
Ideally you want to key your xpath to an ID as close to the area of the DOM you want to search as possible, this will ensure you are only searching a specific area of the DOM rather than using an xpath like the one shown above that will search through the entire DOM even it it does find a matching element quickly.
I'll provide some examples of what I would call good xpaths using http://www.lazeryattack.com as an example. If you have anything specific in mind shout and I'll see what I can do to help:
The Voice Comms link: //ul[#id='leftMenu']/li/a[.='Voice Comms']
H3 element that contains a span element with the text "January VAT Increase": //div[#id='news']/h3[span[.='January VAT Increase']]
The first paragraph of text under the above element: //div[#id='news']/h3[span[.='January VAT Increase']]/following-sibling::p[1]
The second paragraph of text under the above element: //div[#id='news']/h3[span[.='January VAT Increase']]/following-sibling::p[2]
Start searching from the featuredNews div and drop down to the h2 element with the text "New Look And Feel": //div[#id='featuredNews']/descendant::h2[.='New Look And Feel']
I would suggect using FireFox with the FireBug and FirePath extensions to help you work out xpaths, this is my personal favourite combination.
Did you try
//ul[#class='sitemap']
Notice the single quote around sitemap.
XPath would make your tests slow and id, name are better option to use.