单击 Angular 网页中的 TableRow 时发生 StaleElementException
StaleElementException when Clicking on a TableRow in an Angular WebPage
<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 的这个片段,它是对名称为 Customer 'Allard' 的客户的搜索操作结果显示的一行。我想单击此客户以继续到下一页,但大多数情况下这会导致 StaleElementException。
我尝试了两种不同的方法,使用 Protractor 和不使用 Protractor。
第一种方式:
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();
}
}
问题(我认为)
使用 StaleReferenceExceptions,以前创建的 IWebElement 不再附加到 DOM(您可能已经知道这一点)。最有可能发生的是:
1:您点击搜索。
2:Selenium执行driver.FindElement(...)
,找到匹配元素
3: 然后 搜索功能完成,DOM 更新。之前找到的旧 IWebElement 不见了。
4: Then Selenium 尝试点击元素(不再存在,导致 StaleElementException。有一个元素 匹配 那个元素之前有过,但在 Selenium 眼中它不是同一个元素。)
你说这种情况“大部分时间”发生让我更加怀疑这种情况,因为例外情况取决于事件的顺序,这会有所不同取决于 Selenium 与网页的相对速度。
如何解决(如果这是你的问题)
您需要在页面上找到一些内容,以向 Selenium 指示搜索操作已完成。这就是编写 GUI 自动化脚本的创造力所在。如果您知道页面上的某些内容会因加载而发生变化,请设计一个明确的等待以确保完成。可能会显示一个加载栏,或者在搜索完成时出现一条消息。您可以在单击搜索之前抓取一个与您的搜索不匹配的元素,然后进行明确的等待以确保它消失,然后再继续寻找您的结果做期待在那里。
它看起来像下面这样。
# 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);
我建议制作方法来实现上面的显式等待。这些情况会经常出现。
<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 的这个片段,它是对名称为 Customer 'Allard' 的客户的搜索操作结果显示的一行。我想单击此客户以继续到下一页,但大多数情况下这会导致 StaleElementException。
我尝试了两种不同的方法,使用 Protractor 和不使用 Protractor。
第一种方式:
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();
}
}
问题(我认为)
使用 StaleReferenceExceptions,以前创建的 IWebElement 不再附加到 DOM(您可能已经知道这一点)。最有可能发生的是:
1:您点击搜索。
2:Selenium执行driver.FindElement(...)
,找到匹配元素
3: 然后 搜索功能完成,DOM 更新。之前找到的旧 IWebElement 不见了。
4: Then Selenium 尝试点击元素(不再存在,导致 StaleElementException。有一个元素 匹配 那个元素之前有过,但在 Selenium 眼中它不是同一个元素。)
你说这种情况“大部分时间”发生让我更加怀疑这种情况,因为例外情况取决于事件的顺序,这会有所不同取决于 Selenium 与网页的相对速度。
如何解决(如果这是你的问题)
您需要在页面上找到一些内容,以向 Selenium 指示搜索操作已完成。这就是编写 GUI 自动化脚本的创造力所在。如果您知道页面上的某些内容会因加载而发生变化,请设计一个明确的等待以确保完成。可能会显示一个加载栏,或者在搜索完成时出现一条消息。您可以在单击搜索之前抓取一个与您的搜索不匹配的元素,然后进行明确的等待以确保它消失,然后再继续寻找您的结果做期待在那里。
它看起来像下面这样。
# 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);
我建议制作方法来实现上面的显式等待。这些情况会经常出现。