使用EventFiringWebDriver

时间:2017-06-14 16:49:30

标签: java selenium selenium-webdriver htmlunit-driver stalestateexception

亲爱的所有我使用Selenium EventFiringWebDriver来记录被调用的Web驱动程序方法。我认识到我经常得到一个" StaleReferenceException"而当我只使用HtmlUnitDriver时,我没有问题。

我也认出了这个电话,即" click()"已经在浏览器中执行了#34; StaleElementReferenceException"被扔了。

当使用HtmlUnitDriver或FirefoxDriver独立时,EventFiringWebDriver遇到此类问题时是否有任何想法? 可能是在运行时由原始驱动程序更新WebElements而EventFiringWebDriver的wrapped 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(); 
        }

1 个答案:

答案 0 :(得分:0)

在研究过时异常的堆栈跟踪后,我发现问题不是直接来自EventFiringWebDriver。当我尝试在执行单击后获取元素的标记名称时,它会被WebDriverEventListener的侦听器实现抛出。

对我来说,WebDriverEventListener的设计看起来不是最佳的。换句话说,您可能无法在" afterXXX"中使用传递的WebElement。方法,否则你可能会冒失败的例外。相反,你应该使用" beforeXXX"方法,以检索元素的细节。

我的StaleElementReferenceException的Stacktrace

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

" getTagName()"的Java代码片段基础HtmlUnit Implementation

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

My"容易出错"这个" 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"));
    }
 }