0

亲爱的,我正在使用 Selenium EventFiringWebDriver 来记录调用的 Web 驱动程序方法。我认识到我经常收到“ StaleReferenceException ”,而当我只使用 HtmlUnitDriver 时,我没有遇到问题。

我还认识到调用,即“click()”已经在浏览器中执行,尽管“StaleElementReferenceException”被抛出。

当 EventFiringWebDriver 在使用 HtmlUnitDriver 或 FirefoxDriver 时遇到此类问题时,有人知道吗?会不会是原始驱动程序在运行时更新了 WebElements 而 EventFiringWebDriver 的包装 WebElements没有?或者我们应该将此作为 EventFiringWebDriver 实现的错误提出来?

带有 EventFiringWebDriver 的示例代码 - 抛出 StaleElementReferenceException

        HtmlUnitDriver driver = new HtmlUnitDriver();
        driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        ExtentReports extent = new ExtentReports ("report.html", true);
        ExtentTest logger = extent.startTest("test");

        EventFiringWebDriver eventDriver = new EventFiringWebDriver(driver);
        eventDriver.register(new MyWebDriverEventListener(logger));

        try {
            WebElement element  = null;
            eventDriver.get("https://www.google.com");
            element = eventDriver.findElement(By.xpath("//input[@type='text']"));
            element.sendKeys("Test");
            element.submit();
            Thread.sleep(2000);
            element = eventDriver.findElement(By.xpath("//div[@id='search']//a"));
            String title = element.getText();
            // HERE the StaleElementReferenceException get thrown ALTHOUGH the "click" event get processed by the browser, it loads already the page
            try {
                element.click();
            } catch(StaleElementReferenceException ex) {
            }
            Thread.sleep(2000);
            Assert.assertEquals(title, eventDriver.getTitle());
            logger.log(LogStatus.PASS,"end","Test passed");
         } catch(AssertionError error) {
            logger.log(LogStatus.FAIL,"end","Test failed:" + error.getMessage());
            throw error;
         }
        finally {
            extent.endTest(logger);
            extent.flush();
            extent.close();
            eventDriver.quit(); 
        }

相同的代码 - 只是直接使用 HtmlUnitDriver,没有任何问题

        HtmlUnitDriver driver = new HtmlUnitDriver();
        driver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);

        ExtentReports extent = new ExtentReports ("report.html", true);
        ExtentTest logger = extent.startTest("test");

        try {
            WebElement element  = null;
            driver.get("https://www.google.com");
            element = driver.findElement(By.xpath("//input[@type='text']"));
            element.sendKeys("Test");
            element.submit();
            Thread.sleep(2000);
            element = driver.findElement(By.xpath("//div[@id='search']//a"));
            String title = element.getText();
            element.click();
            Thread.sleep(2000);
            Assert.assertEquals(title, driver.getTitle());
            logger.log(LogStatus.PASS,"end","Test passed");
         } catch(AssertionError error) {
            logger.log(LogStatus.FAIL,"end","Test failed:" + error.getMessage());
            throw error;
         }
        finally {
            extent.endTest(logger);
            extent.flush();
            extent.close();
            driver.quit(); 
        }
4

1 回答 1

0

在研究了陈旧异常的堆栈跟踪后,我意识到问题并非直接来自 EventFiringWebDriver。当我在执行单击后尝试获取元素的标记名称时,它被我的WebDriverEventListener的侦听器实现抛出。

对我来说, WebDriverEventListener的设计似乎不是最优的。换句话说,您可能无法在“afterXXX”方法中使用传递的 WebElement,否则您可能会面临过时异常的风险。相反,您应该使用“beforeXXX”方法来检索元素的详细信息。

我的 StaleElementReferenceException 的堆栈跟踪

at org.openqa.selenium.htmlunit.HtmlUnitDriver.assertElementNotStale(HtmlUnitDriver.java:963)
at org.openqa.selenium.htmlunit.HtmlUnitWebElement.assertElementNotStale(HtmlUnitWebElement.java:734)
at org.openqa.selenium.htmlunit.HtmlUnitWebElement.getTagName(HtmlUnitWebElement.java:291)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.openqa.selenium.support.events.EventFiringWebDriver$EventFiringWebElement$1.invoke(EventFiringWebDriver.java:332)
at com.sun.proxy.$Proxy18.getTagName(Unknown Source)
at ch.megloff.test.SimpleExtentReportWebDriverEventListener.afterClickOn(SimpleExtentReportWebDriverEventListener.java:111)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.openqa.selenium.support.events.EventFiringWebDriver$1.invoke(EventFiringWebDriver.java:81)
at com.sun.proxy.$Proxy16.afterClickOn(Unknown Source)
at org.openqa.selenium.support.events.EventFiringWebDriver$EventFiringWebElement.click(EventFiringWebDriver.java:346)
..s

底层HtmlUnit 实现的“getTagName()”的 Java 代码片段

public String getTagName() {
   assertElementNotStale();
   return element.getNodeName();
} 

我对此“afterClickOn”方法的“容易出错”侦听器实现 - 在执行单击后不应调用“getTagName()”

 public class MyWebDriverEventListener extends AbstractWebDriverEventListener {
    ...
    @Override
    public void afterClickOn(WebElement element, WebDriver driver) {
        // bad implementation, click has been already performed 
        // so you may risk to have a stale exception in case the 
        // browser  switched already to the other page (DOM got changed)
        logEvent("Clicked on tag: " + element.getTagName() + " with href: " + element.getAttribute("href"));
    }
 }
于 2017-06-14T17:25:43.783 回答