Selenium WebDriver with Java - how to add "else" condition - java

I have code:
public void setList(By localizator, String v_value {
Select some_list = new Select(driver.findElement(localizator));
for(WebElement position_list : some_list.getOptions()) {
if(position_list.getText().equalsIgnoreCase(v_value)) {
some_list.selectByVisibleText(position_list.getText());
break;
}
}
}
How can I add condition: if selenium doesn't find position_list.getText().equalsIgnoreCase(v_value) then system throw new RuntimeExpression?

Use iterator instead of foreach, it provides a hasNext() method with which you can check if you are currently dealing with the last element of your list.
Iterator<WebElement> iterator = some_list.getOptions().iterator();
and then instead of your foreach:
while(iterator.hasNext()) {
WebElement current = iterator.next();
if(current.getText().equalsIgnoreCase(v_value)) {
current.selectByVisibleText(position_list.getText());
break;
}
if(!iterator.hasNext()){
throw new RuntimeException();
}
}

Just a suggestion from what I see in your code.
When you use some_list.selectByVisibleText(position_list.getText()); the selectByVisibleText(..) method is already setup to iterate over all available options and select the one that matches the text parameter you pass in. Putting the call inside a loop checking for the option to be available is not ideal if you are looking to throw an exception.
Also, let's say you have the following code -
public void setList(By localizator, String v_value {
Select some_list = new Select(driver.findElement(localizator));
some_list.selectByVisibleText(position_list.getText());
....
}
In this case selectByVisibleText would throw a NoSuchElementException("Cannot locate element with text: " + text); in case the option is not available for selection. You should be able to catch that and throw a runtime exception.

I guess a simple answer to your question is a try catch
public void setList(By localizator, String v_value {
Select some_list = new Select(driver.findElement(localizator));
for(WebElement position_list : some_list.getOptions()) {
try{
if(position_list.getText().equalsIgnoreCase(v_value)) {
some_list.selectByVisibleText(position_list.getText());
break;
}
}
catch(RuntimeExpression ex)
{
...
}
}
}

Related

How do I continue with next element in the Java Stream in case of exception?

I have a stream like this,
List<String> test = Arrays.asList("1", "2,", "3");
test.stream().map(t -> {
try {
validate(t);
} catch (Exception e) {
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage(), e);
}
return true;
})
In case of an exception, I would like to store it somewhere, process the next element and then show all exceptions at once. Is this possible?
Well, don't rethrow the exception:
var exceptions = test.stream().map(t -> {
try {
validate(t);
} catch (Exception e) {
return e;
}
return null;
})
.filter(Objects::nonNull) // if you don't need to preserve the index
.toList();
I modified your code slightly. Your main issue is that you're re-throwing that exception when you catch it -- that will stop processing at the first exception. Then you need some way to store the inputs that cause an error (that's what invalidInputs is for. I'm assuming that your next step is to actually use the results of that input to convert, otherwise you don't need to use map(), so my "validate" method also just does the conversion too. I use a JUnit test harness for stuff like this, and I left in the assert()s; you should take them (and the #Test annotation) out for your code.
//throws NumberFormatException if input doesn't parse into an integer
public static Integer validate(String input) throws Exception{
return Integer.parseInt(input);
}
#Test
public void testStreamMap() {
List<String> test = Arrays.asList("1", "2,", "3");
List<String> invalidInputs = new ArrayList<>();
List<Integer> result= test.stream().map(t -> {
Integer localResult;
try {
localResult=validate(t);
} catch (Exception e) {
invalidInputs.add(t);
localResult=null;
}
return localResult;
}).collect(Collectors.toList());
assertTrue(invalidInputs.contains("2,"));
assertFalse(result.contains(2));
}
You can try this approach to collect all the exceptions in a list as follows:
Here,
I have iterated over the list using forEach and in case of catch , added the exception e in the listOfExceptions list.
As I have entered three invalid inputs in the list , it is giving three exceptions in the list at the end corresponding to each element which is giving exception.
For the demo purpose, I have created one more list listOfElementsWithoutExceptions showing the elements which are processed without any exceptions.
Note: You can have your own custom exception list in place of List<Exception>.
public class Test2 {
public static void main(String[] args) {
List<String> test = Arrays.asList("test1", "test2", "3","4","test5","6");
List<Exception> listOfExceptions = new ArrayList<>();
List<String> listOfElementsWithoutExceptions = new ArrayList<>();
test.forEach(t -> {
try {
validate(t);
listOfElementsWithoutExceptions.add(t);
} catch (Exception e) {
listOfExceptions.add(e);
}
});
System.out.println("list of exceptions:: " + listOfExceptions);
System.out.println("list of elements without exceptions:: "+ listOfElementsWithoutExceptions);
}
private static void validate(String t) {
Integer.parseInt(t);
}
}
Output:
list of exceptions::
[java.lang.NumberFormatException: For input string: "test1",
java.lang.NumberFormatException: For input string: "test2",
java.lang.NumberFormatException: For input string: "test5"]
list of elements without exceptions:: [3, 4, 6]

Showing an Integer tableview in javaFx as a string

I am trying to show a tableview where when the value in the table is a integer like 1 for example I want to display a String. So far I tried to get the cellValue like this:
public void changeView() {
if(intervall.getCellFactory().call(intervall).equals(1)) {
intervall.getCellFactory().call(intervall).setText("Täglich");
}
}
And I am calling the method in my initialize after setting the cellvalue.
public void initializeTable() {
try {
// Ablesen
Statement pStatement = connection.createStatement();
flightList = FXCollections.observableArrayList();
ResultSet myRs = pStatement
.executeQuery("select * from fluglinie where fluggesellschaft =\"" + fluggesellschaft + "\"");
while (myRs.next()) {
flightList.add(new flightRouteAddModel(myRs.getString("startFlughafen"),
myRs.getString("zielFlughafen"), myRs.getString("startDatum"), myRs.getString("flugzeug"),
myRs.getInt("intervall"), myRs.getInt("anzahlEconomy"), myRs.getInt("anzahlBusiness"),
myRs.getFloat("preisEconomy"), myRs.getFloat("preisBusines"), myRs.getFloat("distanz")));
}
} catch (Exception e) {
System.out.println(e);
}
startAirport.setCellValueFactory(new PropertyValueFactory<>("startAirport"));
targetAirport.setCellValueFactory(new PropertyValueFactory<>("targetAirport"));
flightDate.setCellValueFactory(new PropertyValueFactory<>("flightDate"));
airplane.setCellValueFactory(new PropertyValueFactory<>("airPlane"));
intervall.setCellValueFactory(new PropertyValueFactory<>("intervall"));
seatCountEco.setCellValueFactory(new PropertyValueFactory<>("countEconomy"));
seatCountBus.setCellValueFactory(new PropertyValueFactory<>("countBusiness"));
priceEco.setCellValueFactory(new PropertyValueFactory<>("priceEconomy"));
priceBus.setCellValueFactory(new PropertyValueFactory<>("priceBusiness"));
distance.setCellValueFactory(new PropertyValueFactory<>("distance"));
table.setItems(flightList);
changeView();
}
But it is not working can someone maybe take a look at this? I know changing the db would be maybe a better solution but I kinda wanted to try this workaround
The cellFactory returns TableCells. Calling this yourself does not result in a cell that is part of the TableView (or becomes part of it). Any TableCell with a properly impelemented equals method never yields true, if 1 (or any other Integer) is passed.
Assuming you always want to display Täglich instead of 1, the way to go about this is using a custom cellFactory for this column:
intervall.setCellFactory(col -> new TableCell<flightRouteAddModel, Integer>() {
#Override
protected void updateItem(Integer item, boolean empty) {
String text = "";
if (item != null) {
switch(item) {
case 1:
text = "Täglich";
break;
case 7:
text = "Wöchentlich";
break;
default:
text = String.format("Alle %d Tage", item);
break;
}
}
setText(text);
}
});
BTW: Please learn about the java naming conventions. This makes the code easier to read for other people and it should make this more readable even for yourself, since all java APIs (that I know of) use these conventions: Type names start with an uppercase letter.

Stale Object Reference while Navigation using Selenium

I have been trying a simple program that navigates and fetches data from the new page, comes back in history and open other page and fetch data and so on until all the links have been visited and data is fetched.
After getting results on the below site, i am trying to loop through all the links i get in the first column and open those links one by one and extract text from each of these page. But the below program only visits first link and gives StaleElementReferenceException, I have tried using Actions but it didn't work and I am not aware about JavascriptExecutor. I also tried solutions posted on other SO questions, one of which was mine over here. I would like to have the mistake corrected in the below code and a working code.
public class Selenium {
private final static String CHROME_DRIVER = "C:\\Selenium\\chromedriver\\chromedriver.exe";
private static WebDriver driver = null;
private static WebDriverWait wait = null;
private void setConnection() {
try {
System.setProperty("webdriver.chrome.driver", CHROME_DRIVER);
driver = ChromeDriver.class.newInstance();
wait = new WebDriverWait(driver, 5);
driver.get("https://sanctionssearch.ofac.treas.gov");
this.search();
} catch (Exception e) {
e.printStackTrace();
}
}
private void search() {
try {
driver.findElement(By.id("ctl00_MainContent_txtLastName")).sendKeys("Dawood");
driver.findElement(By.id("ctl00_MainContent_btnSearch")).click();
this.extractText();
} catch (Exception e) {
e.printStackTrace();
}
}
private void extractText() {
try {
List<WebElement> rows = driver.findElements(By.xpath("//*[#id='gvSearchResults']/tbody/tr"));
List<WebElement> links = null;
for (int i = 1; i <= rows.size(); i++) {
links = driver.findElements(By.xpath("//*[#id='gvSearchResults']/tbody/tr/td[1]/a"));
for (int j = 0; j < links.size(); j++) {
System.out.println(links.get(j).getText() + ", ");
links.get(j).click();
System.out.println("Afte click");
driver.findElement(By.id("ctl00_MainContent_btnBack")).click();
this.search();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] ar) {
Selenium object = new Selenium();
object.setConnection();
}
}
Generally we will be getting the Stale Exception if the element attributes or something is changed after initiating the webelement. For example, in some cases if user tries to click on the same element on the same page but after page refresh, gets staleelement exception.
To overcome this, we can create the fresh webelement in case if the page is changed or refreshed. Below code can give you some idea.
Example:
webElement element = driver.findElement(by.xpath("//*[#id='StackOverflow']"));
element.click();
//page is refreshed
element.click();//This will obviously throw stale exception
To overcome this, we can store the xpath in some string and use it create a fresh webelement as we go.
String xpath = "//*[#id='StackOverflow']";
driver.findElement(by.xpath(xpath)).click();
//page has been refreshed. Now create a new element and work on it
driver.fineElement(by.xpath(xpath)).click(); //This works
In this case, we are collecting a group of webelements and iterating to get the text. But it seems there is some changes in the webelement after collecting the webelements and gettext throws staleness. We can use a loop and create the element on the go and get text.
for(int i = 0; i<5; i++)
{
String value = driver.findElement(by.xpath("//.....["+i+"]")).getText);
System.out.println(value);
}
Hope this helps you. Thanks.
The reason you get StaleElementReference Exception, is normally because you stored element(s) into some variable, however after that you did some action and page has changed (due to some ajax response) and so your stored element has become stale.
The best solution is not to store element in any variable in such case.
This should work.
links = driver.findElements(By.xpath("//*[#id='gvSearchResults']/tbody/tr/td[1]/a"));
for (int j = 0; j < links.size(); j++) {
System.out.println(links.get(j).getText() + ", ");
driver.findElements(By.xpath("//*[#id='gvSearchResults']/tbody/tr/td[1]/a")).get(j).click();
System.out.println("Afte click");
driver.findElement(By.id("ctl00_MainContent_btnBack")).click();
this.search();
}
Please check this code
private void extractText() {
try {
List<WebElement> rows = driver.findElements(By.xpath("//*[#id='gvSearchResults']/tbody/tr"));
List<WebElement> links = null;
System.out.println(rows.size());
for (int i = 0; i < rows.size(); i++) {
links = driver.findElements(By.xpath("//*[#id='gvSearchResults']/tbody/tr/td[1]/a"));
WebElement ele= links.get(0);
System.out.println(ele.getText() + ", ");
ele.click();
System.out.println("After click");
driver.findElement(By.id("ctl00_MainContent_btnBack")).click();
}
} catch (Exception e) {
e.printStackTrace();
}
}

Java Selenium: How to validate xpath?

I am trying to find an element using xpath.
I tried this method:
if(a_chromeWebdriver.findElement(By.xpath(XPATH1)) != null){
homeTable = a_chromeWebdriver.findElement(By.xpath(XPATH1));
}
else{
homeTable = a_chromeWebdriver.findElement(By.xpath(XPATH2));
}
I assumed that if the first xpath won't be found, it will try he second one. But it throws an exception of element not found.
I also tried to check size = 0 instead of null, but got the same result.
You can use this method to check whether your xpath is present or not :
create a method : isElementPresent
public boolean isElementPresent(By by) {
try {
driver.findElements(by);
return true;
} catch (org.openqa.selenium.NoSuchElementException e) {
return false;
}
}
Call it using xpath like this :
isElementPresent(By.xpath(XPATH1));
So your code would become :
if(isElementPresent(By.xpath(XPATH1))){
homeTable = a_chromeWebdriver.findElement(By.xpath(XPATH1));
}
else{
homeTable = a_chromeWebdriver.findElement(By.xpath(XPATH2));
}
You could use findElements instead of findElement and then check the size:
List<WebElement> elements = a_chromeWebdriver.findElements(By.xpath(XPATH1));
if(elements.size() > 0){
homeTable = elements.get(0);
} else{
homeTable = a_chromeWebdriver.findElement(By.xpath(XPATH2));
}
But a better way would be to combine the 2 XPath in a single one with |:
homeTable = a_chromeWebdriver.findElement(By.xpath(XPATH1 + "|" + XPATH2));
You could create a method,
public WebElement getElement(By by) {
try {
return a_chromeWebdriver.findElement(by);
} catch (org.openqa.selenium.NoSuchElementException e) {
return null;
}
}
You could use it as follows,
WebElement element = getElement(By.xpath(XPATH1));
if (element == null)
element = getElement(By.xpath(XPATH2));
First add implicit wait to your code that will handle synchronization issues
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
Add OR Operator rather than adding condition as other answers points out. homeTable = a_chromeWebdriver.findElement(By.xpath(XPATH1 | XPATH2));

Change method findByOneCss that he received more than one meaning and all

This is the method itself
private static WebElement findByOneCss (WebElement we, String selector) {
try {
return we.findElement (By.cssSelector (selector));
} catch (NoSuchElementException e) {
return null;
}
}
I understand that you need to change to findElement findElements but do not get to take account of all the views.
I have a loop that bypasses the values ​​here he
for (WebElement wle: wlElements) {
WebElement commenWe = findByOneCss (wle, ".activity-new-val");
wl.setReason1 (commenWe! = null? commenWe.getText (): "");
wlList.add (wl);
}
What does it need to change, I tried to like this
List <WebElement> commenWe = findAllByOneCss (wle, ".activity-old-val");
wl.setReason (commenWe! = null? ((WebElement) commenWe) .getText (): "");
wlList.add (wl);
But it beats mistake java.util.ArrayList can not be cast to org.openqa.selenium.WebElement
Depending on what type wlList is you could use: wlList.addAll(commenWe);
Or you iterate over commenWe like this:
List<WebElement> commenWe = findAllByOneCss(wle, ".activity-old-val");
for (WebElement we : commenWe) {
//whatever [wl] is...
wl.setReason(we!=null ? ((WebElement) we).getText(): "");
wlList.add(wl);
}

Categories