JavaFX application permanently freezing when executing loops on Selenium - java

I got the following code:
exch.setOnAction(e -> {
for (int i = 0; i < 10; i++) {
BrowserThread.driver.findElement(By.linkText("Premium Exchange")).click();
String strVal = BrowserThread.driver.findElement(By.id("premium_exchange_stock_wood")).getText();
String strVal2 = BrowserThread.driver.findElement(By.id("premium_points")).getText();
int intVal = Integer.parseInt(strVal);
int intVal2 = Integer.parseInt(strVal2);
if (intVal >= 64 && intVal2 >= 1) {
BrowserThread.driver.findElement(By.name("buy_wood")).clear();
BrowserThread.driver.findElement(By.name("buy_wood")).sendKeys("64"); //enter 64 in the 'buy box'
BrowserThread.driver.findElement(By.xpath("//input[#value='Calculate best offer ']")).click(); //click calculate best offer
BrowserThread.driver.findElement(By.xpath("//div[#id='premium_exchange']/div/div[2]/button")).click(); //click buy
try {
Thread.sleep(10000);
} catch (InterruptedException ex) {
Logger.getLogger(BrowserTab.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
LogTab.log.appendText("Not enough premium points.\n");
}
if (stop.isPressed()) {
LogTab.log.appendText("Stopped task.\n");
break;
}
try {
Thread.sleep(5000);
} catch (InterruptedException ex) {
Logger.getLogger(MarketTab.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
It basically refreshes a webpage infinitely when a button is pressed on the GUI.
There is a button to start the loop (exch), and a button to break the loop (stop). But my problem is, the GUI freezes when it executes tasks on the browser. This applies to everything, not just this for-loop.
For example, I have a run-button to open the selenium web browser. The GUI freezes until the web browser has loaded completely.
I checked around and found out I have to use threads, but I have no idea where to start. I tried making a separate class for the browser to run on a different thread, but that didn't work and I can't seem to find out what I did wrong.
BrowserThread class:
public class BrowserThread extends Thread {
static WebDriver driver;
private String baseUrl;
private String browsertype;
public BrowserThread(String name, String browsertype) {
super(name);
this.browsertype = browsertype;
}
// set up method to initialize driver object
public void setUp(String browsertype) throws Exception {
if (browsertype.contains("Chrome")) {
System.setProperty("webdriver.chrome.driver","res\\chromedriver.exe");
driver = new ChromeDriver();
} else if (browsertype.contains("PhantomJS")) {
driver = new PhantomJSDriver();
System.setProperty("phantomjs.binary.path", "res\\phantomjs.exe");
} else if (browsertype.contains("PhantomJS Linux")) {
driver = new PhantomJSDriver();
System.setProperty("phantomjs.binary.path", "res/phantomjs.exe");
}
baseUrl = "https://www.google.com/";
driver.get(baseUrl);
}
}

Related

Why Class.forName() in static code terminate the process when using mutil-thread? [duplicate]

This question already has answers here:
JUnit terminates child threads
(6 answers)
Closed 2 years ago.
I'm currently learning JDBC. And I try to update the product information and insert a log at the same time.
private void testTransaction() {
try {
// Get Connection
Connection connection = ConnectionUtils.getConnection();
connection.setAutoCommit(false);
// Execute SQL
Product product = new Product(1, 4000d);
productService.updateProduct(connection, product);
Log log = new Log(true, "None");
logService.insertLog(connection, log);
// Commit transaction
connection.commit();
} catch (Exception e) {
e.printStackTrace();
} finally {
ConnectionUtils.closeConnection();
}
}
When using single thread, it would be fine.
#Test
public void testMultiThread() {
testTransaction();
}
But When I using multi-thread, even start one thread, the process would terminate automatically.
#Test
public void testMultiThread() {
for (int i = 0; i < 1; i++) {
new Thread(this::testTransaction).start();
}
}
After debugging, I found that it was Class.forName() function in ConnectionUtils cause this situation.
public class ConnectionUtils {
static private String url;
static private String driver;
static private String username;
static private String password;
private static Connection connection = null;
private static ThreadLocal<Connection> t = new ThreadLocal<>();
static {
try {
Properties properties = new Properties();
properties.load(new FileReader("src/main/resources/jdbcConnection.properties"));
driver = properties.getProperty("driver");
url = properties.getProperty("url");
username = properties.getProperty("username");
password = properties.getProperty("password");
Class.forName(driver);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() {
try {
connection = DriverManager.getConnection(url, username, password);
} catch (Exception e) {
e.printStackTrace();
} finally {
t.set(connection);
}
return connection;
}
}
The process will terminate at Class.forName(). I found this by adding two print funcion before and after the statement. And only the former works.
System.out.println("Before");
Class.forName(driver);
System.out.println("After");
The console only print the Before and doesn't show any exception information.
I want to know that why multi-thread in java will cause this situation and how to solve this problem.
This is more likely your test method complete before your other threads and the test framework is not waiting (junit?). You need to wait until the threads have completed. You should use an Executors, this is more convinient.
#Test
public void testMultiThread() {
Thread[] threads = new Thread[1];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(this::testTransaction);
threads[i].start();
}
// wait thread completion
for (Thread th : threads) {
th.join();
}
}
Junit will terminate all your thread as long as the test method finish.
In your case, test will finish when the loop ends, it doesn't care whether
testTransaction has finished. It has nothing to do with class.forName , maybe it's just because this method exceute longer.
you can check this answer

Selenium: How to avoid StaleElementReferenceException when looping through a set of elements?

I have a page that contains a bunch of tables. I loop through the tables in the outer loop and then loop through each row in the table in the inner loop. It all works fine. But some of the pages have a Next button. When I add code to click that after completing the page, then I start getting StaleElementReferenceException while looping through the rows of a table.
Here is the code:
WebDriverWait wait1 = new WebDriverWait(driver, 10000);
WebElement maxPage = null;
WebElement auctionsWaitingDiv = driver.findElement(By.cssSelector("div[class='Head_W']"));
if (auctionsWaitingDiv.isDisplayed() == false) return properties;
try {
maxPage = wait1.until(ExpectedConditions.visibilityOfElementLocated(By.id("maxWA")));
} catch (TimeoutException ex) {
return properties;
}
Integer maxPageNo = 1;
if (!maxPage.getText().isEmpty())
maxPageNo = Integer.parseInt(maxPage.getText());
for (int i = 1; i <= maxPageNo; i++) {
driver.findElement(By.cssSelector("div[id='Area_W']")); //only look at Auctions Waiting section
WebDriverWait wait2 = new WebDriverWait(driver, 10000);
List<WebElement> tables = null;
try {
tables = wait2.until(ExpectedConditions.visibilityOfAllElementsLocatedBy(By.cssSelector("table[class='ad_tab']")));
} catch (TimeoutException ex) {
System.out.println("table not found in allotted time");
return properties;
} catch (StaleElementReferenceException ex) {
System.out.println("returning due to StaleElementReferenceException");
return properties;
}
for (WebElement table: tables) {
List<String> propAttributes = new ArrayList<>();
// StaleElementReferenceException: The element reference of
// <table class="ad_tab"> is stale; either the element is no
// longer attached to the DOM, it is not in the current
// frame context, or the document has been refreshed
List<WebElement> rows = table.findElements(By.cssSelector("tr"));
String parcelLink = "";
for (WebElement row : rows) {
WebElement key = row.findElement(By.cssSelector("th"));
WebElement val = row.findElement(By.cssSelector("td"));
String keyVal = key.getText() + val.getText();
propAttributes.add(keyVal);
if (key.getText().equals("Parcel ID:")) {
WebElement a = val.findElement(By.cssSelector("a"));
parcelLink = a.getAttribute("href");
}
}
}
driver.findElement(By.xpath(".//*[#class='PageRight']")).click(); //click the "Next" button
}
What I don't understand is why the stale element is happening at all? The page is not changing during the loop and I've waited until all elements have been fetched. How to avoid the StaleElementReferenceException?
Edit: The last stack trace shows it is happening in this line:
List<WebElement> rows = table.findElements(By.cssSelector("tr"));
and the error message above it shows:
SEVERE: null
org.openqa.selenium.StaleElementReferenceException: The element reference of <table class="ad_tab"> is stale; either the element is no longer attached to the DOM, it is not in the current frame context, or the document has been refreshed
The StaleElementReferenceException is thrown whenever you want to access an element reference which is not available anymore. This happens when the element is no longer attached to the DOM or if the page was updated.
The solution for this is just searching for the element again whenever this happens.
You could adapt all your tests or page objects. Or you write your own RobustWebDriver and RobustWebElement which refreshes the element if a SERE is thrown.
RobustWebDriver:
public class RobustWebDriver implements WebDriver {
private WebDriver originalWebDriver;
public RobustWebDriver(WebDriver webDriver) {
this.originalWebDriver = webDriver;
}
#Override
public void get(String url) {
this.originalWebDriver.get(url);
}
#Override
public String getCurrentUrl() {
return this.originalWebDriver.getCurrentUrl();
}
#Override
public String getTitle() {
return this.originalWebDriver.getTitle();
}
#Override
public List<WebElement> findElements(By by) {
List<WebElement> elements = new ArrayList<>();
for (WebElement element : this.originalWebDriver.findElements(by)) {
elements.add(new RobustWebElement(element, by, this));
}
return elements;
}
#Override
public WebElement findElement(By by) {
return new RobustWebElement(this.originalWebDriver.findElement(by), by, this);
}
#Override
public String getPageSource() {
return this.originalWebDriver.getPageSource();
}
#Override
public void close() {
this.originalWebDriver.close();
}
#Override
public void quit() {
this.originalWebDriver.quit();
}
#Override
public Set<String> getWindowHandles() {
return this.originalWebDriver.getWindowHandles();
}
#Override
public String getWindowHandle() {
return this.originalWebDriver.getWindowHandle();
}
#Override
public TargetLocator switchTo() {
return this.originalWebDriver.switchTo();
}
#Override
public Navigation navigate() {
return this.originalWebDriver.navigate();
}
#Override
public Options manage() {
return this.originalWebDriver.manage();
}
}
RobustWebElement:
public class RobustWebElement implements WebElement {
private WebElement originalElement;
private RobustWebDriver driver;
private By by;
private static final int MAX_RETRIES = 10;
public RobustWebElement(WebElement element, By by, RobustWebDriver driver) {
this.originalElement = element;
this.by = by;
this.driver = driver;
}
#Override
public void click() {
int retries = 0;
while (retries < MAX_RETRIES) {
try {
this.originalElement.click();
return;
} catch (StaleElementReferenceException ex) {
refreshElement();
}
retries++;
}
throw new StaleElementReferenceException(
String.format("Element is still stale after %s retries.", MAX_RETRIES));
}
#Override
public void sendKeys(CharSequence... keysToSend) {
int retries = 0;
while (retries < MAX_RETRIES) {
try {
this.originalElement.sendKeys(keysToSend);
return;
} catch (StaleElementReferenceException ex) {
refreshElement();
}
retries++;
}
throw new StaleElementReferenceException(
String.format("Element is still stale after %s retries.", MAX_RETRIES));
}
// TODO add other unimplemented methods with similar logic.
private void refreshElement() {
this.originalElement = driver.findElement(by);
}
And then you just need to wrap your WebDriver into the RobustWebDriver and you are ready to go:
WebDriver driver = new RobustWebDriver(new ChromeDriver());
EDIT:
Of course you need to take care of scrolling up and down by yourself.
Well after tearing my hair out for a day, I finally realized what was happening. It should have been obvious to me. When the "Next" button is clicked, it takes some time for the new page to load. By simply adding a delay, the new DOM is loaded and processing begins on it, not again on the previous one!
driver.findElement(By.xpath(".//*[#class='PageRight']")).click();
try {
Thread.sleep(4000); //provide some time for the page to load before processing it
} catch (InterruptedException ex) {
Logger.getLogger(RealAuction.class.getName()).log(Level.SEVERE, null, ex);
}
Now it runs to completion with no StaleElementReferenceException.

Unreachable code in SeleniumWebDriver

I was with a element is not attached to the page document in my Java script for automation using SeleniumWebDriver.
I searched the internet and found the script below that solved the error element is not attached to the page document.
boolean breakIt = true;
while (true) {
breakIt = true;
try {
Select acao = new Select(driver.findElement(By.id("cboSubMotivo")));
acao.selectByValue("519");
} catch (Exception e) {
if (e.getMessage().contains("element is not attached")) {
breakIt = false;
}
}
}
I continued the automation process and right after the above script, I added the code below to select an option within a DropDown List.
Select status = new Select(driver.findElement(By.id("cboStatus")));
At this point Eclipse displays the error message: Unreachable code.
I searched the internet but did not find anything about the error message regarding SeleniumWebDriver.
Here is the complete code and error message displayed by Eclipse.
public class validarStatus {
static WebDriver driver;
#Before
public void setUp() throws Exception {
System.setProperty("webdriver.chrome.driver", "E:\\Selenium\\chromedriver.exe");
}
#Test
public void logarBkoMais() throws InterruptedException {
WebDriver driver = new ChromeDriver();
driver.get("http://10.5.9.45/BKOMais_S86825EstrategiaBackOfficeClaroFixo");
driver.manage().window().maximize();
// Logar BkoMais
driver.findElement(By.id("matricula_I")).sendKeys("844502");
driver.findElement(By.id("senha_I")).sendKeys("Pw34Jdt#*");
driver.findElement(By.id("bt_entrar")).click();
// Logar na Estratégia
driver.findElement(By.id("mn_backoffice")).click();
driver.findElement(By.id("mn_bkoffice_prod_203")).click();// Produto
driver.findElement(By.id("mn_bkoffice_est_57")).click();// Estratégia
// Selecionado a atividade
Select atividade = new Select(driver.findElement(By.id("cboAtividade")));
atividade.selectByIndex(3);
// Registro >> Novo
Thread.sleep(500);
driver.findElement(By.id("mn_registro")).click();
driver.findElement(By.id("mn_novo_caso")).click();
// Cod Os Estratégia VREL
String CodOs = driver.findElement(By.xpath("//*[#id=\"content\"]/div[1]/fieldset[1]/div[2]/div[3]/span"))
.getText();
System.out.println(CodOs);
// Campo Análise de Contrato
Select analiseContrato = new Select(driver.findElement(By.id("cboMotivo")));
analiseContrato.selectByIndex(5);
// Campo Ação
boolean breakIt = true;
while (true) {
breakIt = true;
try {
Select acao = new Select(driver.findElement(By.id("cboSubMotivo")));
acao.selectByValue("519");
} catch (Exception e) {
if (e.getMessage().contains("element is not attached")) {
breakIt = false;
}
}
}
Select status = new Select(driver.findElement(By.id("cboStatus")));
}
#After
public void tearDown() throws Exception {
}}
As I am understand correct, there's no guarantee for compiler that code above while statement will run. It will run only when there would be exception thrown and the while-loop breaks. Moreover your breakIt isn't changing at all. As I think right this code will be work right:
while (breakIt) {
breakIt = true;
try {
Select acao = new Select(driver.findElement(By.id("cboSubMotivo")));
acao.selectByValue("519");
} catch (Exception e) {
if (e.getMessage().contains("element is not attached")) {
breakIt = false;
}
}
}

Proper way to pass a webdriver to another class

I want to pass my WebDriver to another class instead of passing it to the individual methods within that class. That would mean passing it to the constructor of the class when I create an instance of it. Here is my code, and my issue further below -
public class StepDefinitions{
public static WebDriver driver = null;
CustomWaits waits;
#Before("#setup")
public void setUp() {
driver = utilities.DriverFactory.createDriver(browserType);
System.out.println("# StepDefinitions.setUp(), driver = " + driver);
waits = new CustomWaits(driver);
}
}
public class CustomWaits {
WebDriver driver;
public CustomWaits(WebDriver driver){
this.driver = driver;
}
public boolean explicitWaitMethod(String id) {
boolean status = false;
try {
WebDriverWait wait = new WebDriverWait(driver, 30);
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id(id)));
status = element.isDisplayed();
} catch (NullPointerException e){
e.printStackTrace();
}
return status;
}
}
The error I am getting in is NullPointerException when a method of that class is called within an #Given, #When, etc. This is a scope issue I cannot resolve.
Feature File:
#test
Feature: Test
#setup
Scenario: Navigate to Webpage and Assert Page Title
Given I am on the "google" Website
Then page title is "google"
Here is the step definition:
#Given("^element with id \"([^\"]*)\" is displayed$")
public void element_is_displayed(String link) throws Throwable {
if (waits.explicitWaitMethod(link)) {
// This is where waits becomes null when I put a breakpoint
driver.findElement(By.id(link)).isDisplayed();
} else {
System.out.println("Timed out waiting for element to display");
}
}
I would do something like this.
public class StepDefinitions{
public StepDefinitions() {
driver = utilities.DriverFactory.createDriver(browserType);
System.out.println("# StepDefinitions.setUp(), driver = " + driver);
waits = new CustomWaits(driver);
}
public static WebDriver driver = null;
public static CustomWaits waits;
#Given("^element with id \"([^\"]*)\" is displayed$")
public void element_is_displayed(String link) throws Throwable {
if (waits.explicitWaitMethod(link)) {
// This is where waits becomes null when I put a breakpoint
driver.findElement(By.id(link)).isDisplayed();
} else {
System.out.println("Timed out waiting for element to display");
}
}
}
public class CustomWaits {
private static WebDriver driver;
public CustomWaits(WebDriver driver){
this.driver = driver;
}
public boolean explicitWaitMethod(String id) {
boolean status = false;
try {
WebDriverWait wait = new WebDriverWait(driver, 30);
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id(id)));
status = element.isDisplayed();
} catch (NullPointerException e){
e.printStackTrace();
}
return status;
}
}

Updating a TextArea via setText clears all text

I made a chatroom, server and client, in java.
Here is the code were my onlinelist messes up:
public void run() {
try {
while (true) {
String message = din.readUTF();
if (message.startsWith("CONNECTEDLISTEDWOOOOOOOOT")) {
ConnectedList con = new ConnectedList();
if (demanded == 1) {
con.ta.setText(message.substring(26));
con.setSize(200, 400);
con.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
con.setVisible(true);
demanded = 0;
} else {
con.ta.setText(message.substring(26));
}
} else {
ta.append(message+"\n");
if(!lol.isActive()) {
InputStream in = getClass().getResourceAsStream("bleep.wav");
AudioStream as = new AudioStream(in);
AudioPlayer.player.start(as);
}
}
}
} catch(IOException ie) { System.out.println(ie); }
}
this block of code works perfectly:
if (demanded == 1) {
con.ta.setText(message.substring(26));
con.setSize(200, 400);
con.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
con.setVisible(true);
demanded = 0;
}
It creates a new window using JFrame just with a textlabel(ta) with all connected users on it, also demanded just controls wether the frame is already opened or not.
Then the part were it gets messed up:
else {
con.ta.setText(message.substring(26));
}
Here it's just supposed to refresh the list by setting the text to the new list
but instead of doing that, it just wipes the window.
How can I fix it?
Before:
After:
well, I just found out the problem just putting:
ConnectedList con = new ConnectedList();
at the top by all other variables, and now it does work,

Categories

Resources