I was trying to automate the Make My Trip site using Selenium. These are the steps I took:
Search for MakeMyTrip in Google -> Done
Open makemytrip and change country to US -> Done
Click on feedback -> Done
Trying to fill feedback form -> Error
It's saying, unable to find the element.
I have tried the following:
1. Tried finding the element by id
2. Tried finding the element by xpath
//div[#class='feedback-form-container']//form[#id='feedbackForm']//input[#id='field_name_NAME']"
Code:
public void setUp() throws Exception {
driver = new FirefoxDriver();
baseURL = "http://www.google.com/";
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}
#Test
public void makeMyTriptest() throws Exception {
System.out.println("Entered this loop");
driver.get(baseURL + "/?gws_rd=ssl");
driver.findElement(By.id("lst-ib")).sendKeys("makemytrip");
System.out.println("send keys successful");
driver.findElement(By.linkText("Flights - MakeMyTrip")).click();
driver.findElement(By.id("country_links")).click();
driver.findElement(By.xpath("//*[#id='country_dropdown']//p//a[#href='http://us.makemytrip.com/']")).click();
driver.findElement(By.xpath("//div[#id='webklipper-publisher-widget-container-content-expand-collapse']")).click();
//entering feedback details
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
//driver.findElement(By.id("field_name_NAME")).sendKeys("SubbaRao");
driver.findElement(By.xpath("//div[#class='feedback-form-container']//form[#id='feedbackForm']//input[#id='field_name_NAME']")).sendKeys("SubbaRao");
//driver.findElement(By.id("field_email_EMAIL")).sendKeys("test#test.com");
}
The Feedback form is located inside an iframe. You have to switch into it's context:
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
//WebElement iFrame = driver.findElement(By.xpath("//*[id='print_ticket_overlayiframe']"));
driver.switchTo().defaultContent();
driver.switchTo().frame("webklipper-publisher-widget-container-frame");
//driver.findElement(By.id("field_name_NAME")).sendKeys("SubbaRao");
driver.findElement(By.xpath("//*[#id='field_name_NAME']")).sendKeys("SubbaRao");
now while you are in the iframe, search for the input
Works for me.
Related
I tried to implement a logout test method through selenium in Spring Boot but I cannot detect dropdown menu located top right hand side.
How can I fix it?
Here is the test method shown below.
#Test
#Order(4)
public void logout() throws InterruptedException {
login();
driver.get("https://github.com");
Thread.sleep(1000);
// Header-item position-relative mr-0 d-none d-md-flex
WebElement profileDropdown = driver.findElement(By.cssSelector(".Header-item.position-relative.mr-0.d-none.d-md-flex")); // cannot work
// dropdown-item dropdown-signout
WebElement signOutButton = driver.findElement(By.cssSelector(".dropdown-item.dropdown-signout")); // cannot work
profileDropdown.click();
Thread.sleep(1000);
signOutButton.click();
}
Here is the error part shown below
java.net.SocketException: Connection reset
org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":".dropdown-item.dropdown-signout"}
1st Edited
String xpathProfile = "//*[#aria-label='View profile and more']";
WebElement profileDropdown = driver.findElement(By.xpath(xpathProfile));
String xpathSignOut = "//button[contains(#class,'dropdown-signout')]";
WebElement signOutButton = driver.findElement(By.xpath(xpathSignOut));
I got this issue shown below.
org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"//button[contains(#class,'dropdown-signout')]"}
This is a bad practice to try to locate elements like this, you should be more specific. Given this DOM that you are working with I would try using a selector somewhat like this:
String xpathProfile = "//*[#aria-label='View profile and more']";
String xpathSignOut = "//button[contains(#class,'dropdown-signout')]";
As you can see it's an xpath type selector and I would recommend learning xpath as it is far more readable once you get used to it and it also works in a few edge cases where you wouldn't be able to use css selector.
Also I've noticed that if you make the window size smaller, at some point the profile button you are trying to click is hidden in github, so maybe that is why your button is not getting clicked. You could try setting a specific bigger window size using chromeOptions:
ChromeOptions options = new ChromeOptions();
options.addArgument("--window-size=1920,1080");
ChromeDriver driver = new ChromeDriver(options);
Can you actually see the button when the test is running?
Here is the answer shown below
public void logout() throws InterruptedException {
login();
driver.get("https://github.com");
Thread.sleep(1000);
// Header-item position-relative mr-0 d-none d-md-flex
WebElement profileDropdown = driver.findElement(By.cssSelector(".Header-item.position-relative.mr-0.d-none.d-md-flex"));
profileDropdown.click();
Thread.sleep(1000);
// dropdown-item dropdown-signout
WebElement signOutButton = driver.findElement(By.cssSelector(".dropdown-item.dropdown-signout"));
signOutButton.click();
Thread.sleep(2000);
}
I am trying to open a link in a new tab using selenium java automation code.
Initially i tried with actions class but it wasn't working. Later i tried using the Keys to automate the same thru keyboard actions and it worked. But i wanted to know why am i unable achieve the same with Actions class. Just wanted to if i am doing anything wrong here or is Actions class not suitable for this.
Below is the code snippet i have written.
public class InterviewQuestion {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
//System.out.println(System.getProperty("user.dir")+"\\"+"chromedriver.exe");
System.setProperty("webdriver.chrome.driver", System.getProperty("user.dir")+"\\"+"chromedriver.exe");
WebDriver driver = new ChromeDriver();
driver.get("https://www.google.co.in/");
driver.manage().window().maximize();
WebElement GoogleSearchTextBox = driver.findElement(By.xpath("//input[#title='Search']"));
GoogleSearchTextBox.sendKeys("test automation");
GoogleSearchTextBox.sendKeys(Keys.ENTER);
**boolean useActionsClass = false,useKeys = true;**
// finding the required element to be clicked
WebElement RequiredSearchResult = driver.findElement(By.xpath("//div[#class='EIaa9b']/div[1]/div[2]/a"));
if(**useActionsClass**)
{
Actions actions = new Actions(driver);
//actions.moveToElement(RequiredSearchResult).build().perform();
Thread.sleep(5000);
actions.moveToElement(RequiredSearchResult).contextClick(RequiredSearchResult).sendKeys(Keys.ARROW_DOWN).sendKeys(Keys.ARROW_DOWN).sendKeys(Keys.ENTER).build().perform();
}
if(useKeys)
{
Thread.sleep(5000);
String s = Keys.chord(Keys.CONTROL,Keys.ENTER);
RequiredSearchResult.sendKeys(s);
Set<String> windows = driver.getWindowHandles();
Iterator itr = windows.iterator();
Object FirstWindowHandle = itr.next();
Object SecondWindowHandle = itr.next();
driver.switchTo().window((String) SecondWindowHandle);
Thread.sleep(5000);
//driver.switchTo().window((String) FirstWindowHandle);
}
//driver.quit();
}
}
First, get the link with the help of href attribute from your RequiredSearchResultLink element. once you have the link, use selenium 4 driver.switchTo().newWindow(WindowType.TAB); method to open a new tab. Once the tab is open, just pass your get method, the url which you got from your link field.
If you are not using selenium 4, I will strongly suggest using it, as it will remove lots of unnecessary code from the action class.
Selenium 4 dependency:
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.0.0</version>
</dependency>
Code with Selenium 4:
driver.get("https://www.google.co.in/");
driver.manage().window().maximize();
WebElement GoogleSearchTextBox = driver.findElement(By.xpath("//input[#title='Search']"));
GoogleSearchTextBox.sendKeys("test automation");
GoogleSearchTextBox.sendKeys(Keys.ENTER);
WebElement RequiredSearchResultLink = driver.findElement(By.xpath("//div[#class='EIaa9b']/div[1]/div[2]/a"));
String href = RequiredSearchResultLink.getAttribute("href");
driver.switchTo().newWindow(WindowType.TAB);
driver.get(href);
Thread.sleep(10);
driver.quit();
}
3 things you need to
Copy the link you need to open in new tab
Open new tab
Paste your link
driver.switchTo().newWindow(WindowType.TAB);
driver.get("your new lin");
I am trying to check if web page is loaded completed or not (i.e. checking that all the control is loaded) in selenium.
I tried below code:
new WebDriverWait(firefoxDriver, pageLoadTimeout).until(
webDriver -> ((JavascriptExecutor) webDriver).executeScript("return document.readyState").equals("complete"));
but even if page is loading above code does not wait.
I know that I can check for particular element to check if its visible/clickable etc but I am looking for some generic solution
As you mentioned if there is any generic function to check if the page has completely loaded through Selenium the answer is No.
First let us have a look at your code trial which is as follows :
new WebDriverWait(firefoxDriver, pageLoadTimeout).until(webDriver -> ((JavascriptExecutor) webDriver).executeScript("return document.readyState").equals("complete"));
The parameter pageLoadTimeout in the above line of code doesn't really reseambles to actual pageLoadTimeout().
Here you can find a detailed discussion of pageLoadTimeout in Selenium not working
Now as your usecase relates to page being completely loaded you can use the pageLoadStrategy() set to normal [ the supported values being none, eager or normal ] using either through an instance of DesiredCapabilities Class or ChromeOptions Class as follows :
Using DesiredCapabilities Class :
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.remote.DesiredCapabilities;
public class myDemo
{
public static void main(String[] args) throws Exception
{
System.setProperty("webdriver.gecko.driver", "C:\\Utility\\BrowserDrivers\\geckodriver.exe");
DesiredCapabilities dcap = new DesiredCapabilities();
dcap.setCapability("pageLoadStrategy", "normal");
FirefoxOptions opt = new FirefoxOptions();
opt.merge(dcap);
WebDriver driver = new FirefoxDriver(opt);
driver.get("https://www.google.com/");
System.out.println(driver.getTitle());
driver.quit();
}
}
Using ChromeOptions Class :
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.PageLoadStrategy;
public class myDemo
{
public static void main(String[] args) throws Exception
{
System.setProperty("webdriver.gecko.driver", "C:\\Utility\\BrowserDrivers\\geckodriver.exe");
FirefoxOptions opt = new FirefoxOptions();
opt.setPageLoadStrategy(PageLoadStrategy.NORMAL);
WebDriver driver = new FirefoxDriver(opt);
driver.get("https://www.google.com/");
System.out.println(driver.getTitle());
driver.quit();
}
}
You can find a detailed discussion in Page load strategy for Chrome driver (Updated till Selenium v3.12.0)
Now setting PageLoadStrategy to NORMAL and your code trial both ensures that the Browser Client have (i.e. the Web Browser) have attained 'document.readyState' equal to "complete". Once this condition is fulfilled Selenium performs the next line of code.
You can find a detailed discussion in Selenium IE WebDriver only works while debugging
But the Browser Client attaining 'document.readyState' equal to "complete" still doesn't guarantees that all the JavaScript and Ajax Calls have completed.
To wait for the all the JavaScript and Ajax Calls to complete you can write a function as follows :
public void WaitForAjax2Complete() throws InterruptedException
{
while (true)
{
if ((Boolean) ((JavascriptExecutor)driver).executeScript("return jQuery.active == 0")){
break;
}
Thread.sleep(100);
}
}
You can find a detailed discussion in Wait for ajax request to complete - selenium webdriver
Now, the above two approaches through PageLoadStrategy and "return jQuery.active == 0" looks to be waiting for indefinite events. So for a definite wait you can induce WebDriverWait inconjunction with ExpectedConditions set to titleContains() method which will ensure that the Page Title (i.e. the Web Page) is visible and assume the all the elements are also visible as follows :
driver.get("https://www.google.com/");
new WebDriverWait(driver, 10).until(ExpectedConditions.titleContains("partial_title_of_application_under_test"));
System.out.println(driver.getTitle());
driver.quit();
Now, at times it is possible though the Page Title will match your Application Title still the desired element you want to interact haven't completed loading. So a more granular approach would be to induce WebDriverWait inconjunction with ExpectedConditions set to visibilityOfElementLocated() method which will make your program wait for the desired element to be visible as follows :
driver.get("https://www.google.com/");
WebElement ele = new WebDriverWait(driver, 10).until(ExpectedConditions.visibilityOfElementLocated(By.xpath("xpath_of_the_desired_element")));
System.out.println(ele.getText());
driver.quit();
References
You can find a couple of relevant detailed discussions in:
Selenium IE WebDriver only works while debugging
Selenium how to manage wait for page load?
I use selenium too and I had the same problem, to fix that I just wait also for the jQuery to load.
So if you have the same issue try this also
((Long) ((JavascriptExecutor) browser).executeScript("return jQuery.active") == 0);
You can wrap both function in a method and check until both page and jQuery is loaded
Implement this, Its working for many of us including me. It includes Web Page wait on JavaScript, Angular, JQuery if its there.
If your Application is containing Javascript & JQuery you can write code for only those,
By define it in single method and you can Call it anywhere:
// Wait for jQuery to load
{
ExpectedCondition<Boolean> jQueryLoad = driver -> ((Long) ((JavascriptExecutor) driver).executeScript("return jQuery.active") == 0);
boolean jqueryReady = (Boolean) js.executeScript("return jQuery.active==0");
if (!jqueryReady) {
// System.out.println("JQuery is NOT Ready!");
wait.until(jQueryLoad);
}
wait.until(jQueryLoad);
}
// Wait for ANGULAR to load
{
String angularReadyScript = "return angular.element(document).injector().get('$http').pendingRequests.length === 0";
ExpectedCondition<Boolean> angularLoad = driver -> Boolean.valueOf(((JavascriptExecutor) driver).executeScript(angularReadyScript).toString());
boolean angularReady = Boolean.valueOf(js.executeScript(angularReadyScript).toString());
if (!angularReady) {
// System.out.println("ANGULAR is NOT Ready!");
wait.until(angularLoad);
}
}
// Wait for Javascript to load
{
ExpectedCondition<Boolean> jsLoad = driver -> ((JavascriptExecutor) driver).executeScript("return document.readyState").toString()
.equals("complete");
boolean jsReady = (Boolean) js.executeScript("return document.readyState").toString().equals("complete");
// Wait Javascript until it is Ready!
if (!jsReady) {
// System.out.println("JS in NOT Ready!");
wait.until(jsLoad);
}
}
Click here for Reference Link
Let me know if you stuck anywhere by implementing.
It overcomes the use of Thread or Explicit Wait.
public static void waitForPageToLoad(long timeOutInSeconds) {
ExpectedCondition<Boolean> expectation = new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driver) {
return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
}
};
try {
System.out.println("Waiting for page to load...");
WebDriverWait wait = new WebDriverWait(Driver.getDriver(), timeOutInSeconds);
wait.until(expectation);
} catch (Throwable error) {
System.out.println(
"Timeout waiting for Page Load Request to complete after " + timeOutInSeconds + " seconds");
}
}
Try this method
This works for me well with dynamically rendered websites:
Wait for complete page to load
WebDriverWait wait = new WebDriverWait(driver, 50);
wait.until((ExpectedCondition<Boolean>) wd -> ((JavascriptExecutor) wd).executeScript("return document.readyState").equals("complete"));
Make another implicit wait with a dummy condition which would always fail
try {
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[contains(text(),'" + "This text will always fail :)" + "')]"))); // condition you are certain won't be true
}
catch (TimeoutException te) {
}
Finally, instead of getting the html source - which would in most of one page applications would give you a different result , pull the outerhtml of the first html tag
String script = "return document.getElementsByTagName(\"html\")[0].outerHTML;";
content = ((JavascriptExecutor) driver).executeScript(script).toString();
There is a easy way to do it. When you first request the state via javascript, it tells you that the page is complete, but after that it enters the state loading. The first complete state was the initial page!
So my proposal is to check for a complete state after a loading state. Check this code in PHP, easily translatable to another language.
$prevStatus = '';
$checkStatus = function ($driver) use (&$prevStatus){
$status = $driver->executeScript("return document.readyState");
if ($prevStatus=='' && $status=='loading'){
//save the previous status and continue waiting
$prevStatus = $status;
return false;
}
if ($prevStatus=='loading' && $status=='complete'){
//loading -> complete, stop waiting, it is finish!
return true;
}
//continue waiting
return false;
};
$this->driver->wait(20, 150)->until($checkStatus);
Checking for a element to be present also works well, but you need to make sure that this element is only present in the destination page.
Something like this should work (please excuse the python in a java answer):
idle = driver.execute_async_script("""
window.requestIdleCallback(() => {
arguments[0](true)
})
""")
This should block until the event loop is idle which means all assets should be loaded.
I have tried my best to write a login script in Selenium for the following site https://www.topmba.com/app. Here is my code:
public class TopMba {
String driverPath = "/usr/bin/chromedriver";
WebDriver driver;
String username = "test#gmail.com"; // Change to your username and passwrod
String password = "12345";
// This method is to navigate topmba URL
#BeforeClass
public void init() {
System.setProperty("webdriver.chrome.driver", driverPath);
driver = new ChromeDriver();
driver.navigate().to("https://www.topmba.com");
}
// To log in topmba
#Test
public void login() {
driver.findElement(By.className("tm-user")).click();
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
driver.switchTo().frame(driver.findElement(By.xpath("//*[#id=\"tm-modal-frame-nvtfa7vvbm\"]")));
driver.findElement(By.id("edit-user")).sendKeys(username);
driver.findElement(By.id("edit-pass")).sendKeys(password);
driver.findElement(By.id("edit-submit")).click();
driver.switchTo().defaultContent();}
#AfterClass
public void quit() {
driver.close();
}
Here is the Exception :
org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"//*[#id="tm-modal-frame-nvtfa7vvbm"]"}
Use the below code:
driver.get("https://www.topmba.com");
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
String parentWindowHandle = driver.getWindowHandle();
driver.findElement(By.className("tm-user")).click();
WebElement iframe = driver.findElement(By.xpath("//iframe[contains(#src,'app/sso/user/login')]"));
driver.switchTo().frame(iframe);
driver.findElement(By.id("edit-name")).sendKeys(username);
driver.findElement(By.id("edit-pass")).sendKeys(password);
driver.findElement(By.id("edit-submit")).click();
driver.switchTo().window(parentWindowHandle);
There are a couple of things you need to take care as follows :
To click on the icon with tooltip as Login you have used :
driver.findElement(By.className("tm-user")).click();
If you look at the HTML this Locator Strategy identifies the element uniquely but for a more focused click you need to target the <span> tag which is within an <a> tag which is within the <li> tag with the class attribute you have used. Of-coarse you have induce WebDriverWait.
Once the Sign In Dialog Box opens up you will observe the login fields are within an <iframe>. So you have to induce WebDriverWait for both the cases, once for the frame to be available and for the desired element to be clickable and you can use the following solution :
Code Block :
System.setProperty("webdriver.gecko.driver", "C:\\path\\to\\geckodriver.exe");
WebDriver driver = new FirefoxDriver();
driver.get("https://www.topmba.com");
new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(By.cssSelector("li.tm-user>a.tmba-user>span.fa-img-icons.fa-img-user"))).click();
new WebDriverWait(driver, 10).until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.xpath("//iframe[#src='/app/sso/user/login']")));
new WebDriverWait(driver, 10).until(ExpectedConditions.elementToBeClickable(By.cssSelector("input.input-block-level.form-text.required.form-control#edit-name"))).sendKeys("khawar");
driver.findElement(By.cssSelector("input.input-block-level.form-text.required.form-control#edit-pass")).sendKeys("khawar");
driver.findElement(By.cssSelector("button.btn.btn-warning.btn-block.button.js-form-submit.form-submit#edit-submit")).click();
Browser Snapshot :
I am facing some problem with PhantomJS reg locating the webelements. I have gone through previously answered questions in which 2 possible solutions was given:
Sync Issue-give Implicit wait
Css selector don't work in phantomjs.
I have tried both the solution but my code is still not working.
Code:
public class Headless_phantomJS {
#Test
public void googlesearch() throws InterruptedException
{
File path=new File("C:/Third party softwares/phantomJS/phantomjs-2.1.1-windows/phantomjs-2.1.1-windows/bin/phantomjs.exe");
System.setProperty("phantomjs.binary.path",path.getAbsolutePath());
WebDriver driver= new PhantomJSDriver();
driver.manage().window().maximize();
driver.navigate().to("https://www.google.co.in/");
System.out.println("inside Test");
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
driver.findElement(By.xpath("//input[#id='lst-ib']")).isEnabled();
driver.findElement(By.xpath("//input[#id='lst-ib']")).sendKeys("lol");
driver.findElement(By.xpath(".//*[#id='tsf']/div[2]/div[3]/center/input[1]")).click();
}
}
Here is your own code block which executes well with PhantomJS 2.1.1 with some tweaks and some added Sysouts for your convenience:
#Test
public void googlesearch()
{
File path=new File("C:\\Utility\\phantomjs-2.1.1-windows\\bin\\phantomjs.exe");
System.setProperty("phantomjs.binary.path",path.getAbsolutePath());
WebDriver driver= new PhantomJSDriver();
driver.manage().window().maximize();
driver.navigate().to("https://www.google.co.in/");
System.out.println("inside Test");
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
System.out.println("Checking if the Search field is Enabled");
driver.findElement(By.name("q")).isEnabled();
System.out.println("Sending lol to Search field");
driver.findElement(By.name("q")).sendKeys("lol");
System.out.println("Clicking on Google Search button Next");
driver.findElement(By.name("btnG")).click();
System.out.println("Google Search Completed");
}