In a sidebar menu I want to move to a menu item. I'm using this code:
#FindBy(xpath = ".//*[#id='sidebar-wrapper']/ul//a[contains(text(), 'Contact')]")
WebElement contactLink;
public void clickHamburgerMenuAndContactLink() {
Actions action = new Actions(driver);
action.click(hamburgerMenu).moveToElement(contactLink, 0, 0).click().perform();
}
This works most of the time although it also fails from time to time (behavior seems to be unstable).
First I tried to move without mentioning the x and y Offset using only the webelement contactlink as an argument in the moveToElement method. This don't work at all, I don't understand why. I tried also with build() before the perform() but this makes no difference.
The unstable behaviour is probably due to the animation effect which makes the contact link unsteady. I would wait for the close button since it is displayed once the menu reaches its final position:
public void clickHamburgerMenuAndContactLink() {
WebDriverWait wait = new WebDriverWait(driver, 10000);
hamburgerMenu.click();
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("menu-close")));
contactLink.click();
}
Related
I have a little problem and I don't know why code does not work.
I have element on site (window) which I want to resize (clicking on corner and pulling).
#Test
public void ResizeWindow()
{
driver.get(URL);
WebElement resizeableWindow = driver.findElement(By.xpath("//*[#id='resizable']/div[3]"));
Actions actions = new Actions(driver);
actions.moveToElement(resizeableWindow);
actions.clickAndHold(resizeableWindow);
actions.moveByOffset(50,50);
}
But this piece of code does not want to resize window (code does not have problem with finding element). Any tips? Or hint on what should I change?
You need to call perform() as last command to execute the previous commands
actions.perform();
The methods from Actions class return this, so you can chain them
Actions actions = new Actions(driver);
actions
.moveToElement(resizeableWindow)
.clickAndHold(resizeableWindow)
.moveByOffset(50,50)
.perform();
Basically I'm trying to see if a button is able to be clicked at the moment. If not I would like to try again. So I need some kind of a goto function to return to an earlier line of my code. Although I suspect I written this extremely poorly and it could have been done much easier.
try {
driver.findElement(By.xpath("//button[#id='btn_ok']")).click();
}catch (Exception e) {
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
}
for context, here is the button culprit in question.
<button type="submit" value="ok" name="s1" id="btn_ok" class="green">
You can use fluent wait for this. This will check for the button to be clickable at every 5 seconds for 30 seconds. You can adjust the time according to your need. Try this code and give feedback whether it worked or not.
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(30, TimeUnit.SECONDS)
.pollingEvery(5, TimeUnit.SECONDS)
.ignoring(NoSuchElementException.class);
WebElement clickseleniumlink = wait.until(new Function<WebDriver, WebElement>(){
public WebElement apply(WebDriver driver ) {
return driver.findElement(By.xpath("//button[#id='btn_ok']"));
}
});
clickseleniumlink.click();
Try this way.see if it helps.
int size=driver.findElements(By.xpath("//button[#id='btn_ok']")).size();
if (size>0)
{
driver.findElement(By.xpath("//button[#id='btn_ok']")).click();
}
else
{
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
int size1=driver.findElements(By.xpath("//button[#id='btn_ok']")).size();
if (size1>0)
{
driver.findElement(By.xpath("//button[#id='btn_ok']")).click();
}
}
You can use explicit wait to wait for the button to be clickable. It will test the button every 500 ms for maximum of specified time until it's clickable
WebDriverWait wait = new WebDriverWait(driver, 5); // maximum wait time is 5 here, can be set to longer time
WebElement button = wait.until(ExpectedConditions.elementToBeClickable(By.id("btn_ok")));
button.click();
As a side note, implicitlyWait set the max time the driver will search for an element, it doesn't delay the script.
I prefer this, as it can take literally any boolean condition to "wait until".
public static void WaitUntil(this IWebDriver driver, Func<bool> Condition, float timeout = 10f)
{
float timer = timeout;
while (!Condition.Invoke() && timer > 0f) {
System.Threading.Thread.Sleep(500);
timer -= 0.5f;
}
System.Threading.Thread.Sleep(500);
}
driver.WaitUntil(() => driver.FindElements(By.XPath("some xpath...").Length == 0);
//Here is the particular benefit over normal Selenium waits. Being able to wait for things that have utterly nothing to do with Selenium, but are still sometimes valid things to wait for.
driver.WaitUntil(() => "Something exists in the database");
I find that the implicit waiting causes me more trouble than it is worth. And I find explicit selenium waiting can get a bit verbose, and it doesn't cover everything I need from it in my framework, so I've made a good number of extensions. Here is one of them. Note, I use the FindElements for the example above because I do not want an exception thrown if nothing is found. This should work for you.
Note: This is C#, but it shouldn't be difficult to modify this for any language (especially Java). If your language does not allow extensions like this, simply call the method directly in a class. You will need to put this in a static class to be functional. Be careful when extending existing classes like this in logic, as it can confuse others when they are trying to determine where the methods are defined.
Quick answer
Please checkout below piece of code and lets know if it resolved your problem.
public synchronized boolean clickOnButtonWhenItBecomesClickable() {
boolean buttonClicked=false;
try {
List<WebElement> element = driver.findElements(By.xpath("//button[#id='btn_ok']"));
while(element.size()!=0) {
// if any action needed to perform to display button, please do it.
element = driver.findElements(By.xpath("//button[#id='btn_ok']"));
if(element.size()!=0) {
wait = new FluentWait<WebDriver>((WebDriver) driver).withTimeout(30, TimeUnit.SECONDS).pollingEvery(5,
TimeUnit.SECONDS);
wait.until(ExpectedConditions.elementToBeClickable(driver.findElement(By.xpath("//button[#id='btn_ok']"))));
buttonClicked=true;
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return buttonClicked;
}
I have a Selenium Grid and WebDriver 2.48.2 test that runs too fast. The majority of the time the test stops because a radio button isn't selected prior to a button being pressed.
The radio buttons are setup using JavaScript based on a JSON file to create any number of them within a section on the fly. Once the continue button is clicked that section is destroyed and a new one created with new radio buttons.
I tried an implicit wait with no success.
driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
The only solution that is working for me is a delay to allow enough time for the radio button to be clicked.
driver.findElement(By.id("radiobuttonid")).click();
Thread.sleep(delay);
But in my opinion this isn't an ideal solution, it's possible the delay may not be long enough or that it's too long, wasting time; there could be any number of radio buttons so the time will increase exponentially.
I've tried setting up various explicit waits with different expected conditions but with no success.
I've tried waiting for the radio button to be created since it may not exist (presenceOfElementLocated & elementToBeClickable). I've tried waiting for it to be selected (elementToBeSelected).
I'm having trouble finding exactly what the expected conditions are supposed to do since the descriptions are brief and open to misinterpretation.
Ideally, I want the test to continue soon after the radio button is clicked. If possible, what's the best way to do this?
EDIT
L.Bar's suggestion below didn't work for me, but it was very helpful to determine that the radio buttons exist, just that the continue button is being clicked before the radio button has a chance to be selected.
EDIT 2
This is just to expand on Jeremiah correct answer. I put the code into a method to make it reusable.
private static Predicate<WebDriver> forceSelectionOfElement (final String id)
{
return new Predicate<WebDriver>()
{
#Override
public boolean apply(WebDriver arg0)
{
WebElement element = arg0.findElement(By.id(id));
boolean rval = element.isSelected();
if (!rval) {
element.click();
}
return rval;
}
};
}
Usage
WebDriverWait wait = new WebDriverWait(driver, 5);
wait.until(forceSelectionOfElement("q___01_02_01___1___a"));
Remember to import this namespace, it took me an embarrassingly long time to figure out I imported the wrong one :)
import com.google.common.base.Predicate;
I've had a similar problem, but in my case my 'click' event was lost somewhere. My test would proceed, the click code would trigger, but the state of the element would never visibly change and the test would fail. I ended up leveraging the looping behavior of the WebDriverWait by adding a custom predicate that is a bit more persistent about the selected state.
WebDriverWait wait = new WebDriverWait(driver, 5);
final By lookup = By.id("radio");
LOG.debug("Wait for radio to be clickable.");
wait.until(ExpectedConditions.elementToBeClickable(lookup)); //I assume this implies visibility.
LOG.debug("Element clickable. Proceeding into click behavior.");
wait.until(new Predicate<WebDriver>() {
#Override
public boolean apply(WebDriver arg0) {
LOG.debug("Resolving 'myId' Element");
WebElement radio = arg0.findElement(lookup);
boolean rval = radio.isSelected();
LOG.debug("Element Resolved and has a state of " + (rval ? "selected" : "not selected"));
if (!rval) {
LOG.debug("Clicking on the Element!");
radio.click();
}
//If we return false we will loop. So the first time through we let this click the radio for us.
//Second time through we should find that the element is clicked. If it's not we click it again until it represents the state we're wanting.
return rval;;
}});
The custom predicate will
Resolve the WebElement
Capture the current Selected status
Click the WebElement if it is not selected
Return the current selected status.
So this should not allow the test to proceed until the clicked state of the element is what I want it to be. So far it's done basically what I've wanted.
It's also worth noting that Thread.sleep is seen as not the best practice for selenium interactions. This is what the ExplicitWait concept is meant to account for. I've linked one of the latest topics in which I'm aware of this being discussed.
Thread.sleep works but implicit wait, webdriverwait and fluent wait does not?
Best of Luck!
My way to do it:
public bool IsElementPresent(By by, IWebDriver driver)
{
try
{
driver.FindElement(by);
return true;
}
catch (NoSuchElementException)
{
return false;
}
}
public bool IsElementPresent(By by, IWebDriver driver, int sec)
{
bool itemExist = false;
itemExist = IsElementPresent(by, driver);
while (!itemExist && sec >= 0)
{
Thread.Sleep(1000);
itemExist = IsElementPresent(by, driver);
sec--;
}
if (sec == -1)
return false;
else
return true;
}
Calling to test if exist
//Checking if element exist 10 sec
if(IsElementPresented(By.Id("radiobuttonid"),driver,10))
{
//element exist click on it
}
else
{
//didn't exist.
}
You stated that you explored ExpectedConditions, have you tried ExpectedConditions.elementToBeSelected()? You should be able to detect if the radio button is selected and then move forward. Try something like this
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement radio = driver.findElement(By.id("radiobuttonid"));
radio.click();
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.id("ID of message element")));
// do stuff
EDIT
Changed code after more info from OP
I have a problem using Selenium Webdriver (version 2.32.0) and Firefox (21.0), trying to change the values on a slider.
I wrote a Java code like this:
private void selectGiftCardPrice() throws TestingException {
try {
WebElement slider = getDriver().findElement(
By.cssSelector("div.sliderHandle"));
Actions move = new Actions(getDriver());
move.dragAndDropBy(slider, 90, 0);
move.build().perform();
sleep(4000);
} catch (Exception e) {
log.info(e);
throw new TestingException("e");
}
I tried out every code I found on the Web, every change, and it still does not work. It does not show any problem, just finds the element, and does nothing. Any idea what it is, or what can I do?
EDIT from comment:
I finally made it working with jQuery slider demo
driver.get("http://jqueryui.com/resources/demos/slider/multiple-vertical.html");
WebElement slider = driver.findElement(By.xpath("//div[1]/a[contains(#class,'ui-slider-handle')]"));
But it is still not working for me with jQuery UI Slider demo page using Xpath //div[#id='slider']/a. What is the problem?
This code works absolutely fine for me.
program handles slider of website : Homeshope18.com
Check it out:
WebDriver driver = new FirefoxDriver();
driver.get("http://www.homeshop18.com/fashion-jewellery/category:15143/filter_Theme:%28%22Traditional+Wear%22+%22Cuff+%26+Kada%22+%22Daily+Wear%22+%22Maang+Tikka%22+%22Openable+Round%22+%22Round%22+%22Openable+Oval%22%29/sort:Popularity/inStock:true/?it_category=HP&it_action=JW-HPSP01&it_label=HP-HPSP01-131021235900-PD-JW-ZC-VK-SC_DiwaliFestWeddingJewellery&it_value=0");
WebElement slider = driver.findElement(By.xpath("//*[#id='slider-range']/a[1]"));
Thread.sleep(3000);
Actions moveSlider = new Actions(driver);
Action action = moveSlider.dragAndDropBy(slider, 30, 0).build();
action.perform();
Using Actions class, firs use clickAndHold("WebElemnt");
Then to move horizontally we need to move in the Y direction of the screen so we can use movebyoffset, i.e X-axis: 0 & Y axis: 40px
To move vertically we need to move in the X direction of the screen so we can use movebyoffset, i.e X-axis: 40px & Y axis: 0
The sample code would be :
Actions slider=new Actions(driver);
slider.clickAndHold("WebElemnt");
slider.movebyoffset(0,40).build.perform();
I want to do mouseover function over a drop down menu. When we hover over the menu, it will show the new options.
I tried to click the new options using the xpath. But cannot click the menus directly.
So, as the manual way I am trying to hover over the drop down menu and then will click the new options.
Actions action = new Actions(webdriver);
WebElement we = webdriver.findElement(By.xpath("//html/body/div[13]/ul/li[4]/a"));
action.moveToElement(we).build().perform();
Its not really possible to perform a 'mouse hover' action, instead you need to chain all of the actions that you want to achieve in one go. So move to the element that reveals the others, then during the same chain, move to the now revealed element and click on it.
When using Action Chains you have to remember to 'do it like a user would'.
Actions action = new Actions(webdriver);
WebElement we = webdriver.findElement(By.xpath("html/body/div[13]/ul/li[4]/a"));
action.moveToElement(we).moveToElement(webdriver.findElement(By.xpath("/expression-here"))).click().build().perform();
None of these answers work when trying to do the following:
Hover over a menu item.
Find the hidden element that is ONLY available after the hover.
Click the sub-menu item.
If you insert a 'perform' command after the moveToElement, it moves to the element, and the sub-menu item shows for a brief period, but that is not a hover. The hidden element immediately disappears before it can be found resulting in a ElementNotFoundException. I tried two things:
Actions builder = new Actions(driver);
builder.moveToElement(hoverElement).perform();
builder.moveToElement(clickElement).click().perform();
This did not work for me. The following worked for me:
Actions builder = new Actions(driver);
builder.moveToElement(hoverElement).perform();
By locator = By.id("clickElementID");
driver.click(locator);
Using the Actions to hover and the standard WebDriver click, I could hover and then click.
Based on this blog post I was able to trigger hovering using the following code with Selenium 2 Webdriver:
String javaScript = "var evObj = document.createEvent('MouseEvents');" +
"evObj.initMouseEvent(\"mouseover\",true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);" +
"arguments[0].dispatchEvent(evObj);";
((JavascriptExecutor)driver).executeScript(javaScript, webElement);
This code works perfectly well:
Actions builder = new Actions(driver);
WebElement element = driver.findElement(By.linkText("Put your text here"));
builder.moveToElement(element).build().perform();
After the mouse over, you can then go on to perform the next action you want on the revealed information
Check this example how we could implement this.
public class HoverableDropdownTest {
private WebDriver driver;
private Actions action;
//Edit: there may have been a typo in the '- >' expression (I don't really want to add this comment but SO insist on ">6 chars edit"...
Consumer < By > hover = (By by) -> {
action.moveToElement(driver.findElement(by))
.perform();
};
#Test
public void hoverTest() {
driver.get("https://www.bootply.com/render/6FC76YQ4Nh");
hover.accept(By.linkText("Dropdown"));
hover.accept(By.linkText("Dropdown Link 5"));
hover.accept(By.linkText("Dropdown Submenu Link 5.4"));
hover.accept(By.linkText("Dropdown Submenu Link 5.4.1"));
}
#BeforeTest
public void setupDriver() {
driver = new FirefoxDriver();
action = new Actions(driver);
}
#AfterTest
public void teardownDriver() {
driver.quit();
}
}
For detailed answer, check here - http://www.testautomationguru.com/selenium-webdriver-automating-hoverable-multilevel-dropdowns/
I found this question looking for a way to do the same thing for my Javascript tests, using Protractor (a javascript frontend to Selenium.)
My solution with protractor 1.2.0 and webdriver 2.1:
browser.actions()
.mouseMove(
element(by.css('.material-dialog-container'))
)
.click()
.perform();
This also accepts an offset (i'm using it to click above and left of an element:)
browser.actions()
.mouseMove(
element(by.css('.material-dialog-container'))
, -20, -20 // pixel offset from top left
)
.click()
.perform();
Sample program to mouse hover using Selenium java WebDriver :
public class Mhover {
public static void main(String[] args){
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("http://www.google.com");
WebElement ele = driver.findElement(By.id("gbqfba"));
Actions action = new Actions(driver);
action.moveToElement(ele).build().perform();
}
}
You can try:
WebElement getmenu= driver.findElement(By.xpath("//*[#id='ui-id-2']/span[2]")); //xpath the parent
Actions act = new Actions(driver);
act.moveToElement(getmenu).perform();
Thread.sleep(3000);
WebElement clickElement= driver.findElement(By.linkText("Sofa L"));//xpath the child
act.moveToElement(clickElement).click().perform();
If you had case the web have many category, use the first method. For menu you wanted, you just need the second method.
Try this re-usable method,
public void MoveThePoiterToElement(By by){
log.info("Moving the cursor to the element");
Actions action = new Actions(driver);
action.moveToElement(driver.findElement(by));
action.build().perform();
log.info("Cursor moved to the element");
}
I tried that and it worked normal
action = ActionChains(driver)
element = driver.find_element_by_xpath("XPath_selector")
action.move_to_element(element).perform()