How to perform Xpath looping and skip one element - java

How to perform X path looping?
for (int i=1;i<3;i++)
String xPath = "//*[#id='rso']//h3/a["+i+"]"
all_elements_text.add(driver.findElement(By.xpath(xPath)).getText());
return all_elements_text.toArray() ; }
i want to skip a[2]

try below code
for (int i=1;i<3;i++){
if(i!=2){
all_elements_text.add(driver.find Element(By.xpath("//*[#id='rso']//h3/a["+i+"]")).getText());
return all_elements_text.toArray() ;
}

Use below code to achieve the same what you have required
public static ArrayList<String> getAllValues()
{
ArrayList<String> all_elements_text = new ArrayList<>();
for(int i=1;i<3;i++)
{
if(i!=2)
{
all_elements_text.add(driver.findElement(By.xpath("//*[#id='rso']//h3/a["+i+"]")).getText());
}
}
return all_elements_text;
}
And Call this method from your Test where it requires to get All text and print all values e.g.
#Test
public void yourTestCase()
{
for(String s :getAllValues())
{
System.out.println(s);
}
}

A couple of facts about the solution :
Your xpath being indexed becomes brittle.
You are never sure when Google Analytics changes the indexes of the search result.
So the best practice would be to avoid and drop the keywords from the search result e.g. Documentation etc.
So keeping those in mind, lets assume we would :
Open the URL https://www.google.com/
Search for the text selenium webdriver
From the entire search result we want to drop the results which contains the word Documentation
Here is the sample code to search for the text selenium webdriver and drop the results containing the word Documentation :
List <WebElement> my_list = driver.findElements(By.xpath("//div[#id='rso']//div[#class='srg']/div[#class='g']//h3/a"));
List <String> my_text = new ArrayList<String>();
for (int i=0; i<my_list.size(); i++)
if(!my_list.get(i).getAttribute("innerHTML").contains("Documentation"))
my_text.add(my_list.get(i).getAttribute("innerHTML"));

Related

Iterate through a list of webelements within a table and assert equal each string

My goal is to iterate through a list of webelements (generated upon using a filter) within a table, spread across multiple pages and assert equal each string within those webelements with a provided string in a Cucumber step.
These webelements consist of strings (1 webelement = 1 string) placed within a column within the table.
All these strings equal.
Their data-testid is the same.
These webelements are spread across a number of pages (dynamic).
The loop would end when reached the last page, which contains a button of
which attribute text becomes disabled (when last page is displayed).
Here's what I started writing, but I'm a bit stuck at the moment. If
you can advise me how to continue further, I'm really greateful. At the moment, I get this error, when I execute the test.
1. Tests in error:
stale element reference: element is not attached to the page document
2. Not sure how to integrate the assert.
Actual code:
By nextPageBtn = By.xpath("//*[#data-testid='asd']");
By disabledNextPageBtn = By.xpath("//*[#data-testid='asdf']");
By filterValue = By.xpath("//*[#data-testid='asdf1']");
public List<String> sameFilterResultIsDisplayedForAllRows() {
List<WebElement> filterResultsList = new ArrayList<WebElement>();
List<String> stringsFromFilterResultsList = new ArrayList<String>();
boolean disabledNext = false;
do {
click(driver, nextPageBtn);
filterResultsList.addAll(driver.findElements(filterValue));
try {
getValueFromSomeAttribute(driver, disabledNextPageBtn,
"randomElementAttribute");
disabledNext = true;
} catch (Exception e) {
}
} while (disabledNext == false);
for (WebElement filterResultsList) {
System.out.println(a.getText());
try {
stringbookings.add(a.getText());
} catch (Exception e) {
}
}
return stringsFromFilterResultsList;
}
The assert would be something like this:
#Then("the results filtered for all rows contain value {string}")
public void expectedFilteredValues(String expectedFilteredValueString) {
String expectedFilteredResult;
expectedFilteredResult = 'randomString';
List<String> actualFilteredValues = javaMethods.sameFilterResultIsDisplayedForAllRows();
Assert.assertEquals(expectedFilteredResult, actualFilteredValues);
The issue resided with addAll(), prolly because of this:
"The behavior of this operation is undefined if the specified collection is modified while the operation is in progress. (Note that this will occur if the specified collection is this list, and it's nonempty.)"
I had to use add(), and create a secondary array within a for loop.
for (WebElement element : elements) {
stringsFromFilterResultsList.add(bookingTypeElement.getText());
}
Then, the assert is like this:
List list = javaMethods.
sameFilterResultIsDisplayedForAllRows();
for (int i = 0; i < list.size(); i++) {
Assert.assertEquals(expectedValue, list.get(i));
}

Fill string array with url links through for loop

I need a little help.
I have a string array (urllinks) which I want to fill with url links which are being parsed with jsoup through a for loop.
In below code example there are 2 urls but the list only gets filled with the first link. I don`t know how many links will be parsed, can be 1 but also 12.
public static String[] urllinks;
...
for (int i = 0; i < links.size(); i++) { // links size = 2
String url = doc.select("a").attr("abs:href");
urllinks[i] = url;
}
Any help would be appreciated.
Thanks in advance.
You problem is due to the fact that you call attr("abs:href") on doc.select("a") which returns an object of type Elements such that you always get the first match as stated in the javadoc:
Get an attribute value from the first matched element that has the
attribute.
You should rather iterate as next:
List<String> urls = new ArrayList<>();
// Iterate over all the links that have an attribute abs:href
for (Element link : doc.select("a[abs:href]")) {
urls.add(link.attr("abs:href"));
}
urllinks = urls.toArray(new String[urls.size()]);
To answer my own question, I solved it by creating an arraylist and then convert it back to a string array.
Dirty but it works.
{
private static String[] urllinks;
private static ArrayList<String> mStringList = new ArrayList<>();
...
int i = 0;
for (Element el : links) {
String url = el.attr("abs:href");
if (url != null) {
mStringList.add(i, url);
i++;
}
else {
// Do something
}
urllinks = mStringList.toArray(urllinks);
// check if urls are actualy in string array
Log.d("LINK 1", urllinks[0]);
Log.d("LINK 2", urllinks[1]);
...
}

How to short List having WebElement inside it

I am getting some value from a HTML Table. I am able to print the values but not able to figure out a way by which i can sort them alphabetically.
Code which i used-
List<WebElement> lst = driver.findElements(By.xpath(".//*[#class='user-questions lines']/tbody/tr/td[2]"));
for(WebElement s : lst) {
System.out.println(s.getText()); //This line prints the value
String[] ss = new String[lst.size()];
int i=0;
if(s.getText() != null) {
ss[i]=s.getText();
System.out.println(ss[1]); // But here i am getting null
}
i++;
}
First i tried to sort it using Collections.sort(lst) but got an error message:
Bound mismatch: The generic method sort(List) of type Collections is not applicable for the arguments (List).
Then i tried to put the string value inside a String array and later sort it but here i am getting null value when i tried to put the value into the String array
Today i was stuck in the same thing and found this question asked a way back at the start of this year. When i tried the solutions given i got a NullPointerException.
I wrote a small code and now i am able to short the webelements accoriding to the Natural alphabetical order. Here is the code-
//Here storing the WebElements in the List
List<WebElement> lst = driver.findElements(By.xpath("WebElement XPath"));
//Here creating a String array
String[] str = new String[lst.size()];
for (int i = 0 ; i<str.length ; i++){
str[i] = driver.findElements(By.xpath("WebElement XPath")).get(i).getText();
}//for
Arrays.sort(str);
for(String strr: str){
System.out.println(strr);
}
driver_1.close();
driver_1.quit();
}//try
catch(Exception e){
e.printStackTrace();
driver.close();
driver.quit();
}//catch
First i stored the webelements in the List. Then i created a String array for sorting.In the first for loop i stored the string which i got from the website. After that i sorted them using Arrays.sort method
In the advance for loop i am printing the output.
As i can see the question is very old and if during this time you got much better answer then please share it.
You getting null at System.out.println(ss[1]);
because:
ss[i]=s.getText(); always put in ss[0], because: before if int i=0;.
So ss[1] always empty.
To solve it put int i=0; before for(WebElement s : lst)
Declare i outside foreach loop. and sysout ss[i]. On your first loop execution obviously ss[1] will be null.
Another way around is:
List<WebElement> lst = driver.findElements(By.xpath(".//*[#class='user-questions lines']/tbody/tr/td[2]"));
String[] str = new String[lst.size()];
int i = 0;
for (WebElement ele : lst) {
if(ele.getText()!=null)
str[i] = ele.getText();
i++;
}
Arrays.sort(str); // to sort the array of strings

Building an array from a list of options

I currently have the following code which locates the Show id, then the elements in the option tags beneath and prints them out one by one.
WebElement dropDown = driver.findElement(By.id("Show"));
List<WebElement> options = dropDown.findElements(By.tagName("option"));
for (WebElement el : options) {
System.out.println(el.getAttribute("text"));
}
How can I modify it so that it builds up an array of all the text elements, instead of printing them out one by one?
In WebDriver we've a method in Select class to get all the options available in select tag.
List<WebElement> options = new Select(driver.findElement(By.id("Show"))).getOptions();
To get all the option values arrays follow below logic.
public String[] getOptions() {
String optionValues="";
List<WebElement> options = new Select(driver.findElement(By.id("Show"))).getOptions();
for(WebElement eachOption : options) {
optionValues+=eachOption.getText()+",";
}
return optionValues.split(",");
}
You just need to declare another array (or list, depending on your preference) and change your System.out.println() statement.
For a List of whatever object the text attribute is:
for(WebElement el : options){
secondList.Add(el.getAttribute("text"));
}
For an array, it would be easiest using indexing:
for(int i = 0; i < options.Size(); i++){
secondArray[i] = options.Get(i).getAttribute("text");
}

Verify over 200 List elements on a page in Webdriver

I have some 200 elements who's mark-up is as follows:
<span id="1356329740258" class="pagename">Sport & leisure</span>
<span id="1356329740259" class="pagename">Food & drink</span>
<span id="1356329740260" class="pagename">Household</span>
<span id="1356329740261" class="pagename">Gardening</span>
I can access them with Webdriver in a fairly ugly manner:
List<WebElement> elements;
elements = driver.findElements(By.xpath( ".//*[starts-with(#id, '135')]"));
...Because each starts with a '135'.
But driver.findElement(By.cssSelector(".pagename");
...does not work, perhaps something to do with the '' tags
What I now need to do, is do a .getText() for each element in the list and verify it against the expected, corresponding array value. I'm starting off thinking of this method:
String[] expected = {"Sport & leisure", "Food & drink", "Household", "Gardening"};
List<WebElement> elements = select.find.Elements(By.xpath( ".//*[starts-with(#id,'135')]"));
// compare #array items with #found elements in List
if (expected.length != elements.size()) {
System.out.println("the wrong number of elements were found");
}
// check value of every pagename class element equals expected value
for (int i = 0; i < expected.length; i++) {
String elementsValue = elements.get(i).getAttribute("value");
if (elementsValue.equals(expected[i])) {
System.out.println("passed on: " + elements);
} else {
System.out.println("failed on: " + elements);
}
}
This has the obvious limitation of potentially having to store 200 odd text strings in the array and will therefore become unwieldy. Is there a more elegant solution? I could read the array values in from a .csv I guess and used Parameterized runner but then I'd still need to declare each value in the constructor right?
You can use the Lists contains or containsAll function to determine equality. So basically like this:
final List<String> expectedElements = readFromCSV("expectedElements.csv");
final List<WebElement> elements = select.find.Elements(By.xpath( ".//*[starts-with(#id,'135')]"));
final List<String> stringElements = new ArrayList<>(elements.length);
for (WebElement element : elements) {
stringElements.add(element.getAttribute("value"));
}
final boolean isSame = stringElements.containsAll(expectedElements);
This is not a direct answer to your question, but only a few corrections to your code:
1.
You can replace the code that you consider "ugly":
List<WebElement> elements = select.findElements(By.xpath(".//*[starts-with(#id,'135')]"));
With a code that finds the elements using their class attribute:
List<WebElement> elements = select.findElements(By.xpath("//span[#class='pagename']"));
2.
Since non of these elements has a value attribute, you should replace the following line:
String elementsValue = elements.get(i).getAttribute("value");
With:
String elementsValue = elements.get(i).getAttribute("innerHTML");

Categories