Java 元素不可见异常-即使使用了不同的Selenium等待

Java 元素不可见异常-即使使用了不同的Selenium等待,java,selenium-webdriver,wait,Java,Selenium Webdriver,Wait,我正在尝试使用Selenium和Java自动化web应用程序的功能测试。在我的应用程序中有几个菜单。单击特定菜单时,会出现子菜单下拉列表 我使用下面的代码单击子菜单 driver.findElement(By.xpath("id=menu")).click(); driver.findElement(By.xpath("id=sub_menu_a")).click(); 但问题是它在第二行抛出了一个“ElementNotVisibleException”。即使使用隐式等待,也会发生同样的情况

我正在尝试使用Selenium和Java自动化web应用程序的功能测试。在我的应用程序中有几个菜单。单击特定菜单时,会出现子菜单下拉列表

我使用下面的代码单击子菜单

driver.findElement(By.xpath("id=menu")).click();
driver.findElement(By.xpath("id=sub_menu_a")).click();
但问题是它在第二行抛出了一个“ElementNotVisibleException”。即使使用隐式等待,也会发生同样的情况

driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("id=sub_menu_a")));
显式等待

driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("id=sub_menu_a")));
等等

Wait<WebDriver> fluentWait=new FluentWait<WebDriver>(driver)
                .withTimeout(60, TimeUnit.SECONDS)
                .pollingEvery(2, TimeUnit.SECONDS)
                .ignoring(NoSuchElementException.class,ElementNotVisibleException.class);
        WebElement element=fluentWait.until(new Function<WebDriver, WebElement>() {
            public WebElement apply(WebDriver driver){
                driver.findElement(By.xpath("id=menu"));
                return driver.findElement(By.xpath("id=sub_menu_a"));
            }
        });
        element.click();

在第一行代码之前和之后。但这并不是一个永久的解决方案,因为页面加载时间可能因网络速度和页面中的数据而异。还有其他解决方案吗?

流畅的等待应该可以。 尝试使用类似以下内容:

Wait<WebDriver> wait = new FluentWait<WebDriver>(driver).withTimeout(10, TimeUnit.SECONDS).ignoring(NoSuchElementException.class);
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("id=sub_menu_a")));
Wait Wait=new FluentWait(驱动程序)。带超时(10,TimeUnit.SECONDS)。忽略(NoSuchElementException.class);
wait.until(ExpectedConditions.elementtobelickable(By.xpath(“id=sub_menu_a”));
但我会选择css选择器,它们非常适合html页面

Wait<WebDriver> wait = new FluentWait<WebDriver>(driver).withTimeout(10, TimeUnit.SECONDS).ignoring(NoSuchElementException.class);
wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#sub_menu_a")));
Wait Wait=new FluentWait(驱动程序)。带超时(10,TimeUnit.SECONDS)。忽略(NoSuchElementException.class);
wait.till(ExpectedConditions.element可选择(由.cssSelector(“子菜单”));
或者如果你的子菜单是菜单的子菜单,我会选择它

Wait<WebDriver> wait = new FluentWait<WebDriver>(driver).withTimeout(10, TimeUnit.SECONDS).ignoring(NoSuchElementException.class);
wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#menu #sub_menu_a")));
Wait Wait=new FluentWait(驱动程序)。带超时(10,TimeUnit.SECONDS)。忽略(NoSuchElementException.class);
wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector(“#menu#sub#menu_a”));
你能试试吗


另外,如果你能让html找到正确的xpath,那就更好了,因为我认为更好的xpath会产生点击子菜单的结果。

很久以前我也有类似的问题(不记得确切的情况,所以剪下的html页面确实会有帮助),所以我不得不使用Thread.sleep() 为了避免长时间等待,我们将提出类似以下方法:

static void waitAndClick(WebDriver driver, By by, int attempts, int sleep) throws InterruptedException {
    for (int i = 0; i < attempts; i++) {
        WebElement element = null;
        try {
            element = driver.findElement(by);
        } catch (NoSuchElementException e) {
            // Do nothing
        }
        if (element == null) {
            int time = sleep * (i + 1);
            Thread.sleep(time);
        } else {
            element.click();
            break;
        }
    }
    throw new NoSuchElementException("Error");
}
static void waitAndClick(WebDriver驱动程序、By、int尝试、int睡眠)抛出中断异常{
for(int i=0;i

这不是一个100%完整的解决方案,只是一个想法。

尝试使用Actions类,看看它是否有效

driver.findElement(By.xpath("id=menu")).click(); 
WebElement subMenu=driver.findElement(By.xpath("id=sub_menu_a"));   
Actions myaction = new Actions(driver);
myaction.moveToElement(subMenu);
WebDriverWait wait = new WebDriverWait(driver, 15);
wait.until(ExpectedConditions.elementToBeClickable(subMenu));
myaction.click().perform();
试试这个

    WebElement menu=driver.findElement(By.xpath("id=menu"));
    JavascriptExecutor executor = (JavascriptExecutor)driver;
    executor.executeScript("arguments[0].click();", menu);
    WebElement subMenu=driver.findElement(By.xpath("id=sub_menu_a"));
    executor.executeScript("arguments[0].click();", subMenu);

希望这项工作

我已经编辑了我的答案并添加了我的FluentWait。你的定位器应该很好,因为它们可以用于睡眠。也许忽略ElementNotVisibleException是一个问题。上述解决方案在80%的时间内都可以正常工作,但偶尔会失败,我经常想,我必须使用睡眠。但这始终是一个Javascript等待问题。您是否使用任何UI框架?例如,对于JQuery Mobile,您必须等待css选择器
html.ui Mobile rendering
消失,否则框架尚未完成渲染。您确定您的ID在整个DOM树中是唯一的,而不仅仅是在可见页面中吗?我认为webdriver可以找到“菜单”,并在加载页面时单击它。因此,菜单没有弹出,导致试图查找子菜单时出现“ElementNotVisibleException”。因此,在单击菜单之前应用所有类型的等待,仍然是失败的。有没有办法等到页面完全加载后再运行呢?这是可行的,但问题是我添加了30秒的隐式等待时间。因此,如果在第一次迭代中找不到元素,那么webdriver将等待30秒来抛出异常。