Selenium, Unable to find element by containing text following child node - selenium

A little bit of background:
The HTML looks like this:
<table>
<thead>
<tr>
<th>Head1</th>
<th>Head2</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<span>
<span class="icon">S</span>
"Auto"
</span>
</td>
<td>
<span>
Cost, Time
</span>
</td>
</tr>
</tbody>
</table>
A simple version of the code looks like this: (run in pry)
[69] pry> e = driver.find_element(:xpath, "//table/tbody/tr/td/span")
=> #<Selenium::WebDriver::Element:0x7ba9a4d694458ec id=":wdc:1361791490676">
[70] pry> e.text
=> "SAutomotive"
[71] pry> e = driver.find_element(:xpath, "//table/tbody/tr/td/span[contains(text(),'Auto')]")
Selenium::WebDriver::Error::NoSuchElementError: The element could not be found
from /Users/ben/.rvm/gems/ruby-1.9.3-p194/gems/selenium-webdriver-2.29.0/lib/selenium/webdriver/remote/response.rb:52:in `assert_ok'
I have no access to changing the HTML code
Although there is only one row in this table there is the possibility of more being added and I cannot predict the location of the row, this is why i am trying to find it by name
my normal code is:
e = driver.find_element(:xpath, "//table/tbody/tr[td/span[contains(text(),'Auto')]]")
The problem I am having is that I cannot find any way of getting the row in the table by the name given in the text of the first table cell.

Use below xpath
"//table/tbody/tr/td/span[contains(.,'Auto')]"

Related

listen for server sent event (SSE) with HTMX and append to a table

I made a simple Go backend that renders an html table (from a SQLite database).
In the same backend i have an /updates endpoint with SSE events when a new row is added to the database.
I want to use htmx to listen for events and then add a row to the table.
What is the right pattern to do this?
I've read https://htmx.org/extensions/server-sent-events/
the example here is to trigger a GET when an event arrives:
<div hx-ext="sse" sse-connect="/updates">
<div hx-get="/table" hx-trigger="sse:rowadded">
...
</div>
</div>
In this way i request the entire table at every update.
How could i add only a single row to the existent rendered table?
You can do this with client side templates.
See https://htmx.org/extensions/client-side-templates/
Example:
<table>
<thead>
<tr>
<th>
Manufacturer
</th>
<th>
Model
</th>
<th>
Power (KW)
</th>
</tr>
</thead>
<tbody id="idTableBody">
<tr id="ModelId_250">
<td>Husqvarna</td>
<td>701 Supermoto</td>
<td>55</td>
</tr>
</tbody>
</table>
In this example mustache is used as templating engine.
<div hx-ext="client-side-templates">
<div hx-ext="sse" sse-connect="/sse-motorbikes">
<div sse-swap="new_bike"
hx-swap="afterbegin"
hx-target="#idTableBody"
mustache-template="idTemplateInsertModel">
</div>
</div>
</div>
Note: EventName is new_bike
Here is the template:
<template id="idTemplateInsertModel">
<tr id="modelId_{{modelId}}">
<td>
{{manufacturer}}
</td>
<td>
{{model}}
</td>
<td>
{{power}}
</td>
</tr>
</template>
With this sse event
type: "new_bike"
data:'{"modelId":208,"manufacturer":"Honda","model":"CRF 1100 L Africa Twin","power":75}'
this row will be inserted into the table body
<tr id="modelId_208">
<td>Honda</td>
<td>CRF 1100 L Africa Twin</td>
<td>75</td>
</tr>
Update
If you want to use a GET request to fetch the new row from the server, you can pass the data sent with the sse event (e.g. an id) to the request.
Check out the answer to this question.
https://stacko...how-to-get-url-for-htmx-get-from-an-sse-event-which-itself-triggers-the-hx-get-c

skrape.it process rows of a table by itself

I am new to the skrape.it library and try to extract content of a table.
Is there a way to process every table by it self, so I get a List with all texts of a row in a List with all rows? e.g.: List<List>
My current approach is to get all texts from every td and count all tr and then process these two lists by calculating the index of the required text.
One row looks like this:
<tr role="row">
<td class="grad" style="background:#067A25; width:50px">
<div class="grad_outer">
<span>4c</span>
</div>
</td>
<td class="name">
King Louie
</td>
<td>
Dave
</td>
<td>
11.03.2022
</td>
<td>
12
</td>
<td>
64.2
</td>
</tr>
I also need to extract the background css attribute of each first td tag. How can I do this?

Selenium XPath multiple selection

I want to find all elements in the table that match the following conditions:
-div text contains '2019';
-div class='excellent';
here is the HTML code excerpt:
<tr>
<td>Name of Person1</td>
<td>
<div class="testDate">21/12/2019</div>
<div class="excellent"></div>
</td>
</tr>
<tr>
<td>Name of Person2</td>
<td>
<div class="testDate">01/12/2017</div>
</td>
</tr>
I tried this solution:
//tr/td[2][div/text()='21/12/2019'][div[#class='starred']]
but I need the year only and not entirely date.
Use the below xpath.
//tr/td[div[contains(.,'2019')]and div[#class='excellent']]
Screenshot:

Webdriver how replace dynamic locator to use Page Factory

Here is html code:
<table>
<tbody>
<tr>
<td>
<a>text1</a>
</td>
<td>
<div>delete<div/>
</td>
</tr>
</tbody>
</table>
<table>
<tbody>
<tr>
<td>
<a>text1</a>
</td>
<td>
<div>delete<div/>
</td>
</tr>
</tbody>
</table>
I need to click on "delete", where contains specified text (for example "text1").
I do this using following xpath:
driver.findElement(By.xpath(".//div/table/tbody/tr/td[text()='" + id + "']/following-sibling::td[3]/div")).click();
But I would like to use Page Factory and avoid using dynamic locator.
So does anyone know how to click on needed element in another way?
If your xPath works why can't you use it in page object?
If you use Java, just do like this:
#FindBy(how = How.xpath, using = "".//div/table/tbody/tr/td[text()='" + id + "']/following-sibling::td[3]/div"")

Unable to find element with css selector

Using Selenium Webdriver for FF/IE using C# (.Net)
Below is my page source and I am trying to use the CssSelector to find/contains the particular name from my page and i have tried with the below code but resulting in error, any help?
//code
driver.FindElement(By.CssSelector("td:contains('John John')"))
//error:
e {"Unable to find element with css selector == td:contains('John John')"} System.Exception {OpenQA.Selenium.NoSuchElementException}
//my html code:
<div id="ctl00_ContentPlaceHolder1_AddeCardControl1_gv_ctl01_RecordCount" style="float:right; padding-right:10px; margin-top:3px;">
<b>308</b> Items Found
</div>
</td>
</tr>
<tr class="item">
<td align="center">Edit</td>
<td align="center" style="width:15px;"></td>
<td>John John</td>
<td> </td>
<td> </td>
<td> </td>
<td><img src="check.png" alt='Active' style='display: ;' /></td>
<td>9/7/2012 11:15:08 PM</td>
</tr>
<tr class="altItem">
<td align="center">Edit</td>
<td align="center" style="width:15px;"></td>
<td>John Schulz</td>
<td> </td>
<td>Visitors</td>
<td> </td>
<td><img src="check.png" alt='Active' style='display: ;' /></td>
<td>9/7/2012 6:28:29 PM</td>
</tr>
<tr class="item">
<td align="center">Edit</td>
<td align="center" style="width:15px;"></td>
<td>Parker Smith</td>
<td> </td>
<td>Visitors</td>
<td> </td>
<td><img src="check.png" alt='Active' style='display: ;' /></td>
<td>9/7/2012 6:01:28 PM</td>
</tr>
<tr class="altItem">
<td align="center">Edit</td>
<td align="center" style="width:15px;"></td>
<td>Test 123</td>
<td> </td>
<td>Visitors</td>
<td> </td>
<td><img src="check.png" alt='Active' style='display: ;' /></td>
<td>9/7/2012 1:36:45 PM</td>
</tr>
<tr class="item">
<td align="center">Edit</td>
<td align="center" style="width:15px;">
The :contains pseudoselector is not part of the W3C CSS Selector standard. As such, browsers do not support selecting elements using it. Some JavaScript CSS selector engines (Sizzle, the engine used by jQuery, for example) provide a :contains pseudoselector, but its presence cannot be relied on.
If you must find an element by the text contents of the element, your only solution at this point is to use XPath. A (very poorly performing) example of how to find this in your case would be as follows:
IWebElement element = driver.FindElement(By.XPath("//td[contains(., 'John John')"));
Note that a better solution will always be to have the application you're automating have proper IDs for the elements you need to find. You should be using text to find elements only as a last resort.
You can try this
var webElements = (Driver.FindElements(By.XPath(elementXpath))).ToList();
webElements.FindIndex(item => item.Text.Contains("John John").Click()
where "elementXpath" is path to each cell in table "names". So you get the list of names and then just find a match. You'll get your item clicked.
You may have better luck using the javascript executor to click the element. I am using a very slow IE9 64bit emulator and it seems the only way to click on certain buttons is to use the javascript executor.
CSS selectors aren't very useful here, because CSS selectors work on the html structure i.e. type, relationship and attributes of web elements; they don't work well on the html content, which in this case is the internal text content 'John John'.
But, xpath will work for this job. The function you need is text() which returns the element's inner text content:
//td[text()='John John']
So your webdriver code should look like this:
driver.FindElement(By.xpath("//td[text()='John John']"));
P.S. All locators verified using Firepath in firefox.
You can use the below code:
driver.FindElement(By.XPath("//td[contains(text(), 'John John')"));