Selenium Java (proper wait for new page to load) - selenium

It's not a question but rather a sharing of information (i think many people will use it)
For few days tried to make one best solution (without sheninigans :-D ) to wait for new page to load, after click etc. Ofc no old days Thread.sleep or implicit waits
Some people suggested to wait until a last element from new page loads, some suggested to use JS executor (document.readyState solution) which will sometimes not work (in my case, it was always giving complete response)
Found another solution, to check when a reference to element on current page will throw StaleElementReferenceException. But... in this case the page didn't manage to load after this exception.
What i did? combined both solutions together and this always does a trick for me... One make sure that document isn't in a ready state (cause throws staleElementReferenceException) and another immediately after that checks till the page fully loads and gives readyState == complete
while(true) {
try {
//it's just an interaction (can be any) with element on current page
anyElementFromCurrentPage.getText();
} catch (StaleElementReferenceException e) {
break;
}
waitForLoad(driver);
return this;
}
void waitForLoad(WebDriver driver) {
new WebDriverWait(driver, 30).until((ExpectedCondition<Boolean>) wd ->
((JavascriptExecutor) wd).executeScript("return
document.readyState").equals("complete"));
}
hope some people will use this bulletproof solution :-)

So I work in C# but Java is similar. This is currently what I use even though its marked as "obsolete".
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(15));
wait.Until(ExpectedConditions.VisibilityOfAllElementsLocatedBy(By.Name("elementNameHere")));

Related

Visibility of element- selenium webdriver

My script creates a new article: fills few fields and click "Submit button" at end of page.
I have written Click() function in util class like :
public void click(String xpathKey)
{
WebElement myDynamicElement = (new WebDriverWait(driver, 60))
.until(ExpectedConditions.visibilityOfElementLocated(
By.cssSelector(prop.getProperty(xpathKey))));
try
{
myDynamicElement.click();
}
catch (Exception e)
{
e.printStackTrace();
throw e;
}
}
Waiting for visibility of element means it will wait until element will be visible on the page or on screen? My script clicks on submit button while it's not exactly visible on the page.
I am running this script since months and it's running perfectly fine. Suddenly it started giving error element is not clickable at point(213, 415). It never appeared before. Anyone has an idea, why it could have happened?
I have done many cases, where the element is not exactly visible, generally button at end of page. selenium does not scroll itself, it finds the element and performs operation.
Try this.
public void click(String xpathKey)
{
WebElement myDynamicElement = (new WebDriverWait(driver, 60))
.until(ExpectedConditions.visibilityOfElementLocated(
By.cssSelector(prop.getProperty(xpathKey))));
try
{
Actions act = new Actions(driver);
act.moveToElement(myDynamicElement);
act.click();
act.build().perform();
}
catch (Exception e)
{
e.printStackTrace();
throw e;
}
}
The error message you are getting indicates that there is an element covering the element you are trying to click. If you read the error message carefully, it will tell you the HTML of the blocking element and that will help you find it on the page. Without more info, it's hard to tell exactly what the situation is but there are a few common causes.
You may have just closed a dialog/popup and it's not quite completely gone before you try to click. In this case, wait for some element that's part of the dialog to be invisible generally solves this problem.
There may be some wait/loading/spinner control that appears and disappears but you are clicking before it's completely gone. The solution is the same as #1, wait for some element that's part of the spinner to be invisible.
There may be some UI element like a header, footer, sidebar that is floating that covers the element you are trying to click if it's at the very bottom/top/etc of the page. These can be a real pain because you never know when the elements are going to align and be covered. One solution is to use JS to scroll the page a little more. For example, if you script is at the top of the page and you want to click something at the bottom. Doing a click will scroll the page to show that element but that puts the element at the very bottom of the page and under a floating footer. You try to click but catch the exception. Since you know you're at the bottom of the page, you scroll the page downwards by X pixels. This brings your desired element out from behind the floating footer and now you can click it.
NOTE: If you are going to click an element right after waiting for it, you should use .elementToBeClickable(locator) instead of .visibilityOfElementLocated(). It won't solve your current problem but it's a more complete and proper wait for what you are wanting to do.

The element is obscured(Server did not provide stack information) automation in edge browser with selenium

org.openqa.selenium.WebDriverException: Element is obscured (WARNING: The server did not provide any stacktrace information).
This code is working fine for chrome and firefox but not with edge browser.
`public class Login {
public WebDriver driver;
By userName = By.id("ctl14_UserName");
By password = By.id("ctl14_Password");
By login = By.id("ctl14_LoginButton");
public Login(WebDriver driver) {
this.driver = driver;
}
// Set password in username textbox
public void setUserName(String strUserName) {
driver.findElement(userName).sendKeys(strUserName);
}
// Set password in password textbox
public void setPassword(String strPassword) {
driver.findElement(password).sendKeys(strPassword);
}
public void clickMyaccount(){
driver.findElement(myAccount).click();
}
// Click on login button
public void clickLogin() {
driver.findElement(login).click();
}
}
//Test class
public class AdminLogin extends BaseForDifferentLogins {
Login objLoginAdmin;
#Test(priority=0)
public void login() throws InterruptedException{
objLoginAdmin=new Login(driver);
objLoginAdmin.clickMyaccount();
Thread.sleep(3000);
objLoginAdmin.setUserName("superuser1");
objLoginAdmin.setPassword("superuser1");
Thread.sleep(3000);
objLoginAdmin.clickLogin();
Thread.sleep(3000);
}
}`
Instead of using webElement.click() you can try to build Actions with click and do perform. Had the same issue on Edge and that did the trick for me:
Actions actions = new Actions(webDriver);
actions.click(webElement).perform();
I have encountered the issue and tried several things to solve it:
enabled EdgePageLoadStrategy.Normal - did not help;
disabled the "save your password?" bubble. - did not help;
normalized the zoom level to 100% - bingo / eureka. This solved the issue.
My test script is a bit more performance-oriented, so I had no desire to add additional objects / capabilties / options. If you want your test to be more deployable add registry editing capabilities to your selenium script. This can be a starter: http://www.winhelponline.com/blog/microsoft-edge-disable-zoom-reset-zoom-level-every-start/
I encountered the same issue on the Edge browser.
It was difficult to figure out what was actually wrong, since the issue seemed to appear/disappear from time to time in my case.
So at some point I decided to contact MS and created this ticket question
Here Steven K mentioned that the obscured element error is most likely due to zoom level not being at 100% So I checked and indeed it was at 125% for some reason.
After I set it back to 100% the issue was resolved for me.
browser.send_keys [:control, '0']
I know this is a ruby+watir example, but I'm sure there is a similar Java trick for this.
I have also encountered this problem while testing Angular with Protractor in Microsoft Edge.
What finally helped me was combining two workarounds:
Set browser zoom value to 100% explicitly in beforeEach function:
browser.actions().keyDown(protractor.Key.CONTROL).sendKeys('0')
.keyUp(protractor.Key.CONTROL).perform();
Do click through browser actions:
browser.actions().mouseMove(yourElementThatIsNotActuallyObscured).click().perform();
Resetting Zoom level to 100% will fix the issue.
public void clickUntillNotObsecured(WebElement elementToClick) {
boolean obsecuredThrown = true;
int c=0;
while (obsecuredThrown && c<30) {
try {
clickOnElement(elementToClick);
obsecuredThrown = false;
} catch (WebDriverException e) {
obsecuredThrown = true;
}
c++;
}
}
You can perform the task with the Action chains in the python specially with Edge browser:
from selenium.webdriver import ActionChains
actionChains = ActionChains(driver)
button_xpath = '//xapth...'
button = driver.find_element_by_xpath(button_xpath)
actionChains.move_to_element(button).click().perform()
But sometimes Action chain does not finds the DOM element. Hence better option to use execute_script in following way which is compatible with all browsers:
button_xpath = '//xapth...'
button = driver.find_element_by_xpath(button_xpath)
driver.execute_script("arguments[0].click();", button)
Even I faced same problem today running tests on Edge, But when I observed the problem, after which step it's failing just check it up, after that step give a time delay of 5 to 10 seconds, by doing this it solved my problem. And i got the same error many times while running in Edge at different part of my program, i just added time delay at all those steps, it solved my problem and now test successfully running on EDGE.
I added delay by using
Thread.sleep(5000);
just try this, if it doesn't work for you, I found one other solution if it's failing at the time of clicking, that is perform click operation using javascript.
WebElement element = driver.findElement(By.id("gbqfd"));
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", element);
This solution I got from
https://softwaretestingboard.com/qna/363/word-around-for-edge-driver-click
https://softwaretestingboard.com/qna/745/excpetion-selenium-webdriverexception-element-obscured
First one worked for me.

How to make Selenium WebDriver wait for page to load when new page is loaded via JS event

I'm working on automating a site which has a number of links which load new pages via a JS event. Basically, there are elements which are clickable, clicking on one causes some JavaScript to run and this leads to a form being submitted and routing to a new page.
Now if these were just standard HTML links there would be no problem as Selenium is smart enough to tell that there's a new page coming and to wait to do things. But as good as it is, Selenium can't tell that the clicks in this instance are leading to new pages to load so it doesn't wait and just keeps going. As such it doesn't wait for the new page, tries to find elements which aren't there and my tests all fail. Bummer.
As a temporary solution I'm just pausing the program for three seconds like so:
oldPageDriver.clickThatButton();
try {
Thread.sleep(3000);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
newPageDriver = new NewPageDriver(driver);
newPageDriver.doStuffOnNewPage();
And this works, sort of. I don't like it because it's "hacky," and just interrupting the program instead of doing something smarter. Because the delay is hard coded at three seconds I get failures if the link is working but just slow. I've considered something like an implicit wait but that accomplishes the same thing and I've not found a solid, workable answer in Java anywhere after a considerable amount of looking.
So, can anyone suggest a way around this? Specifically, how to make Selenium know that a new page is expected and to wait until it's available?
The wait for the document.ready event is not the entire fix to this problem, because this code is still in a race condition: Sometimes this code is fired before the click event is processed so this directly returns, since the browser hasn't started loading the new page yet.
After some searching I found a post on Obay the testing goat, which has a solution for this problem. The c# code for that solution is something like this:
IWebElement page = null;
...
public void WaitForPageLoad()
{
if (page != null)
{
var waitForCurrentPageToStale = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
waitForCurrentPageToStale.Until(ExpectedConditions.StalenessOf(page));
}
var waitForDocumentReady = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
waitForDocumentReady.Until((wdriver) => (driver as IJavaScriptExecutor).ExecuteScript("return document.readyState").Equals("complete"));
page = driver.FindElement(By.TagName("html"));
}
`
I fire this method directly after the driver.navigate.gotourl, so that it gets a reference of the page as soon as possible. Have fun with it!
Explicit waits are what you need;
http://docs.seleniumhq.org/docs/04_webdriver_advanced.jsp
You can directly add this to your test or you may want to DRY it up, especially if there is a common wait expectation such as the disappearance of a spinning icon.
You could extend the click method to always wait after clicking or if following page objects, add a wait_until_loaded method to a base page class. There many other valid approaches but dependent on how the AUT is implemented
Simple ready2use snippet, working perfectly for me
static void waitForPageLoad(WebDriver wdriver) {
WebDriverWait wait = new WebDriverWait(wdriver, 60);
Predicate<WebDriver> pageLoaded = new Predicate<WebDriver>() {
#Override
public boolean apply(WebDriver input) {
return ((JavascriptExecutor) input).executeScript("return document.readyState").equals("complete");
}
};
wait.until(pageLoaded);
}

'sendKeys' are not working in Selenium WebDriver

I am not able to put any value in my application using WebDriver. My application is using frames.
I am able to clear the value of my textbox with driver.findElement(By.name("name")).clear();, but I'm unable to put any value using driver.findElement(By.name("name")).sendKeys("manish");. The click command works for another button on the same page.
I also had that problem, but then I made it work by:
myInputElm.click();
myInputElm.clear();
myInputElm.sendKeys('myString');
Before sendkeys(), use the click() method (i.e., in your case: clear(), click(), and sendKeys()):
driver.findElement(By.name("name")).clear();
driver.findElement(By.name("name")).click(); // Keep this click statement even if you are using click before clear.
driver.findElement(By.name("name")).sendKeys("manish");
Try clicking on the textbox before you send keys.
It may be that you need to trigger an event on the field before input and hopefully the click will do it.
I experienced the same issue and was able to collect the following solution for this:
Make sure element is in focus → try to click it first and enter a string.
If there is some animation for this input box, apply some wait, not static. you may wait for an element which comes after the animation. (My case)
You can try it out using Actions class.
Clicking the element works for me too, however, another solution I found was to enter the value using JavaScript, which doesn't require the element to have focus:
var _element= driver.FindElement(By.Id("e123"));
IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
js.ExecuteScript("arguments[0].setAttribute('value', 'textBoxValue')", _element);
Use JavaScript to click in the field and then use sendkeys() to enter values.
I had a similar problem in the past with frames. JavaScript is the best way.
First pass the driver control to the frame using:
driver.switchTo().frame("pass id/name/index/webelement");
After that, perform the operation which you want to do on the webelement present inside the frame:
driver.findElement(By.name("name")).sendKeys("manish");
I have gone with the same problem where copy-paste is also not working for that text box.
The below code is working fine for me:
WebDriver driver = new FirefoxDriver();
String mobNo = "99xxxxxxxx";
WebElement mobileElementIrs =
driver.findElement(By.id("mobileNoPrimary"));
mobileElementIrs.click();
mobileElementIrs.clear();
mobileElementIrs.sendKeys(mobNo);
I had a similar problem too, when I used
getDriver().findElement(By.id(idValue)).clear();
getDriver().findElement(By.id(idValue)).sendKeys(text);
The value in "text" was not completely written into the input. Imagine that "Patrick" sometimes write "P" another "Pat",...so the test failed
The fix is a workaround and uses JavaScript:
((JavascriptExecutor)getDriver()).executeScript("$('#" + idValue + "').val('" + value + "');");
Now it is fine.
Instead of
driver.findElement(By.id("idValue")).sendKeys("text");
use,
((JavascriptExecutor)getDriver()).executeScript("$('#" + "idValue" + "').val('" + "text" + "');");
This worked for me.
I had a similar problem recently and tried some of the suggestions above, but nothing worked. In the end it fell back on a brute-force retry which retries if the input box wasn't set to what was expected.
I wanted to avoid thread.sleep for obvious reasons and saw different examples of it failing that looked like some kind of race or timing condition.
public void TypeText(string id, string text)
{
const int numberOfRetries = 5;
for (var i = 1; i < numberOfRetries; i++)
{
try
{
if (TryTypeText())
return;
}
catch (Exception)
{
if (i == numberOfRetries)
throw;
}
}
bool TryTypeText()
{
var element = _webDriver.FindElement(By.Id(id));
element.Click();
element.Clear();
element.SendKeys(text);
if (element.TagName.ToLower() == "input"
&& !DoesElementContainValue(element, text, TimeSpan.FromMilliseconds(1000)))
{
throw new ApplicationException($"Unable to set the type the text '{text}' into element with id {id}. Value is now '{element.GetAttribute("value")}'");
}
return true;
}
}
private bool DoesElementContainValue(IWebElement webElement, string expected, TimeSpan timeout)
{
var wait = new WebDriverWait(_webDriver, timeout);
return wait.Until(driver =>
{
try
{
var attribute = webElement.GetAttribute("value");
return attribute != null && attribute.Contains(expected);
}
catch (StaleElementReferenceException)
{
return false;
}
});
}
In my case, I had some actions.keyDowns(Keys.CONTOL).XXXX;
But I forgot to add the keyUp for that button and that prevented from sending keys and resulted in weird behaviors
Adding X.keyUp() after the x.keyDown() fixed the issue
Try using JavaScript to sendkeys().
WebElement element = driver.findElement(By.name("name"));
JavascriptExecutor executor = (JavascriptExecutor)driver;
executor.executeScript("arguments[0].click();", element);
More information on JavaScript Executor can be found at
JavascriptExecutor - Selenium.
Generally I keep a temporary variable. This should work.
var name = element(by.id('name'));
name.clear();
name.sendKeys('anything');

Chrome WebDriver hungs when currently selected frame closed

I am working on creation of automated test for some Web Application. This application is very complex. In fact it is text editor for specific content. As a part of functionality it has some pop-up frames. You may open this pop-up? make some changes and save them - closing current frame. May problem is in that fact, that close button situated inside frame will be eliminating. And this force Chrome WebDriver to hung. My first try was like this:
driver.findElement(By.xpath("//input[#id='insert']")).click();
driver.switchTo().defaultContent();
But it hungs on first line after executinh click command as this command close frame.
Then I change to this(I have JQuery on the page):
driver.executeScript("$(\"input#insert\").click()");
driver.switchTo().defaultContent();
But this leads to same result.
Then I use this solution:
driver.executeScript("setTimeout(function(){$(\"input#insert\").click()}, 10)");
driver.switchTo().defaultContent();
And it hungs on second line. Only this solution works:
driver.executeScript("setTimeout(function(){$(\"input#insert\").click()}, 100)");
driver.switchTo().defaultContent();
but only if you don't take into account, that it is unstable - some timing issue may occur.
So may question is there more cleaner and more stable way for switch out from closed frame?
P.S.: executeScript - self defined function to decrease amount of code. It simply executer some js on page.
Update:
I realized I was wrong. This problem is not for all iframes. It's occur when tinyMCE popup used. Situation is exactly like in this topic. So it's doubtful I will find answer here, but who knows. Solution described above will help, but only for very short amount of time, meaning that after several seconds pass chromedriver will hangs on next command.
This is how i would do it in Ruby, hopefully you can change it for java
$driver.find_element(:xpath, "//input[#id='insert']").click
$wait.until {$driver.window_handles.size < 2} #this will "explicitly wait" for the window to close
handles = $driver.window_handles #get available window handles
$driver.switch_to.window(handles[0]) #navigate to default in this case the First window handle
hope this helps
Problem was in this line of tinyMCEPopup code:
DOM.setAttrib(id + '_ifr', 'src', 'javascript:""'); // Prevent leak
Executing this script on page fix hang problem(but possibly creates leaks :) ):
(function() {
var domVar;
if (window.tinymce && window.tinymce.DOM) {
domVar = window.tinymce.DOM
}
else if (window.tinyMCE && window.tinyMCE.DOM) {
domVar = window.tinyMCE.DOM
}
else {
return;
}
var tempVar = domVar.setAttrib;console.log(123)
domVar.setAttrib = function(id, attr, val) {
if (attr == 'src' && typeof(val)== 'string' &&(val + "").trim().match(/javascript\s*:\s*("\s*"|'\s*')/)) {
console.log("Cool");
return;
}
else {
tempVar.apply(this, arguments);
}
}
}());
Bug and solution also described here
Note. Code above should be added to parent frame, not into popup frame.