0
<div id="crm" class="row gridrow clickable ng-scope" ng-repeat="customer in customerList" ng-click="gotoRecord(customer.id)">
     <i class="col m1 s1 tiny fa fa-male"></i>
     <div class="col m3 s11 ng-binding"> Allard</div>
     <div class="col m2 s12 ng-binding"></div>
</div>

我有这个 HTML 片段,它是作为对名为“Allard”的客户的搜索操作的结果显示的一行。我想单击此客户以继续到下一页,但大多数情况下这会导致 StaleElementException。

我尝试了两种不同的方式,使用量角器和不使用量角器。

第一种方式:

IWebElement elem = driver.FindElement(By.XPath("//*[contains(text(),'" + nameCustomer + "')]//parent::div[contains(@id,'crm')]"));
        ExplicitWait.WaitAndClick(driver, elem);

第二种方式:

var customers = driver.FindElements(NgBy.Repeater("customer in customerList"));
        foreach (var customer in customers)
        {
            if (elem.Text.Equals(nameCustomer))
            {
                elem.Click();
            }
        }
4

1 回答 1

1

问题(我认为)

使用 StaleReferenceExceptions,之前创建的 IWebElement 不再附加到 DOM(您可能已经知道这一点)。最有可能发生的是:
1:您点击搜索。
2:Selenium 执行driver.FindElement(...)并找到匹配的元素。
3:然后搜索功能完成并且DOM更新。之前找到的旧 IWebElement 已消失。
4:然后Selenium 尝试单击元素(不再存在,导致 StaleElementException。有一个元素与之前存在的元素匹配,但在 Selenium 眼中它不是同一个元素。)

Your statement that this happens "most of the time" makes me suspect this is the case even more, because the exception would depend on the order of events, which would vary depending on the relative speeds of Selenium vs. the web-page.

How to resolve (if this is your problem)

You need to find something on the page that will indicate to Selenium that the search action is done. This is where the creativity of writing GUI automation scripts comes in. If there is something on the page that you know will change as a result of the load, craft an explicit wait to ensure that is complete. Maybe there is a loading bar that shows up, or a message that appears when the search is done. You could grab an element that doesn't match your search before clicking search, then do an explicit wait to make sure it disappears before going on to look for the result you do expect to be there.

It would look something like this below.

# Search action performed before this.
WebDriverWait wait= new WebDriverWait(driver, TimeSpan.FromSeconds(secondsToWait));
wait.Until(ExpectedConditions.InvisibilityOfElementLocated(By.XPath( expressionForElementThatWillDissapear )));


IWebElement elem = driver.FindElement(By.XPath("//*[contains(text(),'" + nameCustomer + "')]//parent::div[contains(@id,'crm')]"));
            ExplicitWait.WaitAndClick(driver, elem);

I'd recommend making the method to implement the explicit wait above. These situations will come up often.

于 2017-06-06T03:51:51.057 回答