Selenium Api, Selenium locators and regex - selenium

In my page I have some ids like "foo:searchResults12345" that are composed of a static part ("foo:searchResults" and a dynamic rendered one - one or more numbers.
I want to retrieve every id that contains the static part "foo:searchResults", ignoring the dynamic one.
I am thinking at using regex for the pattern text, but the problem is that I cannot find any method in Selenium Api to help me with this, such as selenium.getAllIdsInPage().
Anybody had the same problem and figured out a solution?

I would recommend combining getXpathCount with a loop to iterate through each match. For example the following xpath should return the total number of matching nodes when used with getXpathCount
//*[starts-with(#id, 'foo:searchResults')]
You should then be able to loop through each match using the following example XPath:
/descendant::*[starts-with(#id, 'foo:searchResults')][1]
Where 1 would be replaced by the current count in the loop.
Below is an example in Java that should print the matching IDs to system.out:
#Test
public void outputDynamicIds() {
selenium.open("http://www.example.com/");
int elementCount = selenium.getXpathCount("//*[starts-with(#id, 'foo:searchResults')]").intValue();
for (int i = 1; i < elementCount+1; i++) {
System.out.println(selenium.getAttribute("/descendant::*[starts-with(#id, 'foo:searchResults')][" + i + "]#id"));
}
}

Another way to go is to use a custom Location Strategy. I am doing this in my current project and it works fine.
In your particular case you can write a custom strategy that checks if the id attribute of each element starts with the locator string (the static part in your example) and return this element if that is so.
I think this approach is much cleaner.

Related

Selenium locator for element for combining ID which one part is static and one is dynamic

Selenium locator for element for combining ID which one part is static and one is dynamic.
I have one ID which combined with two parts i.e. xyz_abc , where xyz is static and abc is changing ,
How can i make xpath or any locator for selenium?
suppose "id=edit_1545" here edit is static,numbers are dynamic then in that case we can use xpath as //*[contains(#id,'edit')] OR //*[starts_with(#id,'edit')]
You should have provided some more details such as html layout, language - Java/Python/Javascript and what you have tried before asking
Anyway
in Java
String variable = "abc"; // which would change
String locator = "xyz_" + variable

Selenium Web driver - loop over elements and click if matches

i'm in day 2 of my selenium class, need help in finding an efficient way of looping over elements and if matches click the link address.
I want to navigate from classFrame to navList and loop over to find the match and click.
public void switchFrames() {
driver.navigate().to("https://seleniumhq.github.io/selenium/docs/api/java/");
driver.switchTo().frame("classFrame");
/* List<WebElement> elements = driver.findElements(By.className("navList"));
for (WebElement element : elements) {
System.out.println(element.findElement(By.xpath(".//li/a")).getText());
}
*/
List<WebElement> items = driver.findElements(By.cssSelector("ul li"));
if ( items.size() > 0 ) {
for ( WebElement we: items ) {
we.findElement(By.linkText("Deprecated")).click();
}
}
driver.findElement(By.linkText("Deprecated")).click();
driver.close();
}
The main part you are missing and the reason you can't find the element you are looking for is because it's in a frame. In order to access elements in a frame with Selenium, you need to switch the driver context to the frame. You do that using driver.switchTo().frame(). Once you are done interacting with the frame, switch back to the default context using driver.switchTo().defaultContent().
Having said that... let me offer you some more advice since you are just starting out. There are several ways to do this. One way is like what you attempted... grab an element, find a child, loop through those children looking for the link you want. I prefer the more direct approach since we can search for the exact link using an XPath. What you want to do is to click the DEPRECATED link on the navbar. You could just use the By.linkText() locator and that will work but you want to be careful, especially with a page like this that has so many links, to not click on a link you didn't intend to. The way you do that is to narrow the search to the specific area you expect the link to be in, the navbar. Once you narrow the search there, you can quickly and safely find the link you are looking for. I prefer to do it in a single search using an XPath but you could use say a CSS selector to find the navbar area and then use By.linkText() to find the link, e.g.
driver.findElement(By.cssSelector("ul[title='Navigation']").findElement(By.linkText("Deprecated").click();
In that case, you will be scraping the page twice. It's not likely a big performance hit, I just prefer to use a single locator when it makes sense. I would suggest that since you are likely to use this code over and over that you put it in a function and pass it the link name, e.g.
public void clickNavbar(String linkName)
{
driver.switchTo().frame(driver.findElement(By.cssSelector("frame[name='classFrame']")));
driver.findElement(By.xpath("//ul[#title='Navigation']//a[.='" + linkName + "']")).click();
driver.switchTo().defaultContent();
}
Then you can call it like, clickNavbar("Deprecated");

Xpaths are changing dynamically

Im currently auotmating an web application using a selenium framework.For locating the elements im using xpath. For particular drop downs(with a filter in it) in the application the xpaths are getting changed frequently(for the available options in the drop down).The options in the drop down are inside the span section. Is there are any way to handle the dynamic xpath? Currently im using firebug to get the xpaths.
You can always use XPATH text matching if you know what to expect.
//*[text()='DropdownValue']
if you have list elements in the dropdown:
//li[text()='DropdownValue']
If you could provide example of the dropdown structure or just the HTML code of your case, it would be much easier to find a suitable solution.
You could get every element inside your dropdown, get the index of the element which contains the text and then click it:
List<WebElement>elems = driver.findElements(By.xpath("xpath from every element"));
elems.get(getIndex(elems, "Abereen District")).click();
private int getIndex(List<WebElement>elems, String elemText) {
for(int i = 0; i < elems.size(); i++)
{
if(elems.get(i).getText().contains(elemText))
return i;
}
return -1;
}

How to find the element within element in selenium

I am creating a framework for the data validation using selenium. The issue I am struggling with is I want to locate the element "td"(html tag) within element "tr"(html tag) . This is the code I have written.
Iterator<WebElement> i = rows.iterator();
While(i.hasnext()){
List<WebElement> columns = row.findElements(By.tagName("td"));
for(WebElement s:columns)
{
System.out.println("columnDetails : "+s.getText().toString());
}
if(columns.isEmpty())
{
ElementNotFoundException e = new ElementNotFoundException("No data in table");
throw e;
}
Iterator<WebElement> j = columns.iterator();// does some other work
ClusterData c = new ClusterData(); // does some other work
ClusterDataInitializer.initUI(c, j, lheaders); // does some other work
CUIData.put(c.getCN(), c); // does some other work
}
Now the issue with this is:
I am trying to fetch the data from the rows(see table data) in arraylist and use that arraylist further. Currently whats happening is the data for column header is fetched at start of which I have no use.I only want the rows's data. I am not able to determine the proper way to collect the data of table rows only.
if xPath of the table will help you understand it properly then here are the details :
Table header xPath of cluster name column:
/html/body/table/tbody/tr[2]/td[2]/div[2]/div/div/div[2]/div/div/div[2]/div/div/div[2]/div/div/div/div/div/div[2]/div/div/div[2]/div/div/div[2]/div[2]/div/table/tbody/tr/td[2]/div/div[2]
Table row (Table Data) xPath of test cluster 01:
/html/body/table/tbody/tr[2]/td[2]/div[2]/div/div/div[2]/div/div/div[2]/div/div/div[2]/div/div/div/div/div/div[2]/div/div/div[2]/div/div/div[3]/div[2]/div/table/tbody/tr/td[2]/div/div/a
Please let me know if you need anything else.
I am using the following code to extract row data from table.
List<WebElement> rows = getElement(driver,sBy,"table_div_id").findElements(By.tagName("tr"));
where sBy = By.id and table_div_id = id of div in which table is present. This extracts all the rows into arraylist and then i am using code to extract the row data into another arraylist. It is where I am stuck.
Each row from the table is in its own "table" tag so following things are not working :-
List<WebElement> rows = driver.findElements(By.xpath("//div[#id = 'table_div_id']//tr"));
List<WebElement> columns = row.findElements(By.xpath("./td"));
or the approach I used for the previous release of product i.e.
List<WebElement> columns = row.findElements(By.tagName("td"));
So, I used following approach which enabled me to capture all of the visible rows from the table.
List<WebElement> columns = row.findElements(By.xpath(".//table[#class='gridxRowTable']/tbody/tr"));
But after that I faced another issue that is since this table was implemented using dojo, the scrolling was impossible and Selenium was only able to capture the visible rows , so to overcome this I zoomed out in the browser using selenium. This is how i achieved my goal of getting the data.I believe others might have provided me answer if i would have shared some more details. Still , sorry about that and hope my answer helps you all.
instead of
List<WebElement> columns = row.findElements(By.tagName("td"));
try using
List<WebElement> columns = row.findElements(By.xpath("./td"));
Check if this helps. This should give you the td elements. If I have not understood your issue, let me know.
You can use this way-
driver.findElement(By.Xpath("//table[#id=\"table1\"]/tbody/tr[2]/td[1]"));
Regards,
Anuja
Do you have selenium IDE installed? Perform storeText operation on the row you want to retrieve, then xpath will get populated in IDE. There will be multiple xpaths; the most reliable is xpath:position, use that to capture your rows.
And use firebug for better visibilty of your AUT.
Firebug and Selenium IDE are the most basic component of Selenium Framework development.
You can manipulate xpath as you want.

Selenium nth match by id without common parent

I have to test some complicated web service using Selenium.
Problem is that ids of elements are changing from session to session.
For example there is bunch of inputs each have id with prefix textf_id_DComboBox_ and ends with a consecutive numbers, starting number is random (session dependent).
Those inputs doesn't have a common parent so nth-child doesn't work.\
I can find first input by using selector: css=input[id^='textf_id_DComboBox_'] but I have no idea how to find next items (1-7) which match this selector.
I've found some suggestions on stackoverflow that xpath selector should be used, but I was unable to adopt examples for my use case.
Update:
I have also alternative selector which captures first input: css=td.DForm_treeGridNoWrap input.
You can use this XPath in order to select all inputs that contain a common id:
string comboBoxXPath = "//input[contains(#id, 'textf_id_DComboBox')]";
List<WebElement> comboBoxElements = driver.findElements(By.XPath(comboBoxXPath));
At this point, you can iterate through the entire collection, or you can select which one you'd like to interact with by using an index:
comboBoxElements[1]
comboBoxElements[2]
comboBoxElements[3]
etc...
Well, that descrption does not help that much. You can try these tricks:
You can call findElement on WebElement This trick will probably not work, because those IDs do not have common parent. But if they are wrapped, say, in table, you can find the table first:
WebElement table = driver.findElement(By.id("the-table"));
And then to find all input in such table:
List<WebElement> inputs = table.findElements(By.tagName("input"));
Install Selenium IDE to your firefox and try record testcase by using it. You can play with target in Selenium IDE.
Dirty approach
List<WebElement> allInputs = driver.findElements(By.tagName("input"));
Will find all inputs in such page.
Footnote: The code is Java and driver variable is considered as healthy instance of WebDriver