151

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();
John Smith
  • 7,243
  • 6
  • 49
  • 61
Pradeep SJ
  • 2,326
  • 2
  • 15
  • 13
  • Check this site for detailed answer - http://www.testautomationguru.com/selenium-webdriver-automating-hoverable-multilevel-dropdowns/ – vins May 22 '17 at 14:53

10 Answers10

121

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();
Mark Rowlands
  • 5,357
  • 2
  • 29
  • 41
  • 5
    For me this doesn't work. My menu only gets hovered if I perform a build().perform() after a moveToElement() – GarfieldKlon Aug 29 '13 at 07:58
  • 9
    The reason that this wouldn't quite work is that all calls to `webdriver.findElement(By... something)` are executed before anything else (that's the only way their result can be passed on to `moveElement`). At that time the second element that you want to find isn't visible yet because the first one still has to be hovered over. To fix this, as you said, you can insert intermediate `.perform()`s, Then for the second `findElement`, the first hover will have been `perform`ed. The given solution might work, depending on the implementation of the page, but apparently your and my mileage varied. – Sander Verhagen Apr 06 '14 at 08:25
62

None of these answers work when trying to do the following:

  1. Hover over a menu item.
  2. Find the hidden element that is ONLY available after the hover.
  3. 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.

zmorris
  • 1,057
  • 2
  • 12
  • 23
  • 3
    The second example worked for me as well when adding .perform() – TheRed__ Feb 27 '15 at 13:19
  • 1
    Cant belive this is still an issue... not even this works: builder.moveToElement(settings) .moveByOffset(0, 30) .moveToElement(stagingMenu) .pause(20000) .keyDown(Keys.CONTROL) .click(stagingMenu) .keyUp(Keys.CONTROL) .sendKeys(Keys.ENTER) .perform(); i even see the hover css triggerd on the element in the timeout span. but no click gets triggerd no matter what i try – Sangoku May 23 '17 at 09:01
  • How would you handle if the clickable is not an normal element and it comes like **::before**. This before comes visible when you mouse hover – Ashok kumar Ganesan Apr 18 '20 at 13:10
27

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);
John Smith
  • 7,243
  • 6
  • 49
  • 61
Aaron Silverman
  • 22,070
  • 21
  • 83
  • 103
  • 2
    Less obvious solution, but 100% solid for my IE11 testing. If you have problems hovering with `moveToElement`, use this one! I code in C#, so it is not only Java way to do it. – vt100 Aug 18 '15 at 08:39
  • Selenium [Mouse Actions](http://www.seleniumeasy.com/selenium-tutorials/how-to-perform-mouseover-action-in-selenium-webdriver) & [Waits](http://docs.seleniumhq.org/docs/04_webdriver_advanced.jsp#explicit-and-implicit-waits), **Javascript** [initMouseEvent()](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent) [`Example`](http://help.dottoro.com/ljtxvfef.php) – Yash Feb 12 '16 at 11:35
  • What is this `arguments[0]`? – Arian Jan 24 '17 at 01:32
  • @ArianHosseinzadeh its the passed in dom reference to the second argument passed to `executeScript()`, which is a `webElement` – Aaron Silverman Jan 26 '17 at 20:14
  • I get missign ref for Javascript executor. What refercne do I need to add in C# – mark1234 Jul 17 '17 at 21:47
11

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

7

Check this example how we could implement this.

enter image description here

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/

DraxDomax
  • 1,008
  • 1
  • 9
  • 28
vins
  • 15,030
  • 3
  • 36
  • 47
5

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();
Andrei Suvorkov
  • 5,559
  • 5
  • 22
  • 48
Plato
  • 10,812
  • 2
  • 41
  • 61
4

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();
    }
}
Andrei Suvorkov
  • 5,559
  • 5
  • 22
  • 48
Helping Hands
  • 5,292
  • 9
  • 60
  • 127
  • 9
    Please consider including some information about your answer, rather than simply posting code. We try to provide not just 'fixes', but help people learn. You should explain what was wrong in the original code, what you did differently, and why your change(s) worked. – Andrew Barber Dec 10 '14 at 16:53
  • 2
    @AndrewBarber - Given program can really help to user. That program is working proper. User has already accepted that.. – Helping Hands Dec 11 '14 at 05:34
  • 4
    I don't dispute it will *work*; I'm saying that you should explain *why* it might work, why what they had was not working, and what you changed. – Andrew Barber Dec 11 '14 at 13:46
  • This code is equivalent to the OP's and doesn't answer the question. Without any contextual information , it is superfluous. – jpaugh Dec 24 '15 at 15:46
4

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.

Andrei Suvorkov
  • 5,559
  • 5
  • 22
  • 48
Prasetyo Budi
  • 96
  • 1
  • 8
1

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");
}
Jayanth Bala
  • 758
  • 1
  • 5
  • 11
0

I tried that and it worked normal

action = ActionChains(driver)
element = driver.find_element_by_xpath("XPath_selector")
action.move_to_element(element).perform()
Mahmoud Magdy
  • 662
  • 10
  • 13