#selenium #xpath
#selenium #xpath
Вопрос:
У меня есть автоматический тест Selenium, который использует следующий XPath
"//tr[td/strong='Riparian 2m Ungrazed - RBS' and td/button[@id='btnDeleteOption_WG']]"
В настоящее время, всякий раз, когда я запрашиваю этот XPath, он возвращает нужный мне элемент, но также возвращает другой скрытый элемент, которого нет на экране.
Я сравнил два элемента, и единственное различие заключается в следующем
offsetHeight: 39 offsetHeight: 0
offsetLeft: 8 offsetLeft: 0
offsetParent: td offsetParent: null
offsetTop: 10 offsetTop: 0
offsetWidth: 179 offsetWidth: 0
Мне нужно найти элемент слева с параметром offsetParent <td>
.
Кто-нибудь может помочь с XPath, чтобы найти это?
Спасибо!
Ниже приведен HTML-код элемента:
<td class="text-center" style="white-space: nowrap;">
<button id="btnShowItems_WG" class="btn btn-sm btn-primary" ng-disabled="!WG_field.optionHasItems" ng-click="WG_field.optionHasItems ? items.visible = !items.visible : false;" title="View Items" disabled="disabled">
<span class="glyphicon glyphicon-list"></span>
</button>
<button ng-hide="!efsEditRole_RoleAssignedToUser" ng-disabled="false" id="btnAddOptionItem_16_WG" class="btn btn-primary btn-sm" ng-click="appSummaryVm.addItem($index, 'WG'); appSummaryVm.addItemsByOption(WG_field.fieldId, WG_field.tranche, WG_field.optionCode, WG_field.optionTypeId, $index, 'WG');"
title="Add Item" aria-hidden="false">
<span class="glyphicon glyphicon-plus"></span>
</button>
</td>
<td><strong>Riparian 2m Ungrazed - RBS</strong></td>
<td style="width: 10%;">
<input name="optionQuantityWG_16" type="number" class="form-control ng-pristine ng-untouched ng-valid ng-not-empty ng-valid-min ng-valid-max ng-valid-required ng-valid-pattern" ng-class="{
'form-control input-error' : (existingOptionsWG.optionQuantityWG_16.$dirty amp;amp;amp;amp; (
existingOptionsWG.optionQuantityWG_16.$error.max
|| existingOptionsWG.optionQuantityWG_16.$error.min
|| existingOptionsWG.optionQuantityWG_16.$error.pattern
|| existingOptionsWG.optionQuantityWG_16.$invalid
|| existingOptionsWG.optionQuantityWG_16.$error.required
))
}" ng-change="appSummaryVm.updateOptionTotals(WG_field, 'WG'); appSummaryVm.edit();" ng-model="WG_field.optionQuantity" ng-pattern="/^d (.d{1,2})?$/" min="" max="" step="0.01" style="text-align: right;" ng-true-value="10.00"
required="" id="optionWGW0316" ng-disabled="!efsEditRole_RoleAssignedToUser" aria-invalid="false">
<div class="form-control inline-errorUp ng-hide" ng-show="existingOptionsWG.optionQuantityWG_16.$dirty amp;amp;amp;amp; (
existingOptionsWG.optionQuantityWG_16.$error.max
|| existingOptionsWG.optionQuantityWG_16.$error.min
|| existingOptionsWG.optionQuantityWG_16.$error.pattern
|| existingOptionsWG.optionQuantityWG_16.$error.required
|| existingOptionsWG.optionQuantityWG_16.$invalid
)" aria-hidden="true">
<span ng-show="existingOptionsWG.optionQuantityWG_16.$dirty amp;amp;amp;amp; existingOptionsWG.optionQuantityWG_16.$error.max" aria-hidden="true" class="ng-hide">
maximum of 999999999.99
</span>
<span ng-show="existingOptionsWG.optionQuantityWG_16.$dirty amp;amp;amp;amp; existingOptionsWG.optionQuantityWG_16.$error.min" aria-hidden="true" class="ng-hide">
cannot be zero or less
</span>
<span ng-show="existingOptionsWG.optionQuantityWG_16.$dirty amp;amp;amp;amp; (existingOptionsWG.optionQuantityWG_16.$error.pattern || existingOptionsWG.optionQuantityWG_16.$invalid)" ng-hide="existingOptionsWG.optionQuantityWG_16.$error.max || existingOptionsWG.optionQuantityWG_16.$error.min || existingOptionsWG.optionQuantityWG_16.$error.required"
aria-hidden="false" class="">
2 decimal digits only
</span>
<span ng-show="existingOptionsWG.optionQuantityWG_16.$dirty amp;amp;amp;amp; existingOptionsWG.optionQuantityWG_16.$error.required" aria-hidden="true" class="ng-hide">
required
</span>
</div>
</td>
<td class="text-right">6.00
<!----><span ng-if="WG_field.optionUnitType">/</span>
<!---->m</td>
<td class="text-right">60.00</td>
<td class="text-right">0.70</td>
<td class="text-right">96.00</td>
<td class="text-center">
<button ng-hide="!efsEditRole_RoleAssignedToUser" ng-disabled="false" id="btnDeleteOption_WG" class="btn btn-warning btn-sm" style="width: 110px;" ng-click="appSummaryVm.showRemovePrompt(WG_field, 'option', 'WG', $event); appSummaryVm.edit();" title="Delete 'Riparian 2m Ungrazed' Option from field 3/003/003/3"
aria-hidden="false">
<span class="glyphicon glyphicon-trash"></span> remove option
</button>
</td>
Комментарии:
1. можете ли вы предоставить общий доступ к html?
2. Без соответствующего HTML я не уверен, как вы ожидаете, что мы создадим новый локатор и решим эту проблему.
3. прошу прощения, я добавил соответствующий HTML
4. Ну, перво-наперво, идентификаторы должны быть уникальными в HTML-документе. Основываясь на вышесказанном, вы могли бы просто использовать
"//button[@id='btnDeleteOption_WG']"
, потому что это единственный идентификатор в этом фрагменте кода. Если идентификаторы не уникальны, это ошибка, которую вы должны заставить своих разработчиков исправить.
Ответ №1:
Вы можете получить все элементы и отфильтровать их по видимости. Ниже приведен пример кода Java, как получить первый видимый элемент из списка веб-элементов.
С Java 8:
List<WebElement> elements = driver.findElements(By.xpath("//tr[td/strong='Riparian 2m Ungrazed - RBS' and td/button[@id='btnDeleteOption_WG']]"));
WebElement element = elements
.stream()
.filter(WebElement::isDisplayed)
.collect(Collectors.toList())
.get(0);
Python:
elements = driver.find_elements_by_xpath("//tr[td/strong='Riparian 2m Ungrazed - RBS' and td/button[@id='btnDeleteOption_WG']]")
visible_one = list(filter(lambda x: x.is_displayed(), elements))[0]
visible_one.click()