Chrome WebDriver hungs when currently selected frame closed - selenium

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.

Related

Selenium Java (proper wait for new page to load)

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")));

see if the div is present or not in geb

We are using Geb for automation. I have spinner loaded before every page gets loaded. we are using waitFor() , but it takes a long time and the scripts are getting run more than the specified time.The DOM element is
<div classname="loader"></div>
i tried to see if the element is present.
if(!$(".loader").displayed== true)
{}
But i am getting error as ,
geb.waiting.WaitTimeoutException: condition did not pass in 40.0 seconds (failed with exception)
at geb.waiting.Wait.waitFor(Wait.groovy:138)
at geb.waiting.DefaultWaitingSupport.doWaitFor(DefaultWaitingSupport.groovy:51)
at geb.waiting.DefaultWaitingSupport.waitFor(DefaultWaitingSupport.groovy:46)
at geb.Page.waitFor(Page.groovy:516)
at geb.Browser.methodMissing(Browser.groovy:206)
at geb.spock.GebSpec.methodMissing(GebSpec.groovy:56)
at loaderSpec(loaderSpec.groovy:415)
Caused by: Assertion failed:
$(".loader").displayed== false
| | |
| true false
[[[ChromeDriver: chrome on XP (1b3943691dd96ebaf9098b1720c87ee9)] -> css
selector: .loader]]
at loaderSpec(loaderSpec.groovy:415)
at loaderSpec(loaderSpec.groovy:415)
at geb.waiting.Wait.waitFor(Wait.groovy:127)
... 6 more
I am not sure how to check if the div is present or not present. If I extend the time to wait for, I am getting element not found error.
Kindly let me know your input.
Are you checking that the div is visible while you are waiting for the spinner to go away?
I've had an issue exactly like this that plagued me. Here is the solution my coworkers and I came up with:
try{
waitFor(10) { element.isDisplayed() } //wait for spinner to kick in
waitFor() { !element.isDisplayed() } //wait for spinner to go away
} catch(WaitTimeoutException e) {
// if spinner loads & deloads faster than this code is reached
// then WTE will be caught and we dont need to handle the spinner any more
//println(e.printStackTrace())
}
Your boolean expression is more complicated than it needs to be, and in this case you might be noting (!) something you don't mean to be.
in general, you never need to compare booleans. (bool1==true) is the same as saying (bool1).
instead of saying
if(!$(".loader").displayed== true){}
just say:
if($(".loader").displayed){} //to check if the div is displayed
or
if(!$(".loader").displayed){} //to check if the div is not displayed
You can try with code if(!$(".loader")==undefined){}

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');

Switching to a window with no name

Using the Codeception testing framework and Selenium 2 module to test a website, I end up following a hyperlink that opens a new window with no name. As a result the switchToWindow() function will not work because it is trying to switch to the parent window (which I'm currently on). Without being able to switch to the new window I cannot perform any testing on it.
<a class="external" target="_blank" href="http://mylocalurl/the/page/im/opening">
View Live
</a>
Using both Chrome and Firefox debugging tools I can confirm the new window doesn't have a name, and I cannot give it one because I cannot edit the HTML page I am working on. Ideally I would have changed the HTML to use javascript onclick="window.open('http://mylocalurl/the/page/im/opening', 'myPopupWindow') however this is not possible in my case.
I've looked around on the Selenium forums without any clear method to tackle this problem, and Codeception doesn't appear to have much functionality around this.
After searching around on the Selenium forum and some helpful prods from #Mark Rowlands, I got it to work using raw Selenium.
// before codeception v2.1.1, just typehint on \Webdriver
$I->executeInSelenium(function (\Facebook\WebDriver\Remote\RemoteWebDriver $webdriver) {
$handles=$webdriver->window_handles();
$last_window = end($handles);
$webdriver->focusWindow($last_window);
});
Returning back to the parent window was easy because I could just use Codeception's switchToWindow method:
$I->switchToWindow();
Building on the accepted answer, in Codeception 2.2.9 I was able to add this code to the Acceptance Helper and it seems to work.
/**
* #throws \Codeception\Exception\ModuleException
*/
public function switchToNewWindow()
{
$webdriver = $this->getModule('WebDriver')->webDriver;
$handles = $webdriver->getWindowHandles();
$lastWindow = end($handles);
$webdriver->switchTo()->window($lastWindow);
}
Then in the test class I can do this:
$I->click('#somelink');
$I->switchToNewWindow();
// Some assertions...
$I->switchToWindow(); // this switches back to the previous window
I had a heck of a time trying to figure out how to do this by just searching google, so I hope it helps someone else.
Try this,
String parentWindowHandle = browser.getWindowHandle(); // save the current window handle.
WebDriver popup = null;
Iterator<String> windowIterator = browser.getWindowHandles();
while(windowIterator.hasNext()) {
String windowHandle = windowIterator.next();
popup = browser.switchTo().window(windowHandle);
}
make sure to return on parent window using,
browser.close(); // close the popup.
browser.switchTo().window(parentWindowHandle); // Switch back to parent window.
I hope will help you.
Using Codeception 2.2+ it looks like this:
$I->executeInSelenium(function (\Facebook\WebDriver\Remote\RemoteWebDriver $webdriver) {
$handles = $webdriver->getWindowHandles();
$lastWindow = end($handles);
$webdriver->switchTo()->window($lastWindow);
});