繁体   English   中英

Selenium 并不总是识别何时从 DOM 中删除元素

[英]Selenium does not always recognize when an element is removed from the DOM

我在 mac 10.12.3 上使用带有 chromedriver 2.27 的 chrome 56 时遇到问题,尽管我尝试了几个不同版本的驱动程序和几个不同版本的浏览器,但遇到了同样的问题。 在 UI 中,我可以很清楚地看到一个阻塞层已经清除了,但是 selenium 仍然认为它没有。 等待阻塞层清除后(仅查看浏览器),如果我捕获 driver.getPageSource() 的结果,我将获得“旧”页面源,而不是新页面源(已删除阻塞层)。 当我将旧页面源代码作为 html 文档查看时,我可以看到阻塞层。 当我查看测试结束时截取的屏幕截图时,显然没有阻塞层,并且手动检查 DOM 显示该元素已被删除。 不知何故,selenium 似乎正在缓存旧的页面源,并且无法识别何时从 DOM 中删除了元素。 我似乎无法强制它在不完全重新加载页面的情况下刷新缓存的(?)html。 我想避免重新加载页面,因为这会使对阻塞层是否被正确删除的测试无效。

我已经尝试从阻塞层元素中获取一些信息(使用诸如 element.isDisplayed() 或 element.getLocation() 之类的良性内容),但这些似乎仍然表现得好像元素仍然存在一样。

任何有关如何处理此问题的建议将不胜感激。

如果您的目标是单击项目而不考虑阻塞层的状态,您可以使用内联 javascript 单击一个元素。 下面的示例代码。

    try {
            e.click();
        } catch (org.openqa.selenium.WebDriverException E1) {
            ((JavascriptExecutor) driver).executeScript("arguments[0].click();", e.findElements(By.xpath(".//a")).get(0));
        }

我在使用 GWT 弹出面板运行 Selenium 测试时遇到了同样的问题。

有时动画不会完成,弹出窗口和后面的玻璃留在 DOM 上。

当这种情况发生时,我试图从 dom 中删除这两个元素,但得到了奇怪的结果(dom 中的其他元素被删除了!!?)。

最后,我实现了这些隐藏这 2 个元素并更改 className 的函数,以便它们不再打扰我们(请参阅下面的代码)

waitForPopupOpeningAnimationFinished() :在应该打开弹出窗口的点击后启动

waitForPopupClosingAnimationFinished() :在单击弹出按钮后启动,应关闭弹出窗口

    // 200 is the animation time of the popup, we wait a lot more, see com.google.gwt.user.client.ui.PopupPanel.ANIMATION_DURATION
public static final int POPUP_ANIMATION_WAIT_TIME = 300;
public static final String CLASS_GWT_DIALOG_BOX = "gwt-DialogBox";
public static final String X_POPUP = "//div[@class='" + CLASS_GWT_DIALOG_BOX + "']";
public static final By BY_POPUP = By.xpath(X_POPUP);

public static final String X_POPUP_TOTALLY_OPENED_LOCATOR = "//div[contains(@class, '" + CLASS_GWT_DIALOG_BOX + "') and contains(@style, 'clip: rect(auto, auto, auto, auto);')]";
public static final By BY_POPUP_TOTALLY_OPENED_LOCATOR = By.xpath(X_POPUP_TOTALLY_OPENED_LOCATOR);
private static final String CLASS_GWT_POPUP_PANEL_GLASS = "gwt-PopupPanelGlass";
private static final By BY_GLASS_PANEL = By.xpath("//div[contains(@class, '" + CLASS_GWT_POPUP_PANEL_GLASS + "')]");


    public void waitForPopupOpeningAnimationFinished() {
    LOGGER.info("waitForPopupOpeningAnimationFinished");
    try {
        waiter.withTimeout(Duration.ofMillis(POPUP_ANIMATION_WAIT_TIME)).until(ExpectedConditions.visibilityOfElementLocated(BY_POPUP_TOTALLY_OPENED_LOCATOR));
    } catch (TimeoutException e) {
        LOGGER.info("Forcing popup to be visible");
        try {
            js.executeScript("var elementsToBeRemoved = document.getElementsByClassName('" + CLASS_GWT_DIALOG_BOX + "');" //
                    + "if(elementsToBeRemoved.length>0){" //
                    + "elementsToBeRemoved[0].style.overflow='visible';" //
                    + "elementsToBeRemoved[0].style.clip='rect(auto,auto,auto,auto)';" //
                    + "}");
        } catch (JavascriptException e2) {
            LOGGER.warn("Could not find popup to force to be open", e2.getCause());
        }
    }
}

    public void waitForPopupClosingAnimationFinished() {
    try {
        LOGGER.info("waitForPopupClosingAnimationFinished");
        waiter.withTimeout(Duration.ofMillis(POPUP_ANIMATION_WAIT_TIME)).until(ExpectedConditions.invisibilityOfElementLocated(BY_POPUP));
        waiter.withTimeout(Duration.ofMillis(POPUP_ANIMATION_WAIT_TIME)).until(ExpectedConditions.invisibilityOfElementLocated(BY_GLASS_PANEL));
    } catch (TimeoutException e) {
        LOGGER.info("Waiting for popup closing did not work as expected, forcing it");
        javascriptRemovalOfElementByClassName(CLASS_GWT_DIALOG_BOX);
        javascriptRemovalOfElementByClassName(CLASS_GWT_POPUP_PANEL_GLASS);
    }
}

    private void javascriptRemovalOfElementByClassName(String className) {
    LOGGER.info("javascriptRemovalOfElementByClassName : {}", className);
    try {
        js.executeScript("var elementsToBeRemoved = document.getElementsByClassName('" + className + "');" //
                + "if(elementsToBeRemoved.length>0){" //
                + "elementsToBeRemoved[0].style.visibility = 'hidden';" //
                + "elementsToBeRemoved[0].style.display = 'none';" //
                + "elementsToBeRemoved[0].className='shouldHaveBeenRemovedFromDom';" //
                + "}");
        LOGGER.info("Successfully removal of element with class {}", className);
    } catch (JavascriptException jse) {
        LOGGER.info("Apparently element with class {}} does not exists, we are good to go : {}", className, jse.toString());
    }
}

    public void waitForPopupClosingAnimationFinished() {
    try {
        LOGGER.info("waitForPopupClosingAnimationFinished");
        waiter.withTimeout(Duration.ofMillis(POPUP_ANIMATION_WAIT_TIME)).until(ExpectedConditions.invisibilityOfElementLocated(BY_POPUP));
        waiter.withTimeout(Duration.ofMillis(POPUP_ANIMATION_WAIT_TIME)).until(ExpectedConditions.invisibilityOfElementLocated(BY_GLASS_PANEL));
    } catch (TimeoutException e) {
        LOGGER.info("Waiting for popup closing did not work as expected, forcing it");
        javascriptRemovalOfElementByClassName(CLASS_GWT_DIALOG_BOX);
        javascriptRemovalOfElementByClassName(CLASS_GWT_POPUP_PANEL_GLASS);
    }
}

我在展开/折叠 TreeNode 动画时也遇到了同样的问题,因此我实现了在节点展开/折叠后启动的以下功能:

    private static final String X_EXPANDING_TREE_NODE =
"//div[contains(@role, 'treeitem') and @aria-expanded='true']/div[contains(@style, 'overflow: hidden;') and contains(@style, 'height:') and contains(@style, 'position: relative;')]/div[contains(@style, 'top:') and contains(@style, 'position: relative;')]";
private static final By BY_EXPANDING_TREE_NODE = By.xpath(X_EXPANDING_TREE_NODE);

private static final String X_COLLAPSING_TREE_NODE =
"//div[contains(@role, 'treeitem') and @aria-expanded='false']/following:div[contains(@style, 'overflow: hidden;') and contains(@style, 'height:') and contains(@style, 'position: relative;')]/div[contains(@style, 'top:') and contains(@style, 'position: relative;')]";
private static final By BY_COLLAPSING_TREE_NODE = By.xpath(X_COLLAPSING_TREE_NODE);

/**
 * When a report tree node is expanding or collapsing is loading, we can see stuff like
 * <div style="overflow: hidden; height: 1px; position: relative;">
 * <div style="top: -122px; position: relative;">
 * <p>
 * We wait for it do disappear
 * <p>
 * or we force it to animation finished like this for expanding:
 *
 * <div style="overflow: hidden;">
 * <div style="">
 *
 * or we force it to animation finished like this for collapsing:
 *
 * <div style="overflow: hidden; display : none;">
 * <div style="">
 */
public void waitForTreeNodeExpandedAndCollapsed() {
    waitForTreeNodeExpanded();
    waitForTreeNodeCollapsed();
}

public void waitForTreeNodeExpanded(){
    waitForTreeNode(true);
}
public void waitForTreeNodeCollapsed(){
    waitForTreeNode(false);
}

private void waitForTreeNode(boolean expanding) {
    try {
        waiter.withTimeout(Duration.ofSeconds(2)).until(ExpectedConditions.invisibilityOfElementLocated(expanding?BY_EXPANDING_TREE_NODE:BY_COLLAPSING_TREE_NODE ));
    } catch (TimeoutException e) {
        boolean noJavascriptException = false;
        while (!noJavascriptException) { // While javascript throw error like InvalidStateError, we continue
            try {
                LOGGER.info("Waiting for tree expand or collapse did not work as expected, forcing it");
                js.executeScript("while(true){" //
                        + "var iterator = document.evaluate(\"" + (expanding?X_EXPANDING_TREE_NODE:X_COLLAPSING_TREE_NODE) + "\",document, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null );" //
                        + "var thisNode = iterator.iterateNext();" //
                        + "if(thisNode) {" //
                        + "thisNode.parentNode.style='overflow: hidden;" + (expanding?"":"display: none;")  + "';"//
                        + "thisNode.style='';"
                        + "thisNode = iterator.iterateNext();" //
                        + "}else {" //
                        + "break;" //
                        + "}" //
                        + "}");
                noJavascriptException = true;
            } catch (Exception e2) {
                LOGGER.info("Javascript pb", e2.getCause());
            }
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM