You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure Pipeline中测试偶发StaleElementReferenceException问题求助

StaleElementReferenceException问题分析与调试方案

我在Azure Pipeline中运行的测试有大约一半概率抛出StaleElementReferenceException,但本地(无头/非无头模式)运行全部通过。奇怪的是,报错的方法在其他多个测试中调用却没有问题。以下是调用栈和相关代码,请帮忙分析问题并给出调试建议。

调用栈

at OpenQA.Selenium.WebDriver.UnpackAndThrowOnError(Response errorResponse, String commandToExecute)
   at OpenQA.Selenium.WebDriver.Execute(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebDriver.InternalExecute(String driverCommandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebElement.Execute(String commandToExecute, Dictionary`2 parameters)
   at OpenQA.Selenium.WebElement.get_Displayed()
   at SeleniumExtras.WaitHelpers.ExpectedConditions.<>c__DisplayClass6_0.<ElementToBeClickable>b__0(IWebDriver driver)
   at OpenQA.Selenium.Support.UI.DefaultWait`1.Until[TResult](Func`2 condition, CancellationToken token)
   at OpenQA.Selenium.Support.UI.DefaultWait`1.Until[TResult](Func`2 condition)
   at GembaCloud.Tests.Pages.BasePage.BasePageActions.WaitForElementToBeClickable(By element) in C:\agent\_work\53\s\GembaCloud.Tests\Pages\BasePage.cs:line 205
   at GembaCloud.Tests.Pages.BasePage.BasePageActions.GetTable(By byTable, Int32 firstDataRowIndex) in C:\agent\_work\53\s\GembaCloud.Tests\Pages\BasePage.cs:line 259
   at GembaCloud.Tests.Pages.GembaIntelligencePage.GembaIntelligencePageActions.GetGembaIntelligenceTable() in C:\agent\_work\53\s\GembaCloud.Tests\Pages\Home\GembaIntelligencePage.cs:line 52
   at GembaCloud.Tests.Pages.GembaIntelligencePage.GembaIntelligencePageActions.ExpandGembaIntelligenceTableRow(Int32 rowNumber) in C:\agent\_work\53\s\GembaCloud.Tests\Pages\Home\GembaIntelligencePage.cs:line 79
   at GembaCloud.Tests.TestClasses.UserRolePageElementAuthorisationTests.reporting_user_should_not_have_access_to_intelligence_dropdown_create_action_button() in C:\agent\_work\53\s\GembaCloud.Tests\TestClasses\UserRolePageElementAuthorisationTests.cs:line 115

相关代码

GembaIntelligencePage类

public void ExpandGembaIntelligenceTableRow(int rowNumber)
{
    this.ExpandTableRow(this.GetGembaIntelligenceTable(), rowNumber);
}

public IList<IWebElement> GetGembaIntelligenceTable()
{
    return this.GetTable(_elements.byGembaIntelligenceTable, 1);
}

BasePage类

protected IList<IWebElement> GetTable(By byTable, int firstDataRowIndex)
{
    //firstDataRowIndex is so we only return the table rows that we need
    this.WaitForElementToBeClickable(byTable);
    IWebElement table = _driver.FindElement(byTable);

    IList<IWebElement> listOfDataTableRows = table.FindElements(By.CssSelector("tr")).Skip(firstDataRowIndex -1).ToList();

    return listOfDataTableRows;
}

protected void WaitForElementToBeClickable(By element)
{
    WebDriverWait wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(10));
    wait.Until(ExpectedConditions.ElementToBeClickable(element));
}

代码问题分析

  1. 等待条件未处理StaleElementReferenceException
    调用栈显示错误发生在WaitForElementToBeClickable方法中,具体是ExpectedConditions.ElementToBeClickable内部检查元素Displayed属性时抛出异常。WebDriverWait默认仅忽略NotFoundException,但当页面异步更新导致元素被重新渲染时,之前找到的元素会变为stale,此时get_Displayed()会直接抛出StaleElementReferenceException,而等待逻辑不会重试查找。

  2. 重复查找元素存在时间窗口风险
    GetTable方法中,先调用WaitForElementToBeClickable等待元素可点击,之后再调用FindElement重新查找元素。两次查找之间如果页面发生更新(比如AJAX请求完成),新查找的元素可能已经处于stale状态,或者等待的元素和后续查找的元素不是同一个实例。

  3. 返回缓存的元素列表易引发后续问题
    返回的IList<IWebElement>是直接从table中获取的行元素缓存,若后续页面有更新,这些元素会立即变stale,不过当前报错发生在获取table阶段,所以优先解决前两个问题。

调试与修复建议

  • 修改等待方法,添加异常忽略
    更新WaitForElementToBeClickable,让等待逻辑在遇到StaleElementReferenceException时重试查找,同时直接返回等待到的元素避免重复查找:

    protected IWebElement WaitForElementToBeClickable(By element)
    {
        WebDriverWait wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(10));
        wait.IgnoreExceptionTypes(typeof(StaleElementReferenceException), typeof(NotFoundException));
        return wait.Until(ExpectedConditions.ElementToBeClickable(element));
    }
    
    protected IList<IWebElement> GetTable(By byTable, int firstDataRowIndex)
    {
        IWebElement table = this.WaitForElementToBeClickable(byTable);
        IList<IWebElement> listOfDataTableRows = table.FindElements(By.CssSelector("tr")).Skip(firstDataRowIndex -1).ToList();
        return listOfDataTableRows;
    }
    
  • 增加页面稳定性等待
    在查找table前,添加针对页面异步加载的等待,比如等待页面加载完成:

    WebDriverWait wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(10));
    wait.Until(driver => ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").ToString() == "complete");
    
  • 排查环境差异
    检查Azure Pipeline中的浏览器版本、Selenium驱动版本是否与本地一致;测试环境网络延迟可能更高,可适当延长等待时间(如从10秒调整为15秒)。

  • 添加调试日志与截图
    在Azure Pipeline中配置测试日志,记录元素查找时间、页面状态;在异常发生时自动截图,帮助定位具体场景下的页面变化。

内容的提问来源于stack exchange,提问作者Keiggo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 09:45:43