Unable to Handle Ajax Pop up in Selenium WebDriver - java

I'm new in Selenium. I'm trying to make Script in selenium of MacDonald's login and Order.But After login I'm unable to click Continue and any other option please help me.
my code is:--
WebDriver selenium= new FirefoxDriver();
selenium.manage().window().maximize();
String baseurl = "http://www.mcdelivery.co.in/";
selenium.get(baseurl);
Thread.sleep(2000);
Thread.sleep(5000);
WebElement loginbtn = selenium.findElement(By.id("lnkBtnLogin"));
if(loginbtn.isDisplayed()) {
loginbtn.click();
}
WebElement username = selenium.findElement(By.id("txtMobileNumber"));
if(username.isDisplayed()) {
username.clear();
username.sendKeys("******");
}
WebElement pwd = selenium.findElement(By.id("txtMsgPwd"));
if(pwd.isDisplayed()) {
pwd.sendKeys("******");
}
WebElement submit = selenium.findElement(By.id("btnSubmit"));
if(submit.isDisplayed()) {
submit.click();
//Alert aler = selenium.switchTo().alert().accept();
selenium.switchTo().activeElement();
}
WebElement conti = selenium.findElement(By.id("btnContinue"));
if(conti.isDisplayed()) {
conti.click();
}
// selenium.close();
After running this I'm Getting Error
Exception in thread "main" org.openqa.selenium.NoSuchElementException: Unable to locate element:
{"method":"id","selector":"btnContinue"}
Command duration or timeout: 31 milliseconds

Since the Continue button is the part of the pop-up (which takes time to load), you need to give some time to webdriver to detect it. For that purpose, give a timeout using Implicit/Explicit waits.
For above, you can use an Implicit timeout at the top like this;
selenium.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
The above gives a 15 seconds time to the webdriver, each time it tries to locate an element.
Also, in this code,
if(conti.isDisplayed())
{
conti.click();
}
for some odd reasons, the Continue button wasn't getting clicked when inside the if ( conti.isDisplayed() ). So, lose that loop. Just use conti.click();. It worked when tried!

Hi use some kind of explicit wait after switching to the popup like
boolean ajaxPopup = new WebDriverWait(driver,10).until(ExpectedConditions
.visibilityOfElementLocated(By.id("btnContinue"))) != null;
Assert.assertTrue(ajaxPopup);

Related

Dynamic waiting for element to become clickable not working

I have written a function as following
public static WebElement waitForElementToBeClickable(WebDriver driver, WebElement webElement, int seconds) {
WebDriverWait wait = new WebDriverWait(driver, seconds);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(webElement));
element.click();
return element;
}
Now i am importing this function and using it as following
private String loginButton = "btnActive";
private String home = "//a[#id='pt1:_UIShome']";
WebElement login = driver.findElement(By.id(loginButton));
libraryUtils.waitForElements.waitForElementToBeClickable(driver, login, 20).click();
WebElement homeButton = driver.findElement(By.xpath(home));
libraryUtils.waitForElements.waitForElementToBeClickable(driver, homeButton, 20).click();
The login button is clicked but then after going to the next page i get the following error -
org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document
The Xpath is right, I have checked that. And when I use element.click(), that also works but then that would require me to manually enter the sleep time, which is what I'm doing. I would like this to be dynamic. Appreciate any help or suggestions.
Sometimes JS had not been finished running, and if you try to interact with the web element or web elements you would see staleElemenent exception.
However the below solution may work for you :
new WebDriverWait(driver, 10).ignoring(StaleElementReferenceException.class).until(ExpectedConditions.elementToBeClickable(By.xpath("//a[#id='pt1:_UIShome']")));
driver.findElement(By.xpath("//a[#id='pt1:_UIShome']")).click();
Possibly it will be not a nice, but I see no stable solution other that adding some sleep there.
So, please try this:
private String loginButton = "btnActive";
private String home = "//a[#id='pt1:_UIShome']";
WebElement login = driver.findElement(By.id(loginButton));
libraryUtils.waitForElements.waitForElementToBeClickable(driver, login, 20).click();
driver.findElement(By.xpath(home));
libraryUtils.waitForElements.waitForElementToBeClickable(driver, homeButton, 20);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
driver.findElement(By.xpath(home)).click();
Problem here is that you are already doing element.click() in the waitForElementToBeClickable function and calling click again while calling this function.
libraryUtils.waitForElements.waitForElementToBeClickable(driver, login, 20).click();
Since you have already clicked while waiting for the element to be clickable, you shouldn't be clicking it again. I hope you got the answer for StaleElementException

Selenium in Java Error: Missing or invalid type argument for pointer action

I am getting this error "Missing or invalid type argument for pointer action" while trying to execute the below code for Selenium in Java.
public static void main(String args[]) throws InterruptedException
{
WebDriver driver = new FirefoxDriver();
driver.get("https://www.flipkart.com/");
driver.findElement(By.xpath(".//*[#class='_3Ji-EC']/li[8]/a")).click();
WebElement elem = driver.findElement(By.className("_2zrpKA"));
elem.sendKeys("ABC");
WebElement elem2 = driver.findElement(By.xpath(".//*[#class='_2zrpKA
_3v41xv']"));
elem2.sendKeys("XYZ");
driver.findElement(By.xpath(".//*[#class='_2AkmmA _1LctnI
_7UHT_c']")).click();
System.out.println("Success");
//driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
Thread.sleep(5000);
WebElement elem3 = driver.findElement(By.xpath(".//*[#class='_3Ji-
EC']/li[7]/a"));
System.out.println("success");
Actions action = new Actions(driver);
action.moveToElement(elem3).build().perform();
driver.findElement(By.xpath(".//*[#class='_1u5ANM']/li[9]/a")).click();
}
I have tried this using Selenium 3.4.0 and Firefox 51.x, 52.x, 53.x with the latest geckodriver 16.1 and 16.0 .
When I used Firefox 53.x, I was getting the error "Expected [object Undefined] undefined to be a string" else every time I am getting the error "Missing or invalid type argument for pointer action".
In the above code I am able to get "success" printed 2nd time without any problem but after that I am getting the error.
Here is the solution to your Question:
To work with Selenium 3.4.0 with geckodriver v0.16.1 & Mozilla Firefox 53.x you need to specify the absolute path of the geckodriver in your code as:
System.setProperty("webdriver.gecko.driver", "C:\\your_directory\\geckodriver.exe");
Your xpath seems petty vulnerable to me. You may want to construct more unique logical xpath. To click on Log In button you may do:
driver.findElement(By.xpath("//div[#class='AsXM8z']/ul/li/a[#class='_2k0gmP'][text()='Log In']")).click();
I would suggest you not to rely only on class, append some more properties. The xpath for Enter Email field can be:
WebElement elem = driver.findElement(By.xpath("//input[#class='_2zrpKA']"));
The xpath for Enter Password is not unique, you may like to change it to:
WebElement elem2 = driver.findElement(By.xpath("//input[#class='_2zrpKA _3v41xv']"));
The xpath for the Login button needs to be unique as follows:
driver.findElement(By.xpath("//button[#class='_2AkmmA _1LctnI _7UHT_c']")).click();
Avoid using Thread.sleep(5000); rather use ImplicitlyWait or ExplicitWait
The xpath to click on the Username is again vulnerable, you may like to change it to:
WebElement elem3 = driver.findElement(By.xpath("//div[#class='AsXM8z']/ul/li/a[#class='_1AHrFc _2k0gmP']"));
The xpath to click the Log Out button is again vulnerable, you may like to change it to:
driver.findElement(By.xpath("//div[#class='_1H5F__']/div/ul/li/ul/li/a[#class='_2k0gmP'][text()='Log Out']")).click();
Here is your own working code block with some simple tweaks;
System.setProperty("webdriver.gecko.driver", "C:\\your_directory\\geckodriver.exe");
WebDriver driver = new FirefoxDriver();
driver.get("https://www.flipkart.com/");
driver.findElement(By.xpath("//div[#class='AsXM8z']/ul/li/a[#class='_2k0gmP'][text()='Log In']")).click();
//Email
WebElement elem = driver.findElement(By.xpath("//input[#class='_2zrpKA']"));
elem.sendKeys("emailid#domain.com");
//Password
WebElement elem2 = driver.findElement(By.xpath("//input[#class='_2zrpKA _3v41xv']"));
elem2.sendKeys("pass_word");
//Login Button
driver.findElement(By.xpath("//button[#class='_2AkmmA _1LctnI _7UHT_c']")).click();
System.out.println("Success");
//driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
Thread.sleep(5000);
//Click on Name
WebElement elem3 = driver.findElement(By.xpath("//div[#class='AsXM8z']/ul/li/a[#class='_1AHrFc _2k0gmP']"));
System.out.println("success");
Actions action = new Actions(driver);
action.moveToElement(elem3).build().perform();
driver.findElement(By.xpath("//div[#class='_1H5F__']/div/ul/li/ul/li/a[#class='_2k0gmP'][text()='Log Out']")).click();
Let me know if this Answers your Question.

How to return WebElement having particular CSS property using JavascriptExecutor?

I am working on a scenario where I need to find a WebElement based on its CSS property, like background-color.
I have created the JQuery to find the element as below and it finds the webelement correctly using firefox console.
$('.search-bar-submit').each(function() {
return $(this).css('background-color') == '#fdd922';
});
Hence, I wrote the code to find this WebElement, i.e. searchbox and then tried to click it.
driver.get("http://www.flipkart.com/");
driver.findElement(By.id("fk-top-search-box")).sendKeys("iphone");
String query ="$('.search-bar-submit').each(function() { "
+ "return $(this).css('background-color') == '#fdd922'; });";
WebElement searchbox = (WebElement) ((JavascriptExecutor)driver).executeScript(query);
searchbox.click();
When I run the program, it gives me Exception in thread "main" java.lang.NullPointerException on line searchbox.click();
Can anyone help me out find the searchbox using JavascriptExecutor and then click on it? Am I missing something silly here?
Any help is appreciated. Thanks in Advance.
WebElement searchbox = (WebElement)
((JavascriptExecutor)driver).executeScript(query);
The above code calls the function but doesn't do anything with the result, ie. it doesn't return it to the caller.
Add return in the script to return the webelement to the selenium script(webdriver)
return $('.search-bar-submit').each(function() {
return $(this).css('background-color') == '#fdd922';
});
The return type is List<WebElement>so typecast it to List if you typecast it to it will throw an ClassCastException as arraylist cannot be cast to a webelement
Code:
List<WebElement> searchbox = (List<WebElement>) ((JavascriptExecutor)driver).executeScript(query);
for(int i=0;i<searchbox.size();i++){
searchbox.get(i).click();
}
EDIT:
The code was not working in firefox because the firefox browser returns a json object of the webelement.Selenium replaced its uses of org.json with gson.So it is not able to understand the response recieved
Screenshot taken from chrome
Screenshot taken from firefox
Solution
We are using Jquery get function to retrieve the DOM Elements matched by the jquery object
$('.search-bar-submit').each(function() {
return $(this).css('background-color') == '#fdd922';
}).get(0);
Code
public class jquerytest
{
public static void main(String[] args) throws Exception {
WebDriver driver = new FirefoxDriver();
driver.get("https://www.flipkart.com");
driver.findElement(By.id("fk-top-search-box")).sendKeys("iphone");
String query ="return $('.search-bar-submit').each(function() { "
+ "return $(this).css('background-color') == '#fdd922'; }).get(0);";
Thread.sleep(5000);//wait till page loads replace thread.sleep by any waits
WebElement searchbox = (WebElement) ((JavascriptExecutor)driver).executeScript(query);
searchbox.click();
}
}
I have tested the above code on both chrome and firefox it works perfectly
Hope this helps you.Kindly get back if you have any queries
I ran the following code and it all works fine. Your jquery works as well (I love the little message they print to console in the dev view hahaha).
driver.get("http://www.flipkart.com/");
WebElement in = driver.findElement(By.id("fk-top-search-box"));
in.sendKeys("iphone");
WebElement thing = driver.findElement(By.className("fk-font-bold"));
thing.click();
I believe there's a problem with your executeScript and it should be as follows.
System.out.println(((JavascriptExecutor)driver).executeScript(query, driver));
Normally the format for my calling javascript is as follows, this would be to remove the windowed attribute so that a hyperlink would open in the same tab:
String Href = linkObject.getAttribute("href");//located the hyperlink for the documents
Href = Href.substring(0, Href.length()-10)+")";//I remove ",'windowed'" from the link to stop it opening in a new window and having to change the scripts focus
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("return arguments[0].href = \""+Href + "\"", linkObject););
But then you're getting JSON back and WebDriver can't understand that. See the following link for more information on that.
http://grokbase.com/t/gg/webdriver/12ckjcthg8/executing-javascript-that-returns-json-how-best-to-handle
Might I suggest this alternative, it gives the background-color in rgba format:
WebElement pain = driver.findElement(By.className("search-bar-submit");
pain.getCssValue("background-color");

Element not found in cache - perhaps the page has changed since it has looked up

I'm testing a web app, in which after opening a page I need to select a radio button after that a pop-up will appear. In that pop-up I'm selecting an ID. Once selected, it will come to main window, in which I'm trying to select a text field with ID. But I receive the following error:
Element not found in the cache - perhaps the page has changed since it was looked up
Command duration or timeout: 50.14 seconds
driver.findElement(By.xpath("html/body/section/div/div[2]/div[3]/div/div/div/div/ul/li[1]/a")).click();
driver.findElement(By.xpath("html/body/section/div/div[12]/div[1]/div/div[2]/div[3]/div/div/div/div/button[1]")).click();
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
String mainWindowHandle=driver.getWindowHandle();
driver.findElement(By.xpath("html/body/div[3]/div/div")).click();
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
Set s = driver.getWindowHandles();
Iterator ite = s.iterator();
while(ite.hasNext())
{
String popupHandle=ite.next().toString();
if(!popupHandle.contains(mainWindowHandle))
{
driver.switchTo().window(popupHandle);
}
}
driver.findElement(By.xpath("html/body/div[3]/div/div/div[3]/div/div/div[1]/div[2]/div[4]/div[2]/a")).click();
driver.manage().timeouts().implicitlyWait(50, TimeUnit.SECONDS);
driver.switchTo().window( mainWindowHandle );
driver.findElement(By.id("Title")).sendKeys("auto title");
Problem is I cannot find the textfield with ID: Title" for inserting "auto title.
Thanks in Advance.
Instead of using sleep() with hardcoded time intervals, use an explicit wait:
WebDriverWait wait = new WebDriverWait(driver, 30);
WebElement title = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("Title")));
title.sendKeys("auto title");
Finally found a solution by adding
Thread.sleep(5000);
before finding the element and it solved.

selenium get current url after loading a page

I'm using Selenium Webdriver in Java. I want to get the current url after clicking the "next" button to move from page 1 to page 2. Here's the code I have:
WebDriver driver = new FirefoxDriver();
String startURL = //a starting url;
String currentURL = null;
WebDriverWait wait = new WebDriverWait(driver, 10);
foo(driver,startURL);
/* go to next page */
if(driver.findElement(By.xpath("//*[#id='someID']")).isDisplayed()){
driver.findElement(By.xpath("//*[#id='someID']")).click();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[#id='someID']")));
currentURL = driver.getCurrentUrl();
System.out.println(currentURL);
}
I have both the implicit and explicit wait calls to wait for the page to be fully loaded before I get the current url. However, it's still printing out the url for page 1 (it's expected to be the url for page 2).
Like you said since the xpath for the next button is the same on every page it won't work. It's working as coded in that it does wait for the element to be displayed but since it's already displayed then the implicit wait doesn't apply because it doesn't need to wait at all. Why don't you use the fact that the url changes since from your code it appears to change when the next button is clicked. I do C# but I guess in Java it would be something like:
WebDriver driver = new FirefoxDriver();
String startURL = //a starting url;
String currentURL = null;
WebDriverWait wait = new WebDriverWait(driver, 10);
foo(driver,startURL);
/* go to next page */
if(driver.findElement(By.xpath("//*[#id='someID']")).isDisplayed()){
String previousURL = driver.getCurrentUrl();
driver.findElement(By.xpath("//*[#id='someID']")).click();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
ExpectedCondition e = new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver d) {
return (d.getCurrentUrl() != previousURL);
}
};
wait.until(e);
currentURL = driver.getCurrentUrl();
System.out.println(currentURL);
}
Page 2 is in a new tab/window ?
If it's this, use the code bellow :
try {
String winHandleBefore = driver.getWindowHandle();
for(String winHandle : driver.getWindowHandles()){
driver.switchTo().window(winHandle);
String act = driver.getCurrentUrl();
}
}catch(Exception e){
System.out.println("fail");
}
It's been a little while since I coded with selenium, but your code looks ok to me. One thing to note is that if the element is not found, but the timeout is passed, I think the code will continue to execute. So you can do something like this:
boolean exists = driver.findElements(By.xpath("//*[#id='someID']")).size() != 0
What does the above boolean return? And are you sure selenium actually navigates to the expected page? (That may sound like a silly question but are you actually watching the pages change... selenium can be run remotely you know...)

Categories

Resources