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;
}
}
}
Related
I'm writing a Java bot with https://github.com/rubenlagus/TelegramBots, and I have a problem, when I click inline keyboard button, this little clock:
appears and after some time it says that my bot is not responding. My bot is actually fully functional except this one thing. Here is how I receive callbacks:
#Override
public void onUpdateReceived(Update update) {
var messagesToSend = updateReceiver.handle(update);
if (messagesToSend != null && !messagesToSend.isEmpty()) {
messagesToSend.forEach(response -> {
if (response instanceof SendMessage) {
try {
execute((SendMessage) response);
} catch (TelegramApiException e) {
e.printStackTrace();
}
} else if (response instanceof SendPhoto) {
try {
execute((SendPhoto) response);
} catch (TelegramApiException e) {
e.printStackTrace();
}
} else if (response instanceof FileSaveRequest) {
FileSaveRequest request = (FileSaveRequest) response;
try {
saveFile(request);
} catch (TelegramApiException | IOException e) {
e.printStackTrace();
}
}
});
}
}
=
This is only part of the whole code
} else if (update.hasCallbackQuery()) {
final CallbackQuery callbackQuery = update.getCallbackQuery();
final long chatId = callbackQuery.getFrom().getId();
final User user = userRepository.findById(chatId)
.orElseGet(() -> userRepository.save(new User(chatId)));
AnswerCallbackQuery acceptCallback = new AnswerCallbackQuery();
acceptCallback.setShowAlert(false);
acceptCallback.setCallbackQueryId(String.valueOf(update.getCallbackQuery().getId()));
acceptCallback.setCacheTime(1000);
List<PartialBotApiMethod<? extends Serializable>> resultList =
new ArrayList<>(
getHandlerByCallBackQuery(callbackQuery.getData())
.handle(user, callbackQuery.getData()));
resultList.add(acceptCallback);
return resultList;
}
As you can see, I still attach AnswerCallbackQuery but it still doesent work. What's wrong?
you must use answercallbackquery
I just already solve that issue. It's not problem on Library but it could error in some exceptions.
var messagesToSend = updateReceiver.handle(update);
if (messagesToSend != null && !messagesToSend.isEmpty()) {
I dont have full your code but I think there's some confused written and happen exception before if (update.callbackQuery())...
Here is my sample:
#Override
public void onUpdateReceived(Update update) {
// I have error, cannot getCallbackQuery because of print which call method getMessage.getText() is null -> happen exception error on the println
// -> System.out.println(update.getMessage.getText());
if (update.hasMessage() && !update.getMessage().getText().isEmpty()) {
String chat_id = update.getMessage().getChatId().toString();
if (update.getMessage().getText().equals("/start")) {
SendMessage sendMessage = new SendMessage();
sendMessage.setText("Here is option:");
sendMessage.setChatId(chat_id);
sendMessage.setParseMode(ParseMode.MARKDOWN);
InlineKeyboardMarkup inlineKeyboardMarkup = new InlineKeyboardMarkup();
List<List<InlineKeyboardButton>> listInlineButton = new ArrayList<>();
List<InlineKeyboardButton> reportSaleBtn = new ArrayList<>();
List<InlineKeyboardButton> reportBuyBtn = new ArrayList<>();
List<InlineKeyboardButton> reportPriceBtn = new ArrayList<>();
InlineKeyboardButton saleBtn = new InlineKeyboardButton();
InlineKeyboardButton buyBtn = new InlineKeyboardButton();
InlineKeyboardButton priceBtn = new InlineKeyboardButton();
saleBtn.setText(Constant.SALE_REPORT_TEXT);
saleBtn.setCallbackData(Constant.SALE_REPORT);
buyBtn.setText(Constant.BUY_REPORT_TEXT);
buyBtn.setCallbackData(Constant.BUY_REPORT);
priceBtn.setText(Constant.PRICE_TEXT);
priceBtn.setCallbackData(Constant.PRICE_REPORT);
reportSaleBtn.add(saleBtn);
reportBuyBtn.add(buyBtn);
reportPriceBtn.add(priceBtn);
listInlineButton.add(reportSaleBtn);
listInlineButton.add(reportBuyBtn);
listInlineButton.add(reportPriceBtn);
inlineKeyboardMarkup.setKeyboard(listInlineButton);
sendMessage.setReplyMarkup(inlineKeyboardMarkup);
try {
execute(sendMessage);
} catch (TelegramApiException e) {
e.printStackTrace();
}
}
}
else if (update.hasCallbackQuery()) {
CallbackQuery callbackQuery = update.getCallbackQuery();
String data = callbackQuery.getData();
String chat_id = callbackQuery.getMessage().getChat().getId().toString();
SendChatAction sendChatAction = new SendChatAction();
if (data.equals(Constant.SALE_REPORT)) {
sendChatAction.setChatId(chat_id);
SendMessage sendMessage = new SendMessage();
sendMessage.setText("Generating report, please wait!");
sendMessage.setChatId(chat_id);
try {
sendChatAction.setAction(ActionType.TYPING);
execute(sendChatAction);
execute(sendMessage);
} catch (TelegramApiException e) {
e.printStackTrace();
}
}
}
Why it got an error. Click we click on /start Bot will display all inlinekeyboard.
In the button you only setText() and setCallbackData(). So update.GetMessage() is null.
In while update.getMessage().getText() is null cannot print out. So it is error and it skip the else if (update.hasCallbackQuery()) {...}
I think you can check again your code below:
#Override
public void onUpdateReceived(Update update) {
//check carefully before if may there's exception error before if
}
I hope what I explain may solve your problems too.
How to verify whether file downloading is completed before closing my Selenium web driver in JAVA.
I have written a Selenium code to download 2 files to my desired folder location. However I close the browser instantly after clicking on the 2 links, which given me the downloaded files as temporary files or with an invalid extension. I used Thread.sleep method after clicking on the each of the two links before closing the web driver and it is now working fine.
I need to know whether there is an optimum method to check whether download is completed or not before closing the web driver using explicit method or any other way rather setting a pre-defined time using the Thread.sleep() method.
Here is part of the source code (JAVA, Selenium and Testng) which is relevant to this question.
// Text file download
#Test(priority=2)
public void txtFileDownloadTest() {
fileDownloadPage.clickTxtFileLink();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// Java file download
#Test(priority=3)
public void javaFileDownloadTest() {
fileDownloadPage.clickJavaFileLink();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#AfterClass
public void setDown() {
closeUp();
}
There is a piece of code I was using to download files. Just change fileName and increase timeout in waitSec(driver, int).
public WebDriverWait waitSec(WebDriver driver, int sec) {
return new WebDriverWait(driver, sec);
}
String fileName = "foo";
String filePathFull = "C:/users/user/downloads/" + fileName + ".csv";
waitSec(driver, 30).until(new Function<WebDriver, Boolean>() {
public Boolean apply(WebDriver driver) {
if(Files.exists(Paths.get(filePathFull))) {
return true;
}
else {
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
}
}
return false;
}
});
File exportFile = new File(filePathFull);
if (Files.size(Paths.get(filePathFull)) == 0) {
try {
waitSec(driver, 120).until(new Function<WebDriver, Boolean>() {
public Boolean apply(WebDriver driver) {
try {
if(Files.size(Paths.get(filePathFull)) > 0) {
return true;
}
else {
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
}
}
}
catch (IOException e) {
}
return false;
}
});
}
catch (TimeoutException e) {
}
}
There is always a .part file and until download is complete orginial file (csv in my example) has zero size.
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.
I tried the following solutions to Verify that the button is not displayed for a particular user-group.None of the solutions work. I get a no such element exception with the codes.
Please let me know if there is anything else i can try.
try {
boolean btnPresence = driver.findElement(By.linkText("/html/body/div/div/div/main/div[2]/div[2]/div/form/button")).isDisplayed();
}
catch (org.openqa.selenium.NoSuchElementException e)
{
return;
}
}
Assert.assertTrue(driver.findElement(By.xpath("/html/body/div/div/div/main/div[2]/div[2]/div/form/button")).isDisplayed());
if (driver.findElement(By.xpath("/html/body/div/div/div/main/div[2]/div[2]/div/form/button")).isDisplayed()) {
System.out.println("Fail! Submit button is displayed for a CMS Admin on the ORC TA Form.");}
else {
System.out.println("Pass!!- Submit Button is not displayed for CMS Admin on the ORC TA Form");
}
boolean elePresent = driver.findElement(By.xpath("/html/body/div/div/div/main/div[2]/div[2]/div/form/button")).isDisplayed();
boolean elePresent = driver.findElement(By.xpath("/html/body/div/div/div/main/div[2]/div[2]/div/form/button")).isDisplayed();
boolean exist = driver.findElement(By.xpath("/html/body/div/div/div/main/div[2]/div[2]/div/form/button")).size() == 0;
You can check if the element exists or not:
public boolean existsElement_byXpath(String xpath) {
try {
driver.findElement(By.xpath(xpath));
} catch (NoSuchElementException e) {
return false;
}
return true;
}
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);
}
}