xpath with following-sibling - selenium

I want to access the table with classname 'table table-hover' that should be under the class=='box-title' that contains the text 'OODR Items for next 20 Days'. Can any one please help me out to get the xpath for this ? I tried with following-sibling but no luck. Thanks in advance.
<?xml version="1.0" encoding="UTF-8"?>
<div id="topTenSellers" class="box box-solid box-primary frontpageWidget">
<div class="box-header">
<i class="fa fa-group" />
<h3 class="box-title">OODR Items for next 20 Days</h3>
<div class="box-tools pull-right">
<button class="btn btn-primary btn-sm" data-widget="collapse">
<i class="fa fa-minus" />
</button>
</div>
</div>
<!-- /.box-header -->
<div class="box-body no-padding">
<table class="table table-hover">
<tbody>
<tr>
<th style="width: 10px">#</th>
<th>Booking</th>
<th>Item Start Date</th>
<th>Site</th>
<th>Supplier</th>
</tr>
<tr>
<td>
<strong>1</strong>
</td>
<td>
(642143)
</td>
<td>21/10/2017 00:00:00</td>
<td>Ski</td>
<td>OODR - Out of Date Range</td>
</tr>
</tbody>
</table>
</div>
<!-- /.box-body -->
</div>

You can try following instead of following-sibling as mentioned h3 and table nodes are not siblings:
//div[#id="topTenSellers"]//h3[#class="box-title" and .="OODR Items for next 20 Days"]/following::table[#class="table table-hover"]

If there is only one element of that class name then either of these will work. One thing to note though, selenium can struggle with spaces in class names depending on the version and browser. If you find that is the case, then use multiple contains to handle the spaces.
//table[contains(#class,'table table-hover')]
//table[#class = 'table table-hover']
If you need that the element as a child of that OODR Items for the next 20 days
//h3[contains(text(),'OODR Items for the next 20 days')]/parent::div/following-sibling::div/table[#class ='table table-hover']
This path uses your anchor point, "OODR Items..", then goes to the parent, then sibling, then to the item with the specified class name. Good luck!

Related

How to locate the parent element of a child element identified through innerText?

I need to select a row in a table where I have a text, hence I would like to leverage the option of selecting a text and then eventually selecting the parent
Now the page looks like:
<tr class=" tableRow1" id="_pu5ufb" dr="1" _awtisprimaryrow="1">
<td width="1" class="tableBody w-tbl-cell" align="center"><span
class="selectColumnMarker">
<div class="w-chk-container">
<input bh="CHKINP" hasaction="false" class="w-chk-native"
id="_m7iynb" value="1" type="checkbox" elementid="_jw4lmb"
issender="false" awnomitcomponent="true" name="_jw4lmb"><label
bh="CHK" class="w-chk w-chk-dsize"></label>
</div>
</span>
</td>
<td align="left" class="tableBody w-tbl-cell">
<span>
<table role="presentation" class="mls" cellpadding="0"
cellspacing="0">
<tbody><tr>
<td class="" id="_tz87e" tabindex="0"><a id="_3iqrbb" href="#"
bh="HL" _sf="true">Analyst</a>
</td>
</tr>
</tbody></table>
</span>
</td><td class="tableBody w-tbl-cell">
</td>
<td class="tableBody w-tbl-cell">
</td>
</tr>
I need to find the text Analyst and then find the associated <tr> class and select the <tr> class.
Any help would be highly appreciable
First, whenever you have mixed content (text and markup) it is better to compare elements' string value than text nodes because inline markup might be splitting the compared text into different text nodes.
Second, you can use:
//tr[td='Analyst']/#class
Note: node-set comparison is an existencial comparison. It means that you are asking if there is some node (some td element in this case) with string value equal to 'Analyst'.
Of course, in HTML there are elements for which white space is not significant for rendering (it's not preserved) despite its presence in the source document. In that case you can use this simple XPath 1.0 expression:
//tr[td[normalize-space()='Analyst']]/#class
Do note: a node-set has a false boolean value if and only if it's empty; you can "nest" predicates (properly, a predicate can be any XPath expression).
I need to find the text Analyst and then find the associated tr class and select the tr class.
XPath 2.01
This XPath,
//tr[td/normalize-space() = "Analyst"]/#class
will select all #class attributes of tr elements containing a td with a space-normalized string value of "Analyst".
Do note, however, that in your sample HTML, such a tr has no #class.
1Thanks for correction, #DebanjanB
Fix your XML file to
<?xml version="1.0"?>
<!DOCTYPE stylesheet [
<!ENTITY nbsp " ">
]>
<root>
<tr class=" tableRow1" id="_pu5ufb" dr="1" _awtisprimaryrow="1">
<td width="1" class="tableBody w-tbl-cell" align="center">
<span class="selectColumnMarker">
<div class="w-chk-container">
<input bh="CHKINP" hasaction="false" class="w-chk-native" id="_m7iynb" value="1" type="checkbox" elementid="_jw4lmb" issender="false" awnomitcomponent="true" name="_jw4lmb"/>
<label bh="CHK" class="w-chk w-chk-dsize"/>
</div>
</span>
</td>
<td align="left" class="tableBody w-tbl-cell">
<span>
<table role="presentation" class="mls" cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td class="" id="_tz87e" tabindex="0">
<a id="_3iqrbb" href="#" bh="HL" _sf="true">Analyst</a>
</td>
</tr>
</tbody>
</table>
</span>
</td>
<td class="tableBody w-tbl-cell">
</td>
<td class="tableBody w-tbl-cell">
</td>
</tr>
</root>
Then, the expression you are looking for is
//tr[td/a/text()='Analyst']/#class
But because the tr element does not have a class attribute, the result is empty.
A bit unclear what exactly you meant by ...find the associated tr class and select the tr class... once you have found ...the text Analyst....
However, as the elements are dynamic element and to locate the element with text as Analyst you can use either of the following Java based Locator Strategies:
linkText
WebElement elem = new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfElementLocated(By.linkText("Analyst")));
cssSelector:
WebElement elem = new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("td.tableBody table.mls a[bh='HL']")))
xpath:
WebElement elem = new WebDriverWait(driver, 20).until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//td[contains(#class, 'tableBody')]//table[#class='mls']//a[text()='Analyst']")));
To extract the class attribute of the <tr> element with respect to the text as Analyst you can use the following Java based solution:
xpath:
String tr_class_attrib = new WebDriverWait(driver, 20).until(ExpectedConditions.elementToBeClickable(By.xpath("//td[contains(#class, 'tableBody')]//table[#class='mls']//a[text()='Analyst']//preceding::tr[1]"))).getAttribute("class");

Does vue.js have something like AngularJS' `ng-repeat-start`

Parsing vue.js' docs I can't see any hint that vue.js has something like a ng-repeat-start / ng-repeat-end
Is there a way to archive something like
<table>
<tr class="weather_warning top" ng-repeat-start="warning in dwd_warnings">
<td {{warning.valid_from}} → {{warning.valid_to}}</td>
<td><div style='background:{{warning.color}};'>{{warning.message}}</div></td>
</tr>
<tr class="weather_warning bottom" ng-repeat-end>
<td colspan="2">
{{warning.description}}<br/>
<span>Issued on the {{warning.effective}} ({{warning.headline}}). {{warning.ascertain}}</span>
</td>
</tr>
</table>
Each warning consists of 2 TRs which go together. One is the top half of the message in the iteration, the other one the lower half. It must be this way, because of some very weird formatting stuff, so there's no way around using 2 TRs for one item. Maybe some tags are off in this example, this is because I had to delete a ton of stuff in order to post it here. Note the colspan="2" in the TD of the second TR, which might give a bit of a hint of the problem which is tackled here.
Closest thing I can think of is to use a <template>, eg
<template v-for="item in items">
<header>
Header {{ item }}
</header>
<div class="body">
Body {{ item }}
</div>
<footer>
Footer {{ item }}
</footer>
</template
See https://v2.vuejs.org/v2/guide/list.html#v-for-on-a-lt-template-gt
... you can also use a <template> tag with v-for to render a block of multiple elements
Nothing changes with your edit, you just wrap your two <tr> elements in
<template v-for="warning in dwd_warnings">
<tr class="weather_warning top">
<!-- etc -->
</tr>
<tr class="weather_warning bottom">
<!-- etc -->
</tr>
</template>

How to extract text between 2 same child tags of a parent tag

Below is the html markup and I want to extract mobile number 7788996655 using xpath:-
<table class="table hover" id="resultTable">
<tbody>
<tr class="odd">
<td class="left">
<img src="/symfony/web/index.php/pim/viewPhoto/gamerNumber/1/from/gameDir" height="200" width="196">
</td>
<td class="left">
<span style="font-weight:bold;">John Player</span>
<br>
<span style="font-weight:bold;">Email: </span>
john.player#yyeett.com,
<span style="font-weight:bold;">
Mobile: </span>7788996655,
<span style="font-weight:bold;">Skype: </span>
game.player,
<br>
<span style="font-weight:bold;">Designation: </span>
Moderator,
<br>
<span style="font-weight:bold;">Game Name: </span>
Counter Strike
<br>
</td>
</tr>
</tbody>
</table>
I tried below xpath, but it didn't worked:
//td/span[contains(.,'Mobile:')]/following-sibling::text()[1]
Can someone provide solution for this?
Workaround I tried is to get whole text within td and then used pattern matching regex to extract mobile number from it. But, now i want to know whether is it possible using xpath?
You can do it using below XPath
<parent td node xpath>/text()[preceding-sibling::span[1][text() = 'Mobile: ']]
Now for an explanation. /td/text() will select each text which is part of the td node but is not part of any other node. So in this case it ,,7788996655,, game.player, moderator.
Now out of these 4 text we want to filter out one which has a previous sibling, which is a span and has text Mobile:, so we can add [preceding-sibling::span[1][text()='Mobile: ']]

vue.js when sorting grid only values is updated, not HTML

I am new to Vue.js, and could really use som help on this one.
I am trying to put a class (success) on my table rows to give them background color depending on the value of a property (status) in each of the objects in Array (data), wich is working as intended using the v-bind:class.
The problem arises when i sort the table rows by clicking on the table headers. When this is done there is a mismatch between the colored rows and their content, as if only values of rows is updated and not the rows themselves.
Try it here : https://jsfiddle.net/Bayzter/cyv1o78s/
Does anyone know how to solve this, so colored rows again match up with the correct objects?
<script type="text/x-template" id="grid-template">
<table>
<thead>
<tr>
<th v-for="key in columns"
#click="sortBy(key)"
:class="{active: sortKey == key}">
{{key | capitalize}}
<span class="arrow"
:class="sortOrders[key] > 0 ? 'asc' : 'dsc'">
</span>
</th>
</tr>
</thead>
<tbody>
<tr v-for="
entry in data
| filterBy filterKey
| orderBy sortKey sortOrders[sortKey]" v-bind:class="{ 'success' : data[$index].status == 0}">
<td v-for="key in columns">
{{entry[key]}}
</td>
</tr>
</tbody>
</table>
</script>
<!-- demo root element -->
<div id="demo">
<form id="search">
Search <input name="query" v-model="searchQuery">
</form>
<demo-grid
:data="gridData"
:columns="gridColumns"
:filter-key="searchQuery">
</demo-grid>
</div>
Where you have
v-bind:class="{ 'success' : data[$index].status == 0}"
You want
v-bind:class="{ 'success' : entry.status == 0}"
$data[$index] is not going to refer to the current-order item, it's going to refer to the original-order item. entry is the current item.

How to click a button in row in a table using protractor js

I am writing protractor test cases. I want to click on edit button. When I am checking by id it is not found.
Code:
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>Code</th>
<th>Start Date</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="batch in batches.list">
<td><a ui-sref="root.courses.detail.batches.assessments({ batch_id: batch.id,assessment_status: 'published'})">BID00{{batch.id}}</a></td>
<td>{{batch.start_date}}</td>
<td>
<button id="edit" type="button" class="btn btn-default btn-sm" tooltip-placement="top" tooltip="Edit" ng-controller="batchesCtrl" ng-click="edit_batch(batch.id)"><i class="glyphicon glyphicon-edit"></i></button>
<button type="button" id="delete(batch.id)" class="btn btn-danger btn-sm" tooltip-placement="top" tooltip="Delete" ng-click="remove_batch(1, batch.id)" confirmation-needed="Do you really want to delete this batch?"><i class="glyphicon glyphicon-trash" ></i></button>
</td>
</tr>
</tbody>
</table>
How can I make it work?
There are a few problems in your example. In html an ID should be unique on a page. So you can't use an id inside an element that repeats.
You have several options. You could address the button by one of it's styleclasses that the other button does no have like
element(by.repeater('batch in batches.list').row(0)).element(by.css('button.btn-default')).click();
You can also just specify you want the first button it finds like
element(by.repeater('batch in batches.list').row(0)).element(by.css('button:first-of-type')).click();
Alternatively you can also address the element with only css. Sometimes that is easier to maintain than the repeater:
element(by.css('tr:first-of-type > td:last-child > button:first-of-type')).click();
Here i am not sending delay so what happen i am checking for the button which is not loaded
ptor.sleep(500); fixes my problem. It took so much time to identify