I am learning Selenium Webdriver using Java.
As a learning example, I tried to open MakeMyTrip, access International Flights page and click on One Way radio button in Google Chrome.
I tried different ways to locate this radio button but it's still not working.
Please find below my code sample.
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
public class TryRadioClass {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.setProperty("webdriver.chrome.driver", "Chrome exe path");
WebDriver driver=new ChromeDriver();
driver.get("http://www.makemytrip.com/international-flights");
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(45, TimeUnit.SECONDS);
boolean displayFlag = driver.findElement(By.linkText("ONE WAY")).isDisplayed();
System.out.println("Display Flag :- "+displayFlag);
boolean enableFlag = driver.findElement(By.linkText("ONE WAY")).isEnabled();
System.out.println("Enable Flag :- "+enableFlag);
if(displayFlag==true && enableFlag==true)
{
WebElement element=driver.findElement(By.linkText("ONE WAY"));
element.click();
System.out.println("Tried to click One Way");
}
}
}
Can anyone please help me to resolve this issue?
Use below code :-
if(displayFlag==true && enableFlag==true)
{
try{
Thread.sleep(5000);
}
catch(Exception ex)
{
System.out.println(ex.getMessage());
}
WebElement element=driver.findElement(By.xpath("//span[#class='radio_state']"));
JavascriptExecutor executor = (JavascriptExecutor) driver;
executor.executeScript("arguments[0].click();", element);
System.out.println("Tried to click One Way");
}
enjoy .. get back to me if still getting any issue :)
Clicking on link sometimes might skip checking the radio button. Try clicking on the radio button (or input html tag) directly rather than clicking on the anchor tag. Here's an example -
WebElement ele=driver.findElement(By.xpath("//input[#value='one_way']"));
ele.click();
Hope this helps.
Try to never use Thread.sleep(time)
Never use general Exception catching.
Instead of it try this, what is more safe:
public Boolean isDisplayed() {
try {
wait.withTimeout(20).until(new ExpectedCondition<Boolean>() {
#Nullable #Override public Boolean apply(WebDriver input) {
return videoComponent.isDisplayed();
}
});
} catch (TimeoutException e) {
return false;
}
return true;
}
This code will check markup within 20 seconds until it return true.If not, after 20 sec it will return false.
Always specify Exception type, which you want to catch. In other cases it is useless.
Try below xpath.
//*[#id="one_way_button1"]/span/input
It should work.
driver.findElement(By.xpath(//*[#id=\"one_way_button1\"]/span/input)).click();
As per my check, the specific radio button has following structure:
<a id="one_way_button1" href="javascript:void(0);" onclick="change_trip_type('one_way_button', 'trip_type', 'o');" class="one_way_button trip_type row first seg_text" tabindex="1">
<span class="radio_state">
<input type="radio" name="way_fields" value="one_way">
</span> ONE WAY
</a>
So what you are gonna to click is not the tag a which contains 'ONE WAY' but the span inside. You may have a try to locate the span by using xpath
"//a[text()='ONE WAY']/span[#class='radio_state']"
We have found in the past that with a radio and a click that the above happens (Sometimes it clicks it sometimes it does not) and as we try and steer clear of wait for tasks/Thread.Sleep (Due to then timing issues it then can cause on different environments). This alone can become a giant headache quick in using thread.sleeps :p
We have personally found that sometimes the best solution is to send a click then a (Sendkeys.Enter or a Sendkeys.Space) or just send the (Sendkeys.Enter or a Sendkeys.Space) only and don't use the click with a radio.
Especially on pages that use Telerik controls. This then tends to work on multiple machines/environments without the need to add a Thread.Sleep and make every test which uses that step take way longer than it needs to (Trust me when you have 1000's of tests that 5s thread.sleep soon adds up if a lot of tests use the same method)
Just throwing in another possible solution into the mix...
This is the more proper way to do this and I just tested it and it works fine. The best practice is to wait for the element to be clickable. You do that using WebDriverWait with ExpectedConditions. What this will do is wait up to 20s for the element to appear, when it does execution continues. This is a big advantage over Thread.sleep().
driver.get("http://www.makemytrip.com/international-flights");
driver.manage().window().maximize();
WebDriverWait wait = new WebDriverWait(driver, 20);
WebElement oneWayRadioButton = wait.until(ExpectedConditions.elementToBeClickable(By.id("one_way_button1")));
oneWayRadioButton.click();
System.out.println("Clicked One Way");
I tried many different ways to force selenium to wait for the radio button to be visible but it kept timing out. I eventually had to settle for clicking the label for:
WebDriverWait wait = new WebDriverWait(driver, 20);
WebElement element = driver.findElement(selector);
wait.until(ExpectedConditions.elementToBeClickable(element));
element.click();
Where selected is defined by:
By selector = By.cssSelector(cssSelector);
With HTML looking like this:
...
<div class="multi-choice">
<input id="wibble" type="radio" name="wobble" value="TEXT">
<label for="wibble">Wobble</label>
</div>
...
And an example string cssSelector of:
String cssSelector = "label[for='wibble']"
Related
I'm currently testing an email service, and upon opening a list of options to filter email, I want to be able to automate clicking on an option in the list. The code for the list is:
However, selenium cannot find this element, even though I can find it by searching the HTML using CTRL+F. The code I'm currently using to try and find and click this list element is:
wait.until(ExpectedConditions.visibilityOfElementLocated(org.myorg.automation.Objects.ManageEmails.Locators.FilterList));
Select dropdown = new Select(driver.findElement(org.myorg.automation.Objects.ManageEmails.Locators.FilterList));
dropdown.selectByVisibleText("Unread");
The xpath of the list is:
/html/body/div[7]/div/div/div/div/div/div/ul
Any help would really be appreciated!!
The problem is that you don't have a select in this case and the: Select dropdown = new Select(); wont work. You'll need a custom method to select a value from that list
public class Testing {
public WebDriver driver;
#Test
public void TestSomething() {
driver = new ChromeDriver();
driver.get("<the url where this list is present>");
// assuming that the ul list is unique on the page if not find another way to get it
WebElement ulListParent = driver.findElement(By.xpath("//ul[contains(#class,'ms-ContextualMenu-list is-open')]"));
SelectBasedOnValue(ulListParent, "Unread");
driver.close();
}
public void SelectBasedOnValue(WebElement parentElement, String optionValue) {
parentElement.findElement(By.xpath(String.format("//li[text()='%s']", optionValue))).click();
}
}
public void Hover()
{
Actions action = new Actions(BrowserWindow.Instance.Driver);
action.MoveToElement(WebElement).Perform();
}
This is working in Chrome. Not Edge. I have confirmed with the developer that I am "hovering" over the correct element.
WebElement elem = yourWebDriverInstance.findElement(By.xpath("//*[#class='goog-menu goog-menu-vertical uploadmenu density-tiny']/input"));
String js = "arguments[0].style.height='auto'; arguments[0].style.visibility='visible';";
((JavascriptExecutor) yourWebDriverInstance).executeScript(js, elem);
Which also failed to work. Anyone have any idea what I am doing wrong?
More info.
This is also failing on Firefox. I saw an article about out of date selenium drivers. I have JUST installed both geckodriver and set the Edge driver to auto update according to the documentation. I do not believe I have out of date drivers.
More info take 2
Calling code is
public static void DoCloseActiveTabEntire()
{
Element tab = new Element(byTab);
tab.Hover();
// CLose button is not clickable. Cannot use standard BUTTON for find
Button close = new Button(byClosePanelButton);
close.Click();
}
If I set a break point at button close... after the hover attempt, I notice that moving my mouse over the "tab" also does not cause the button to be visible.
This is weird. But replace
action.MoveToElement(WebElement).Perform();
with
action.MoveToElement(WebElement).Build().Perform();
And it works. I read that the Build is built into Perform. But I was kinda just smacking at it hoping something fell out. And it worked.
perform()
perform() is the convenience method for performing the actions without calling build() first.
build()
build() generates a composite action containing all actions so far, ready to be performed and additionally also resets the internal builder state, so subsequent calls to build() will contain fresh sequences.
This usecase
In your usecase, you have invovoked perform() just after moveToElement(WebElement) without generating the composite action to be performed using build().
Solution
A straight forward solution would be to invoke build() before perform() as follows:
public void Hover()
{
Actions action = new Actions(BrowserWindow.Instance.Driver);
action.moveToElement(WebElement).build().perform();
}
So, I don't know why I thought the build().perform() did the job. I know it worked ONCE. What I wound up doing is keeping the hover code the same.
public void Hover()
{
Actions action = new Actions(BrowserWindow.Instance.Driver);
action.MoveToElement(WebElement).Build().Perform();
Thread.Sleep(1000);
}
I changed the calling code which attempts to close the panel/page whatever I want to call it to this:
public static void DoCloseActiveTabEntire()
{
// So there is a defect in EDGE whereby the behavior of the code containted in the hover on the tab executes without
// error but the action underneath does not occur. So in Edge, callng the hover method of the TAB as seen in the else condition
// below does nto display the CLOSE button which needs to be clicked.
// So for Edge, javascript is used to display the button directly.
IWebElement close;
if (BrowserWindow.Instance.Browser == BrowserWindow.Browsers.Edge)
{
close = BrowserWindow.Instance.Driver.FindElement(byClosePanelButton);
string js = "arguments[0].style.height='auto'; arguments[0].style.visibility='visible'; arguments[0].style.display='inline';";
IWebDriver driver = BrowserWindow.Instance.Driver;
IWebElement element = close;
((IJavaScriptExecutor)driver).ExecuteScript(js, element);
}
else
{
Element tab = new Element(byTab);
tab.Hover();
close = new Button(byClosePanelButton).WebElement;
}
close.Click();
}
For me, I am happy that the thing can be closed. I don't care that much whether the hover achieves it.
I have been reading about stale elements and am still a bit confused. For instance, the following won't work, correct?
public void clickFoo(WebElement ele) {
try {
ele.click();
} catch (StaleElementReferenceException ex) {
ele.click();
}
}
because if ele is stale, it will remain stale. The best thing is to redo the driver.findElement(By), but as you can see in this example, there is no xpath. You can attempt to ele.getAttribute("id") and use that, but if the element has no id, this also will not work. All methods calling this would have to put the try/catch around it, which may not be feasible.
Is there some other way the element could be refound? Also, assuming there is an id, would the id remain the same after the element goes stale? What in the WebElement object ele is different once it goes stale?
(Java Eclipse)
I would recommend you NOT create a method like the above. There's no need to add another function layer on top of .click(). Just call .click() on the element itself.
driver.findElement(By.id("test-id")).click();
or
WebElement e = driver.findElement(By.id("test-id"));
e.click();
One way that I use regularly to avoid stale elements is find the element only when you need it and generally I do this by in a page object method. Here's a quick example.
The page object for a home page.
public class HomePage
{
private WebDriver driver;
public WebElement staleElement;
private By waitForLocator = By.id("sampleId");
// please put the variable declarations in alphabetical order
private By sampleElementLocator = By.id("sampleId");
public HomePage(WebDriver driver)
{
this.driver = driver;
// wait for page to finish loading
new WebDriverWait(driver, 10).until(ExpectedConditions.presenceOfElementLocated(waitForLocator));
// see if we're on the right page
if (!driver.getCurrentUrl().contains("samplePage.jsp"))
{
throw new IllegalStateException("This is not the XXXX Sample page. Current URL: " + driver.getCurrentUrl());
}
}
public void clickSampleElement()
{
// sample method code goes here
driver.findElement(sampleElementLocator).click();
}
}
To use it
WebDriver driver = new FirefoxDriver();
driver.manage().window().maximize();
driver.get("http://www.example.com");
HomePage homePage = new HomePage(driver);
homePage.clickSampleElement();
// do stuff that changes the page and makes the element stale
homePage.clickSampleElement();
Now I no longer have to rely on an old reference. I just call the method again and it does all the work for me.
There are many references on the page object model. Here's one from the Selenium wiki. http://www.seleniumhq.org/docs/06_test_design_considerations.jsp#page-object-design-pattern
If you want to read more info on what a stale element is, the docs have a good explanation. http://docs.seleniumhq.org/exceptions/stale_element_reference.jsp
My test script are developed using Java with Selenium webdriver api. There is 1 particular scenario where I need to click on a sub option loaded from a dropdown menu but I am not able to do that. Following are the test steps and the screenshot for the particular problem.
-Launch Microsoft Outlook Web App (OWA) and login
-On main screen I need to enter some text in Search Field
-Click the drop down next to it
-Select "This Folder" from the options loaded
(Screenshot)
I dont see any frameid so not using any. Dropdown works fine but failing to click on suboption.
Adding the code which I am using for click this
public static final By searchDropDown_locator= By.xpath(".//*[#id='divSScp']");
public static final By thisFolderText_locator= By.xpath("(.//*[#id='spnT' and text()='This Folder'])[2]");
public void clickSearchDropDown()
{
WebElement searchIcon= websitedriver.findElement(searchDropDown_locator);
searchIcon.click();
}
public void clickThisFolder()
{
WebElement searchIcon= websitedriver.findElement(thisFolderText_locator);
searchIcon.click();
}
I am calling both these functions in my script file.
What could be the solution here.
Try to use JavascriptExecutor for click as below
public void clickSearchDropDown()
{
WebElement searchIcon= websitedriver.findElement(searchDropDown_locator);
JavascriptExecutor executor = (JavascriptExecutor) driver;
executor.executeScript("arguments[0].click();", searchIcon);
}
public void clickThisFolder()
{
WebElement searchIcon= websitedriver.findElement(thisFolderText_locator);
JavascriptExecutor executor = (JavascriptExecutor) driver;
executor.executeScript("arguments[0].click();", searchIcon);
}
Hope it will help you :)
I am trying to automate search box of Amazon.in and when i try to enter some string over there, it rather points towards the address bar of browser. My code for the same.
Note- I have already tried with different xpaths using firebug and also through tag traversing.
Also please let me know why we have to use always build and perform methods with actions?
public static void main(String args[])
{
WebDriver driver= new FirefoxDriver();
driver.get("http://amazon.in");
Actions action=new Actions(driver);
WebElement element= driver.findElement(By.xpath(".//*[#id='nav-link-yourAccount']/span[2]"));
action.moveToElement(element).build().perform();
WebElement search= driver.findElement(By.xpath(".//*[#id='twotabsearchtextbox']"));
action.keyDown(Keys.SHIFT).moveToElement(search).sendKeys("teststring").build().perform();
action.contextClick(search).build().perform();
}
public static void main(String args[]) {
WebDriver driver = new FirefoxDriver();
driver.get("http://amazon.in");
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
Actions action = new Actions(driver);
WebElement search = driver.findElement(By.xpath(".//*[#id='twotabsearchtextbox']"));
//Search using actions by combining entering search string and then hit enter
action.click(search).sendKeys("Test").sendKeys(Keys.RETURN).build().perform();
// This also works where it does the same without actions class
search.sendKeys("test");
search.sendKeys(Keys.RETURN);
}
In your code:
Below line enters teststring into the browser search instead of the amazon search bar because you are just moving to that element and not clicking on it. action.keyDown(Keys.SHIFT).moveToElement(search).sendKeys("teststring").build().perform();
This like right clicks / context click on the search bar
action.contextClick(search).build().perform();
From the API doc:
build() Generates a composite action containing all actions so far,
ready to be performed (and resets the internal builder state, so
subsequent calls to build() will contain fresh sequences).
perform() A convenience method for performing the actions without
calling build() first
Please read below links for a clear picture on them:
LinkOne
LinkTwo