0

I have a element I am trying to click that is part of a dropdown in a mobile hamburger menu. This dropdown only has two elements/ options in it. I am trying to click the second element. However, when the test is running the test runs too fast, causing the other element in the dropdown to be clicked first. Even though my XPath explicitly calls out the second element I actually want to click. This test is being run in an iOS Mobile emulation chrome window.

What I believe the problem to be is that the dropdown has a nice/ smooth slide effect, making it so that when the dropdown is opened the two elements are kind of on top of each other as they are sliding into place. So the WebDriver tries to click on the second element as it should, but it's sort of 'behind' the first element in a way. The WebDriver ends up actually clicking the first element. I hope this makes sense.

So has any one come across an issue like this, have any slick tricks to help wait for the dropdown to be fully open before selecting a menu item?

The elements are setup like this

<ul class="hamburger-menu">
<li>Menu Item</li>
<li>Dropdown Menu
  <div class="mobile-dropdown">
    <div class="dropdown-element-1"></div>
    <div class="dropdown-element-2"></div>
  </div>
</li>
<li>Menu Item</li>
</ul>

This is a rough version of what I am doing in the code

public static Main()
{   
    By hamburgerMenu = By.XPath("Not important, but the xpath to the menu here");
    By hamburgerMenuButton = By.ClassName("hamburger-menu");
    By dropdownMenuButton = By.XPath("//ul[@class='hamburger-menu']/li[2]");
    By dropdownElement1 = By.XPath("//div[@class='dropdown-element-1']");
    By dropdownElement2 = By.XPath("//div[@class='dropdown-element-2']");   

    IWebDriver driver = new ChromeDriver();
    driver.Navigate().GoToUrl("http://sample.com");

    // Click to open hamburger menu
    driver.FindElement(hamburgerMenuButton).Click();
    //Here I implement a selenium Explicit wait that waits for the hamburger menu to be fully open
    _ = Extensions.WaitForVisible(driver.FindElement(hamburgerMenu), 10);

    // Click to open dropdown menu
    driver.FindElement(dropdownMenuButton).Click();
    //Here I assert that the two elements are present
    Assert.True(driver.FindElement(dropdownElement1).Displayed);
    Assert.True(driver.FindElement(dropdownElement2).Displayed);

    //I need some type of wait here?

    //Then I click on the second element
    driver.FindElement(dropdownElement2).Click();
}

I can't seem to get an Implicit or Explicit wait to work, because those elements are already available in the DOM, so the WebDriver picks them up instantly. There doesn't seem to be anything to 'wait' for. The elements don't have any attributes that make them 'visible' or anything once they are in place under the dropdown menu.

AuntieDot
  • 1
  • 1

2 Answers2

0

There should be a simple solution by using Task.Delay() method. You can pause the script for a set of time before trying to click the dropdown item. I know it is not the cleanest solution since the delay will also be there if the dropdown loads fast enough.

However here is a way how to fix with C# using Selenium which could fix your problem:

My Code:

using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using System.Threading.Tasks;

class Program {
  static void Main() {
    IWebDriver driver = new ChromeDriver();
    driver.Navigate().GoToUrl("http://sample.com");

    // Click to open hamburger menu
    IWebElement hamburgerMenuButton = driver.FindElement(By.ClassName("hamburger-menu"));
    hamburgerMenuButton.Click();

    // Click to open dropdown menu
    IWebElement dropdownMenuButton = driver.FindElement(By.XPath("//ul[@class='hamburger-menu']/li[2]"));
    dropdownMenuButton.Click();

    // Wait for the dropdown animation to complete
    Task.Delay(2000).Wait(); // Adjust this delay as necessary

    // Now click the second dropdown element
    IWebElement dropdownElement = driver.FindElement(By.XPath("//div[@class='mobile-dropdown']/div[2]"));
    dropdownElement.Click();

    // TODO: Implement your Test Code
  }
}
AztecCodes
  • 1,130
  • 7
  • 23
  • 1
    Is Task.Delay(2000).Wait(); anything like Thread.Sleep(2000)? I am told that it is not a good idea to implement Thread.Sleep and Task.Delay sounds similar. So I am wondering if there is a significant enough difference between the two? – AuntieDot Jun 15 '23 at 21:32
0

If "two elements are kind of on top of each other as they are sliding into place. So the WebDriver tries to click on the second element as it should, but it's sort of 'behind' the first element in a way" is the case, then to click on the second element the best approach would be to to induce WebDriverWait for the ElementToBeClickable() and you can use the following Locator Strategy:

new WebDriverWait(driver, TimeSpan.FromSeconds(20)).Until(ExpectedConditions.ElementToBeClickable(By.XPath("//div[@class='dropdown-element-2']"))).Click();
undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • It seems that when I try this, WebDriver thinks that this element is 'clickable' before it really is, and still clicks on the other element in it's way. – AuntieDot Jun 26 '23 at 22:31