How can I handle alerts that occur on page navigation with WebDriver? - selenium

The scenario here is that certain pages I'm testing will have an unload event - i.e. prompt to save changes if there are unsaved changes is a common example and I want to be able to detect that and handle it.
Here is the specific problem:
I'm testing a pretty complicated web app which will allow users to edit rich content in a browser and the app will auto-save changes from the user. So this test does something like the following:
Navigate to the app
Do some edits
Navigate away
However, since the app auto-saves changes on navigating away and there are unsaved changes - this prompt will show up: http://i.stack.imgur.com/c9iP2.png
Whenever there is an alert in Selenium, the next action will fail miserably with a callstack like:
org.openqa.selenium.UnhandledAlertException: unexpected alert open
(Session info: chrome=39.0.2171.65)
(Driver info: chromedriver=2.11.298604 (75ea2fdb5c87f133a8e1b8da16f6091fb7d5321e),platform=Windows NT 6.1 SP1 x86_64) (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 87 milliseconds: null
Build info: version: '2.43.1', revision: '5163bceef1bc36d43f3dc0b83c88998168a363a0', time: '2014-09-10 09:43:55'
System info: host: 'ip-10-231-174-40', ip: '10.231.174.40', os.name: 'Linux', os.arch: 'amd64', os.version: '3.11.0-19-generic', java.version: '1.7.0_51'
Session ID: 889cbda1d1a946a38e90e4ec9f32e827
Driver info: org.openqa.selenium.remote.RemoteWebDriver
Capabilities [{platform=XP, acceptSslCerts=true, javascriptEnabled=true, hasMetadata=true, browserName=chrome, chrome={userDataDir=C:\Users\ADMINI~1\AppData\Local\Temp\scoped_dir1584_15883}, rotatable=false, mobileEmulationEnabled=false, locationContextEnabled=true, webdriver.remote.sessionid=889cbda1d1a946a38e90e4ec9f32e827, version=39.0.2171.65, takesHeapSnapshot=true, databaseEnabled=false, cssSelectorsEnabled=true, handlesAlerts=true, browserConnectionEnabled=false, nativeEvents=true, webStorageEnabled=true, applicationCacheEnabled=false, takesScreenshot=true}]
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:204)
at org.openqa.selenium.remote.ErrorHandler.throwIfResponseFailed(ErrorHandler.java:162)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:599)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:614)
at org.openqa.selenium.remote.RemoteWebDriver.getCurrentUrl(RemoteWebDriver.java:319)
So one solution might be that I put try/catches whenever my test navigates away from this page but I'm wondering if there is a more elegant and systematic solution (i.e. something that would either detect alerts or page navigation so they get handled).
Does anyone have a working solution for this problem?

You need to switch to alert and accept it. Example in Java:
Alert alert = driver.switchTo().alert();
alert.accept();
You may also need to wait for it to appear before switching:
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.alertIsPresent());
Alert alert = driver.switchTo().alert();
alert.accept();
Alternatively, you can stop the popup to be shown in the first place. The idea is to remove all beforeunload event listeners with javascript:
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript(
"window.addEventListener(\"load\", foo, false);" +
"function foo() { " +
"var u = \"beforeunload\";" +
"var v = unsafeWindow;" +
"if (v._eventTypes && v._eventTypes[u]) {" +
"var r=v._eventTypes[u];" +
"for(var s=0;s<r.length;s++) { " +
"v.removeEventListener(u,r[s],false);" +
"}" +
"v._eventTypes[u]=[];" +
"}");

Related

Cannot click on visible text but isDisplayed=False

I am practicing Selenium-Webdriver and encounter the issue that the desirable element(text) is visible on web page, but I cannot click on it.
Trying to do check this element is displayed or not by command line "isDisplayed", and the console returns false result. I am a little bit confused that the text(please see the highlight on attached file) on web is visible but why cannot be clickable?
On this case, how can we perform some actions on it? could you please share your ideas and strategy to do.
Thank you so much.
Here is the web page:
http://www.lazada.com.ph/
My code is
System.setProperty("webdriver.chrome.driver", driver_path);
WebDriver driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
driver.get("https://www.lazada.com.ph/");
//Click on Men's Fashion
WebElement loc = driver.findElement(By.xpath("//div[#data-qa-locator='brands-by-category-cats-item']/div[#data-tab-id='2']"));
Actions hover = new Actions(driver);
hover.moveToElement(loc).click().build().perform();
Error log:
false
Exception in thread "main" org.openqa.selenium.interactions.MoveTargetOutOfBoundsException: (-2114, -93.0999984741211) is out of bounds of viewport width (1366) and height (659)
Build info: version: '3.6.0', revision: '6fbf3ec767', time: '2017-09-27T16:15:26.402Z'
System info: host: 'Lorem', ip: '192.168.30.1', os.name: 'Windows 8.1', os.arch: 'amd64', os.version: '6.3', java.version: '1.8.0_65'
Driver info: org.openqa.selenium.firefox.FirefoxDriver
Capabilities [{moz:profile=C:\Users\Lorem\AppData\Local\Temp\rust_mozprofile.y3xzzu5rD0i5, rotatable=false, timeouts={implicit=0, pageLoad=300000, script=30000}, pageLoadStrategy=normal, moz:headless=false, platform=XP, specificationLevel=0, moz:accessibilityChecks=false, acceptInsecureCerts=true, browserVersion=56.0.2, platformVersion=6.3, moz:processID=4724, browserName=firefox, javascriptEnabled=true, platformName=XP}]
Session ID: 893e64ce-b53c-4bec-9f98-14832e4b7151
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at org.openqa.selenium.remote.http.W3CHttpResponseCodec.createException(W3CHttpResponseCodec.java:185)
at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:120)
at org.openqa.selenium.remote.http.W3CHttpResponseCodec.decode(W3CHttpResponseCodec.java:49)
at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:164)
at org.openqa.selenium.remote.service.DriverCommandExecutor.execute(DriverCommandExecutor.java:83)
at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:586)
at org.openqa.selenium.remote.RemoteWebDriver.perform(RemoteWebDriver.java:652)
at org.openqa.selenium.interactions.Actions$BuiltAction.perform(Actions.java:638)
at basic.Wait.main(Wait.java:41)
The error says it all as follows :
org.openqa.selenium.interactions.MoveTargetOutOfBoundsException: (-2114, -93.0999984741211) is out of bounds of viewport width (1366) and height (659)
Build info: version: '3.6.0', revision: '6fbf3ec767', time: '2017-09-27T16:15:26.402Z'
The WebElement which you are trying to click is Not Visible as it is out of the Viewport. As you have used Actions Class hence it shows MoveTargetOutOfBoundsException
You can consider the following code block to scroll the WebElement within the Viewport first then take help of JavascriptExecutor to click as follows :
System.setProperty("webdriver.chrome.driver", "C:\\Utility\\BrowserDrivers\\chromedriver.exe");
ChromeOptions options = new ChromeOptions();
options.addArguments("start-maximized");
options.addArguments("disable-infobars");
options.addArguments("--disable-extensions");
WebDriver driver = new ChromeDriver();
driver.get("https://www.lazada.com.ph/");
//Click on Men's Fashion
WebElement elem = driver.findElement(By.xpath("//div[#class='c-category-tab c-brands-by-category__tab']/span[#class='c-category-tab__icon c-category-tab__icon_category-fashion']"));
((JavascriptExecutor)driver).executeScript("arguments[0].scrollIntoView();", elem);
((JavascriptExecutor)driver).executeScript("arguments[0].click();", elem);
It seems that you'r xpath giving more then one element .
try below code .
WebElement loc = driver.findElement(By.xpath("(//div[#data-qa-locator='brands-by-category-cats-item']/div[#data-tab-id='2'])[2]"));
Actions hover = new Actions(driver);
hover.moveToElement(loc).click().build().perform();
The problem is that your xpath return 3 elements. If you try the following code, you could notice this:
//Click on Men's Fashion
List<WebElement> loc = driver.findElements(By.xpath("//div[#data-qa-locator='brands-by-category-cats-item']/div[#data-tab-id='2']"));
System.out.println(loc.size());
int i=1;
for(WebElement we :loc)
{
System.out.println("innerText:" + we.getAttribute("innerText"));
System.out.println("getLocation: " + we.getLocation());
System.out.println("getText: " + we.getText());
System.out.println("getSize: " + we.getSize());
if(we.getText().contains("Men's Fashion"))
{
we.click();
}
System.out.println("------------ "+i+" -------------");
i++;
}
The output is:
3
innerText:Men's Fashion
getLocation: (-2210, 838)
getText:
getSize: (141, 118)
------------ 1 -------------
innerText:Men's Fashion
getLocation: (178, 838)
getText: Men's Fashion
getSize: (141, 118)
------------ 2 -------------
innerText:Men's Fashion
getLocation: (2567, 838)
getText:
getSize: (141, 118)
------------ 3 -------------
If you click the element with getText=Men's Fashion it works.
To be honest I don't know why the xpath return 3 elements. I hope someone give the answer.
There are so many ways to reach to this element. couple more below.
//span[#data-id=4]
//span[#data-tracking-nav-header="Men's Fashion"]

Safari Browser: Switch to frame is not working

I am trying to run few test on Mobile Emulators (Safari Browser) and stuck at a problem. Where after switching to an Iframe I am not able to do any action.
There is already a closed issue for that, however I didn't find any solution after going though this thread.
https://github.com/appium/appium/issues/5832
Code which is causing issue
public PaymentPage fillCreditCardInformation(String cardNumber, String expiryDate, String cvv, String postal ){
switchToPaymentFrame();
WebElement cardNumberEditbox = driver.findElement(By.name("cardnumber"));
}
private void switchToPaymentFrame() {
WebElement frame = driver.findElement(By.name("__privateStripeFrame3"));
driver.switchTo().frame(frame);
}
Emulator Used: Iphone 6s, IPad Mini
Webdriver Version: 3.4.0
Safari Driver: 2.48
Stacktrace:
org.openqa.selenium.WebDriverException: undefined is not an object
(evaluating 'a.querySelectorAll') (WARNING: The server did not provide
any stacktrace information) Command duration or timeout: 30.48 seconds
Build info: version: '3.4.0', revision: 'unknown', time: 'unknown'
System info: host: 'DL0019', ip: '127.0.1.1', os.name: 'Linux',
os.arch: 'amd64', os.version: '4.4.0-96-generic', java.version:
'1.8.0_131' Driver info: org.openqa.selenium.remote.RemoteWebDriver
Capabilities [{noReset=true, safari=true,
browserstack.tunnelIdentifier=, browserstack.asyncStop=true,
language=Apache-HttpClient/4.5.3 (Java/1.8.0_131),
browserstack.selenium_version=3.4.0, deviceName==iPad Retina (9.1)
[556DF534-C4AE-48B6-8ED3-BAF86198074A], platform=MAC,
browserstack.video.disableWaterMark=true, desired={noReset=true,
browserstack.tunnelIdentifier=, browserstack.asyncStop=true,
language=Apache-HttpClient/4.5.3 (Java/1.8.0_131),
browserstack.selenium_version=3.4.0, deviceName==iPad Retina (9.1)
[556DF534-C4AE-48B6-8ED3-BAF86198074A], platform=MAC,
browserstack.video.disableWaterMark=true, acceptSslCerts=false,
newCommandTimeout=300.0, browser=ipad, platformVersion=9.1,
acceptSslCert=false, browserName=safari, platformName=iOS,
64bit=false, browserstack.debug=true, orientation=portrait,
browserstack.ie.noFlash=false, os_version=,
mobile={"browser":"tablet","version":"iPad Mini 4-9.1"},
browserstack.geckodriver=0.16.0, version=, browserstack.video=true,
safariIgnoreFraudWarning=true, orig_os=macelc, realMobile=false,
deviceOrientation=PORTRAIT, device=iPad Retina, proxy_type=node},
acceptSslCerts=false, newCommandTimeout=300.0, browser=ipad,
platformVersion=9.1, webStorageEnabled=false, acceptSslCert=false,
browserName=safari, takesScreenshot=true, javascriptEnabled=true,
platformName=iOS, 64bit=false, browserstack.debug=true,
networkConnectionEnabled=false, orientation=portrait,
browserstack.ie.noFlash=false, warnings={}, os_version=,
mobile={"browser":"tablet","version":"iPad Mini 4-9.1"},
browserstack.geckodriver=0.16.0, databaseEnabled=false, version=,
browserstack.video=true, safariIgnoreFraudWarning=true,
orig_os=macelc, realMobile=false, locationContextEnabled=false,
deviceOrientation=PORTRAIT, device=iPad Retina, proxy_type=node}]
Session ID: 6bf643515813d0ccbe5fe75300ac2d8ea15a5960
*** Element info: {Using=name, value=cardnumber}
Can you try this:
Change:
private void switchToPaymentFrame() {
WebElement frame = driver.findElement(By.name("__privateStripeFrame3"));
driver.switchTo().frame(frame);
}
To:
private void switchToPaymentFrame() {
WebDriverWait wait1 = new WebDriverWait(driver, 10);
wait1.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.name("__privateStripeFrame3")));
}
Seems to me like a known issue.
Simply doesn't work.
https://github.com/seleniumhq/selenium-google-code-issue-archive/issues/7658

Regarding issue org.openqa.selenium.UnhandledAlertException: Modal dialog present: A script on this page may be busy

I am currently using Java webdriver 2.53.1 for firefox version 2.46.0. I am getting this below error when run my script for a long time. Since I have different profiles to run multiple scripts at a time using same browser. this firefox browser seems getting crashed.
Please find below error details
org.openqa.selenium.UnhandledAlertException: Modal dialog present: A script on this page may be busy, or it may have stopped responding. You can stop the script now, open the script in the debugger, or let the script continue.
Script: https://website/js/jq…596b2b8fa35fe3a634ea342d7c3.js:1
Build info: version: '2.53.1', revision: 'a36b8b1cd5757287168e54b817830adce9b0158d', time: '2016-06-30 19:26:09'
System info: host: 'MACHINE NAME', ip: 'Ip address', os.name: 'Windows 10', os.arch: 'amd64', os.version: '10.0', java.version: '1.8.0_111'
Driver info: org.openqa.selenium.firefox.FirefoxDriver
Capabilities [{applicationCacheEnabled=true, rotatable=false, handlesAlerts=true, databaseEnabled=true, version=47.0.2, platform=WINDOWS, nativeEvents=false, acceptSslCerts=true, webStorageEnabled=true, locationContextEnabled=true, browserName=firefox, takesScreenshot=true, javascriptEnabled=true, cssSelectorsEnabled=true}]
Session ID: 39cfd1aa-1d74-4b18-bdcd-5255a2b90127
at sun.reflect.GeneratedConstructorAccessor51.newInstance(Unknown Source)
Also I have applied two solutions
say
1.
DesiredCapabilities capabilites = new DesiredCapabilities();
capabilites.setCapability(CapabilityType.UNEXPECTED_ALERT_BEHAVIOUR,UnexpectedAlertBehaviour.ACCEPT);
driver = new FirefoxDriver(capabilites);
as per the below link
https://www.google.com.au/url?sa=t&rct=j&q=&esrc=s&source=web&cd=6&cad=rja&uact=8&ved=0ahUKEwjf4_vy-9rUAhXEEbwKHY8_CTUQFghBMAU&url=https%3A%2F%2Fsupport.mozilla.org%2Fen-US%2Fkb%2Fwarning-unresponsive-script&usg=AFQjCNGh0FhTTjSvFduBRRe36UJCGXz8qA
But still the issues seems not fixed on mt script.
Could anyone provide a solution for this?
This error from my experience is only thrown when you are trying to do a page navigation but have not handled an on screen alert. You need to user the IAlert class to accept or dismiss this alert to continue.
First find what command is triggering the alert, then handle the alert.
If you elaborate more on your issue I may be able to help more, it would be helpful if you included the selenium code that is causing this exception.
Here are some functions I use to deal with alerts.
public void AcceptAlert()
{
try
{
WebDriverWait wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(30));
wait.Until(ExpectedConditions.AlertIsPresent());
IAlert alert = Driver.SwitchTo().Alert();
alert.Accept();
}
catch (Exception)
{ }
}
public void DismissAlert()
{
try
{
WebDriverWait wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(30));
wait.Until(ExpectedConditions.AlertIsPresent());
IAlert alert = Driver.SwitchTo().Alert();
alert.Dismiss();
}
catch (Exception ex)
{
log.Debug(ex.Message);
}
}

Android Emulator default browser can't take screenshot

My Emulator android phone has android default browser, when appium test the android default browser, it can't take screenshot on failure using TakesScreenshot.How can I to solve it.
I am using Selenium Remote Webdriver as driver instance
public synchronized static void captureScreenshot(WebDriver driver, String screenshotName) {
try {
TakesScreenshot ts = (TakesScreenshot) driver;
File source = ts.getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(source, new File("./Screenshots/"
+ screenshotName + ".png"));
System.out.println("Screenshot taken");
filePath=timestamp()+ screenshotName + ".png";
} catch (Exception e) {
System.out.println("Exception while taking screenshot "
+ e.getMessage());
}
}
CONSOLE LOGS :
Exception while taking screenshot An unknown server-side error occurred while processing the command. Original error: Could not proxy. Proxy error: New Command Timeout of 60 seconds expired. Try customizing the timeout using the 'newCommandTimeout' desired capability (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 660.36 seconds
Build info: version: '2.44.0', revision: '76d78cf323ce037c5f92db6c1bba601c2ac43ad8', time: '2014-10-23 13:11:40'
System info: host: 'DocASAP-mac-mini.local', ip: '192.168.1.45', os.name: 'Mac OS X', os.arch: 'x86_64', os.version: '10.11.5', java.version: '1.7.0_79'
Session ID: f8bcc2d5-a00d-43c5-8a8a-157d2fbe6260
Driver info: org.openqa.selenium.remote.RemoteWebDriver
Capabilities [{platform=ANDROID, javascriptEnabled=true, acceptSslCerts=true, browserName=Browser, networkConnectionEnabled=true, desired={newCommandTimeout=60, platform=ANDROID, autoAcceptAlerts=true, acceptSslCerts=true, deviceName=192.168.56.101:5555, platformName=Android, browserName=Browser, setAcceptUntrustedCertificates=true, version=5.1.0}, locationContextEnabled=false, deviceUDID=192.168.57.101:5555, version=5.1.0, newCommandTimeout=60, platformVersion=5.1, autoAcceptAlerts=true, databaseEnabled=false, deviceName=192.168.57.101:5555, platformName=Android, webStorageEnabled=false, setAcceptUntrustedCertificates=true, warnings={}, takesScreenshot=true}]

PHPUnit - Selenium 2: How to select an iframe without id and name?

I'm trying to select an iframe with PHPUnit Selenium, but somehow it seems not to work. This is the code:
<body>
...
<div id="container">
<iframe src="x.html">
<html>
...
<body></body> <!-- this is the body I would like to get -->
...
</html>
</iframe>
</div>
...
</body>
And the PHP:
<?php
class Test extends PHPUnit_Extensions_Selenium2TestCase {
public function testIframe() {
$theFrame = $this->byCssSelector('#container iframe');
$this->frame($theFrame->getId());
$this->byCssSelector('body')->text('test');
}
}
If I check the $theFrame variable, it is an PHPUnit_Extensions_Selenium2TestCase_Element with id=5, but somehow the $this->frame($theFrame->getId()) throws an error:
PHPUnit_Extensions_Selenium2TestCase_WebDriverException: Unable to locate frame: 5
Command duration or timeout: 32 milliseconds
Build info: version: '2.31.0', revision: '1bd294d', time: '2013-02-27 20:52:59'
System info: os.name: 'Linux', os.arch: 'amd64', os.version: '3.2.0-39-generic',
java.version: '1.7.0_17'
Session ID: 0192c3aa-d4a2-4c9d-bcca-bbd7139dd8c3
Driver info: org.openqa.selenium.firefox.FirefoxDriver
Capabilities [{platform=LINUX, databaseEnabled=true, cssSelectorsEnabled=true,
javascriptEnabled=true, acceptSslCerts=true, handlesAlerts=true, browserName=firefox,
browserConnectionEnabled=true, nativeEvents=false, webStorageEnabled=true,
rotatable=false, locationContextEnabled=true, applicationCacheEnabled=true,
takesScreenshot=true, version=20.0}]
Do you have any idea of why?
Give some id or name to iframe and use the below code, it will work.
$this->frame('id/name');
$this->byCssSelector('body')->text('test');
If there are multiple iframes, then assign the value null and start fetching the according to hierarchy(parent->child->so on)
$this->frame(null);
$this->frame('parentFrame');
$this->frame('childFrame');
having the same issue, and my workaround is to execute a javascript that will iterate all iframe tags, then determine the iframe you want to target by its existing attribute, and then set your own attribute as unique identifier.
$this->execute(array(
'script' => "
var myiFrames = document.getElementsByTagName('iframe');
for(var i=0; i<=myiFrames.length; i++)
{
//determine iframe by src which may contain 'test' str
if( myiFrames[i].getAttribute('src').search('test')>=0 ){
myiFrames[i].setAttribute('myCustomId', 'myTargetFrame')
}
}",
'args' => array()
));
then you can now target your iframe by xpath...
$myframe = $this->byXPath("//*[#myCustomId='myTargetFrame']");
$this->frame($frame->attribute('id'));
You can use below method to switch to a frame using it's index. To switch to a first frame present in a webpage we can use the below method.
public function switchToIFrame($index = 0) {
$this->session->getDriver()->switchToIFrame($index);
}