I have an automated Selenium test which uses the following XPath
"//tr[td/strong='Riparian 2m Ungrazed - RBS' and td/button[#id='btnDeleteOption_WG']]"
Currently, whenever I query this XPath it returns the element I need but also returns another hidden element which is not on screen.
I have compared the two elements and the only difference is the following
offsetHeight: 39 offsetHeight: 0
offsetLeft: 8 offsetLeft: 0
offsetParent: td offsetParent: null
offsetTop: 10 offsetTop: 0
offsetWidth: 179 offsetWidth: 0
I need to find the element on the left with the offsetParent of <td>.
Can anybody help with an XPath to find this?
Thanks!
Below is the HTML of the element:
<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 && (
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 && (
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 && existingOptionsWG.optionQuantityWG_16.$error.max" aria-hidden="true" class="ng-hide">
maximum of 999999999.99
</span>
<span ng-show="existingOptionsWG.optionQuantityWG_16.$dirty && existingOptionsWG.optionQuantityWG_16.$error.min" aria-hidden="true" class="ng-hide">
cannot be zero or less
</span>
<span ng-show="existingOptionsWG.optionQuantityWG_16.$dirty && (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 && 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>
You can get all elements and them filter by visibility. Below is a Java code example, how to get first visible element from list of web elements.
With 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()
Related
I have a drop down in WordPress products page which is a select2 ajax enabled.
I have managed to show the options in the drop down using selenium.
But i am not able to select one of the options from the list.
I am able to get the element using the below code. But the element is not castable to Select nor clickable.
driver.findElement(By.cssSelector("[class='multiselect attribute_values wc-enhanced-select select2-hidden-accessible enhanced']"))
Any ideas how to select any option from it?
The HTML code for the drop down is
<tr>
<td class="attribute_name">
<label>Name:</label>
<strong>Brand</strong>
<input type="hidden" name="attribute_names[0]" value="pa_brand">
<input type="hidden" name="attribute_position[0]" class="attribute_position" value="0">
</td>
<td rowspan="3">
<label>Value(s):</label>
<select multiple="" data-placeholder="Select terms" class="multiselect attribute_values wc-enhanced-select select2-hidden-accessible enhanced" name="attribute_values[0][]" tabindex="-1" aria-hidden="true">
<option value="107">Adidas</option>
<option value="110">Gul Ahmed</option>
<option value="111">Khadi</option>
</select>
<span class="select2 select2-container select2-container--default select2-container--above select2-container--open" dir="ltr" style="width: auto;">
<span class="selection">
<span class="select2-selection select2-selection--multiple" aria-haspopup="true" aria-expanded="true" tabindex="-1" aria-owns="select2-attribute_values0-to-results" aria-activedescendant="select2-attribute_values0-to-result-d16b-111">
<ul class="select2-selection__rendered" aria-live="polite" aria-relevant="additions removals" aria-atomic="true">
<li class="select2-search select2-search--inline"><input class="select2-search__field" type="text" tabindex="0" autocomplete="off" autocorrect="off" autocapitalize="none" spellcheck="false" role="textbox" aria-autocomplete="list" placeholder="Select terms" style="width: 418.797px;" aria-owns="select2-attribute_values0-to-results" aria-activedescendant="select2-attribute_values0-to-result-d16b-111"></li>
</ul>
</span>
</span>
<span class="dropdown-wrapper" aria-hidden="true"></span>
</span>
<button class="button plus select_all_attributes">Select all</button>
<button class="button minus select_no_attributes">Select none</button>
<button class="button fr plus add_new_attribute">Add new</button>
</td>
</tr>
As per the HTML:
<select multiple="" data-placeholder="Select terms" class="multiselect attribute_values wc-enhanced-select select2-hidden-accessible enhanced" name="attribute_values[0][]" tabindex="-1" aria-hidden="true">
The WebElement is clearly a <select> node and to select one of the options from the html-select tag you need to induce WebDriverWait for the elementToBeClickable() and you can use either of the following locator strategies:
Using cssSelector and selectByVisibleText():
new Select(new WebDriverWait(driver, Duration.ofSeconds(10)).until(ExpectedConditions.elementToBeClickable(By.cssSelector("select.multiselect.attribute_values.wc-enhanced-select.select2-hidden-accessible.enhanced[data-placeholder='Select terms']")))).selectByVisibleText("Adidas");
Using xpath and selectByValue():
new Select(new WebDriverWait(driver, Duration.ofSeconds(10)).until(ExpectedConditions.elementToBeClickable(By.xpath("//select[#class='multiselect attribute_values wc-enhanced-select select2-hidden-accessible enhanced' and #data-placeholder='Select terms']")))).selectByValue("110");
In the UI I'm working with, for an object there there is a pencil or a basket icon; I want to click the pencil one (which will trigger an edit modal), and want to do it for the specific object.
For now I use this command line:
Click Element xpath = (//a[#ng-click="openCreateEditModal (holding)"])[2]
I would like to replace the "2" by the value of the line corresponding to the value "RF-Account".
Here is a sample of the HTML:
<tbody ng-if="!isEmpty" class="body-table ng-scope" style="height: 165px;">
<!-- ngRepeat: tenant in tenants track by $index --><tr ng-repeat="tenant in tenants track by $index" class="ng-scope" style="">
<td class="ng-binding">RF-Accou</td>
<td>
<span class="text-bold ng-binding text-muted" ng-class="{'text-green' : tenant.status == 'ACTIVE', 'text-muted' : tenant.status == 'INACTIVE'}">INACTIVE</span>
</td>
<td style="width:118px">
<div class="pull-right">
<a name="editBtn" type="submit" class="btn-icon" ng-click="openCreateEditModal(tenant)">
<span class="icon-i-edit fs" data-toggle="tooltip" title=""></span>
</a>
<a name="deleteBtn" type="submit" class="btn-icon" ng-click="deleteTenant(tenant)">
<span class="icon-i-trash fs" data-toggle="tooltip" title=""></span>
</a>
</div>
</td>
</tr><!-- end ngRepeat: tenant in tenants track by $index --><tr ng-repeat="tenant in tenants track by $index" class="ng-scope">
**<td class="ng-binding">RF-Account</td>**
<td>
<span class="text-bold ng-binding text-muted" ng-class="{'text-green' : tenant.status == 'ACTIVE', 'text-muted' : tenant.status == 'INACTIVE'}">INACTIVE</span>
</td>
<td style="width:118px">
<div class="pull-right">
<a name="editBtn" type="submit" class="btn-icon" ng-click="openCreateEditModal(tenant)">
<span class="icon-i-edit fs" data-toggle="tooltip" title=""></span>
</a>
<a name="deleteBtn" type="submit" class="btn-icon" ng-click="deleteTenant(tenant)">
<span class="icon-i-trash fs" data-toggle="tooltip" title=""></span>
</a>
</div>
</td>
</tr><!-- end ngRepeat: tenant in tenants track by $index --><tr ng-repeat="tenant in tenants track by $index" class="ng-scope">
<td class="ng-binding">RF-Accountfirst</td>
<td>
<span class="text-bold ng-binding text-muted" ng-class="{'text-green' : tenant.status == 'ACTIVE', 'text-muted' : tenant.status == 'INACTIVE'}">INACTIVE</span>
</td>
<td style="width:118px">
<div class="pull-right">
<a name="editBtn" type="submit" class="btn-icon" ng-click="openCreateEditModal(tenant)">
<span class="icon-i-edit fs" data-toggle="tooltip" title=""></span>
</a>
<a name="deleteBtn" type="submit" class="btn-icon" ng-click="deleteTenant(tenant)">
<span class="icon-i-trash fs" data-toggle="tooltip" title=""></span>
</a>
</div>
</td>
</tr><!-- end ngRepeat: tenant in tenants track by $index -->
</tbody>
I am trying to find the line that corresponds to the text value "RF-Account".
For your information, the line of "RF-Account" can change.
Could you please help me find the right keyword to use for Robot Framework ?
To rephrase your question - you need a locator that'll get you that, not a robotframework keyword (the keyword is known, Click Element).
If your anchor is the text, then this xpath will do it for you:
//td[text()="RF-Account"]/following-sibling::td//a[#ng-click="openCreateEditModal(tenant)"]
Let me explain: the first part (//td[text()="RF-Account"]) will select a td element which text is "RF-Account". Then it will look for a follow-up td (the "following-sibling axis), that has an a child with that value for ng-click - and return it (the a).
BTW, in the sample source there is no "openCreateEditModal(holding)", thus I've changed it with "tenant", which is present.
For getting count you can use
Get Matching XPath Count //td[.="RF-Account"]
I have an array which i iterate with ngFor in the view as shown below.
I want to hide the button if all elements of y.errortyp are nottested.
How can i achieve this functionality? I tried some combinations of ngIf, but can not find a solution.
<...>
<tr *ngFor="let x of x">
<td> x.name</td>
<td *ngFor="let y of x.results">
<div *ngIf="y.errortyp == 'Error1'" class="red"></div>
<div *ngIf="y.errortyp == 'nottested'" class="grey"></div>
</td>
<td>
<button type="button" class="btn btn-default btn-lg btn-block" aria-label="Left Align"
(click)="download(x)">
Download
</button>
</td>
<...>
I have the following HTML:
<table class="w98">
<tbody>
<tr>
<tr>
<tr>
<td class="p-controlSetLabel">
<td class="editor-field">
**<span class="k-widget k-dropdown k-header" style="width: 165px;" title="" unselectable="on" role="listbox" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-owns="VatRateId_listbox" aria-disabled="false" aria-readonly="false" aria-busy="false" aria-activedescendant="304dd433-4a68-458b-a6d6-03b72335f1cb">**
<span class="k-dropdown-wrap k-state-default" unselectable="on">
<span class="k-input" unselectable="on">Standard - Standard</span>
<span class="k-select" unselectable="on">
<span class="k-icon k-i-arrow-s" unselectable="on">select</span>
</span>
</span>
<input id="VatRateId" class="k-valid" type="text" value="d20b" style="width: 165px; display: none;" name="VatRateId" data-val-required="Please select a VAT Rate." data-val="true" data-role="dropdownlist">
The input id="VatRateId" is hidden, so I can't access it.
My current solution is the following:
var allDropDownFields = FindElements(By.XPath(".//*[#class='k-dropdown-wrap k-state-default']") -- This will return a list of all drop down fields
Then I loop each one of them to find the correct drop down field I want.
Is there a better way of finding the element without getting a list, I tried the following:
FindElement(By.XPath(".//*[#class='k-dropdown-wrap k-state-default'and #aria-owns = 'VatRateId_listbox']")
and the above code is not work.
HTML code is as below:-
<span class="k-widget k-dropdown k-header" style="width: 165px;" title="" unselectable="on" role="listbox" aria-haspopup="true" aria-expanded="false" tabindex="0" aria-owns="VatRateId_listbox" aria-disabled="false" aria-readonly="false" aria-busy="false" aria-activedescendant="304dd433-4a68-458b-a6d6-03b72335f1cb">* <span class="k-dropdown-wrap k-state-default" unselectable="on"> <span class="k-input" unselectable="on">Standard - Standard</span>
Any better suggestion?
Is there a way to click further inside siblings in Selenium Webdriver? For example, here's the HTML:
<tr class="rich-table-row xx-datalist-even" onmouseover="Element.addClassName(this, 'xx-datalist-mouseover')" onmouseout="Element.removeClassName(this, 'xx-datalist-mouseover')">
<td class="rich-table-cell xx-datalist " id="userTableForm01:usersTableData:264:j_id102" style="text-align:center; width:20px;">
<img src="/static/images/graphics/status1.gif" title="Disabled" />
</td>
<td id="userTableForm01:usersTableData:264:col1" class="rich-table-cell xx-datalist">
<span id="userTableForm01:usersTableData:264:author_id">2377</span>
</td>
<td id="userTableForm01:usersTableData:264:col2" class="rich-table-cell xx-datalist">seleniumtest2312</td>
<td id="userTableForm01:usersTableData:264:col3" class="rich-table-cell xx-datalist">
<span style="margin-right:3px">Test2312</span>
Selenium
</td>
<td class="rich-table-cell xx-datalist " id="userTableForm01:usersTableData:264:col4" style="text-align:center;">
<input type="checkbox" name="userTableForm01:usersTableData:264:j_id111" onclick="A4J.AJAX.Submit('userTableForm01',event,{'similarityGroupingId':'userTableForm01:usersTableData:264:j_id112','parameters':{'userTableForm01:usersTableData:264:j_id112':'userTableForm01:usersTableData:264:j_id112'} } )" />
</td>
<td id="userTableForm01:usersTableData:264:col6" class="rich-table-cell xx-datalist">
<a id="userTableForm01:usersTableData:264:enable_link" href="#" style="margin-right:5px" onclick="if(typeof jsfcljs == 'function'){jsfcljs(document.getElementById('userTableForm01'),{'userTableForm01:usersTableData:264:enable_link':'userTableForm01:usersTableData:264:enable_link'},'');}return false">
<span id="userTableForm01:usersTableData:264:enable_link_text" class="xx-datalist">Enable</span>
</a>
<a id="userTableForm01:usersTableData:264:edit_link" href="#" style="margin-right:5px" onclick="if(typeof jsfcljs == 'function'){jsfcljs(document.getElementById('userTableForm01'),{'userTableForm01:usersTableData:264:edit_link':'userTableForm01:usersTableData:264:edit_link'},'');}return false">
<span id="userTableForm01:usersTableData:264:edit_link_text" class="xx-datalist">Edit</span>
</a>
<a id="userTableForm01:usersTableData:264:remove_link" href="#" onclick="if(typeof jsfcljs == 'function'){jsfcljs(document.getElementById('userTableForm01'),{'userTableForm01:usersTableData:264:remove_link':'userTableForm01:usersTableData:264:remove_link'},'');}return false">
<span id="userTableForm01:usersTableData:264:remove_link_text" class="xx-datalist">Delete</span>
</a>
</td>
</tr>
Now, this is a much bigger table than shown, so there are a lot more tr's with more users. The ID's are all auto-generated and different each time, and I am trying to click the 'Enable'-link, though the only thing unique on the same row that I can use is the username seleniumtest2312, which has brought me to this:
driver.findElement(By.xpath("//td[text()='seleniumtest2312']/following-sibling::td[3]/span[text()='Enable']")).click();
But it just won't work (no such element).
If there are better ways of solving this issue I'll be happy to try them.
The last part of your XPath is a bit off :
following-sibling::td[3]/span[text()='Enable']
because <span> you're looking for isn't direct child of <td>. You can try this XPath instead :
//td[.='seleniumtest2312']/following-sibling::td[3]/a/span[.='Enable']