Finding a specific row in a table using capybara - html

I have a users table that list out the users' ID, name, email and username. What I am attempting to do is verify that a specific entry is in that table.
So essentially what I would like to do is find the row that has ID = 22, then verify that name = John Smith, email = john#smith.com and username = jsmith. The able is setup as show below. What I don't understand is a couple of things...
How do I get a row with specific text, I.E. that as user.id = 22.
Once I have that row, how do I use it get each of the elements.
I thought I could do a sort of for loop but can't figure out how to set the has_selector? condition. (below is pseudocode)
page.all('tr').each do |tr|
next unless tr.has_selector?('td.id = 22') #psuedocode
expect(tr.get('td.name').to eq("John Smith")
#other expects here...
end
Table code
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Username</th>
</tr>
</thead>
<tbody>
<% #users.each do |user| %>
<tr>
<td class="id"><%= user.id %></td>
<td class="name"><%= link_to user.name, user %></td>
<td class="email"><%= user.base_name %></td>
<td class="username"><%= user.username %></td>
</tr>
<% end %>
</tbody>
</table>

A nice clean approach would be to add a "data-user-id" attribute to each tr element and then find the row you want with tr = find('tr[data-user-id="22"]'), but if that's not an option there are a number of ways to do this. Either of
td = page.find(:css, 'td.id', text: /^22$/) # find the id td with text of exactly 22
tr = td.find(:xpath, './parent::tr') # get the parent tr of the td
expect(tr).to have_css('td.name', text: 'John Smith')
or finding the row using just an xpath like
tr = page.find(:xpath, ".//tr[./td[#class='id'][text()='22']]")
expect(tr).to have_css('td.name', text: 'John Smith')
should do what you want. If you want to stick with the looping approach (not recommended because it will be slow - and the way your loop is structured it could just not verify anything) it would be
page.all('tr').each do |tr|
next unless tr.has_css?('td.id', text: /^22$/)
expect(tr).to have_css('td.name', text: "John Smith")
#other expects here...
end

Why not just do like this?:
feature "index users" do
let!(:user) { create(:user, name: "John Smith") }
it "shows users" do
visit users_path
within ".name_#{user.id}" do
expect(page).to have_content("John Smith")
end
end
end

This is not so much a technical answer as it is an alternative approach to avoid the need to write what could be brittle, and overly-complicated tests.
Often times, I am just verifying that some object appeared on the page by looking for some clever text. Maybe it is in a table, or maybe it is in a responsive grid... If I make my test care about the UI implementation, it could break when something changes in the UI.
My "trick" is to use some really unusual text for the test. While "John Smith" should work, you can use "John Zebra" and you will definitely not accidentally have that text appearing on the page.
But when I do need to care about data appearing in a table, I use dom_id for each row. In this example of a list of orgs for the super admin, the reseller org name appears in two rows -- the first being the reseller org's row, and he seond being in the reseller column for a referral org:
The table view code snippet...
%table.orgs-list.stripe
%thead
%tr
%th Created
%th Name
%th Reseller
...
%tbody
- organizations.each do |org|
%tr{id: dom_id(org)}
%td= org.created_at....
%td= link_to org.name, org
%td= org.reseller.try(:name)
...
And the cucumber test code snippet:
Then(/^I should see "([^"]*)" showing "([^"]*)" as the reseller$/) do |org_name, reseller_name|
org = Organization.where( name: org_name).first
reseller = Organization.where( name: reseller_name).first
dom_id = "organization_#{org._id}"
within("tr##{dom_id}") do
expect(page).to have_text(reseller.name)
end
end

def row_containing_cell_with_text(text, exact = false)
find('td,th', text: text, exact: exact).ancestor('tr')
end

Related

Using the value of a loop on v-for to set a conditional class

I'm generating table rows using v-for"x in y". I'd also like to set some classes conditional based on one of the values in the loop.
example:
<tr v-for="file in fileList" class="bg-green if file.include">
<td><% file.filename %></td>
<td><% file.extension %></td>
<td><% file.mime %></td>
</tr>
If file.include is true I'd like the class bg-green applied, but its throwing an error.
note: Using custom delimiters as I'm using Flask.
It'd just be:
<tr v-for="file in fileList" :class="{'bg-green': file.include}">
:class is the shorthand form of v-bind:class. A binding is necessary to make the value an expression.
There are several ways to write the expression but in this case the simplest is to use the object form. The keys of the properties are the class names and the values are truthy/falsey values that determine whether or not to include that class name.
Alternatives include things like:
<tr v-for="file in fileList" :class="file.include ? 'bg-green' : ''">
See https://v2.vuejs.org/v2/guide/class-and-style.html for more information.

Like operator in jsp

I want to display search result in jsp page. I used like operator for searching, but I did not get true result.
st =conn.prepareStatement("select * from books where book_name like ? ");
st.setString(1, "%"+book+"%");
ResultSet rslt = st.executeQuery();
if(rslt.next()){ %>
<h3 align="center">Result Of Your Search </h3>
<table align="center">
<thead>
<tr>
<td>Book Name</td>
</thead>
<tbody>
<% while(rslt.next()){ %>
<tr>
<td><%=rslt.getString("book_name")%></td>
When I wrote Java in search box I got only this result: Head First Java, 2nd Edition, but I have another book in database with name "Java: Graphical User Interfaces"
Why I cant get true result?
Please change if condition. You're starting the cycle with using it.
Or You can use this or in any other way;
if(rslt.next()) {
do {
} while (rslt.next());
}
You're calling next() two times before displaying the results:
if (rslt.next()) {
// so now, you point at the first result
while (rslt.next()) {
// so now, you point at the second result

Send Multiple forms (edit multiple objects) in one Submit button (Ruby)

I have numerous objects (customers) populating a table and I need to edit a particular field for each row/customer (via radio buttons) and save all via a single submit button at the bottom of the table.
I figure it would be best to render a form for each line ("accept_reject_form") in which I have my two radio buttons but I can't figure out how to have the form so on submission each selection is saved for each of the customers.
I've spent a while looking at a few similar questions, but none quite address this problem. Any help would be much appreciated :-)
<table>
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>Available Actions</th>
</tr>
</thead>
<tbody>
<% #customers.each do |customer| %>
<tr>
<th><%= customer.name %></th>
<th><%= customer.age %></th>
<th><%= render 'accept_reject_form' %></th>
</tr>
<% end %>
</tbody>
</table>
You don't need a form per line: each form generates a request, this is hugely inefficient. Instead, the data submitted by the form needs to be structured in such a way that your controller action can update multiple records just by looking at the contents of params.
I would make sure that, in the accept_reject_form partial, you don't have the form tag and just have the fields. The form tag should be wrapped around the block where you iterate over #customer: in this case it will need to go around the whole table.
Give each field in your form partial a name value like
"customers[#{customer.id}][first_name]"
"customers[#{customer.id}][last_name]"
etc
This will then come through to the controller like
params = {:customers => {123 => {:first_name => "John", :last_name => "Smith"}, 456 => {:first_name => "Susan", :last_name => "Thompson"}}
Then in the controller (eg the update action) you can do something like this:
if params[:customer] && params[:id]
#traditional params structure for updating a single record
#customer = Customer.find_by_id(params[:id])
#customer.update_attributes(params[:customer])
elsif params[:customers] #note plural
#new params structure for updating multiple records
#customers = []
params[:customers].each do |id, attrs|
customer = Customer.find_by_id(id)
customer.update_attributes(attrs)
#customers << customer
end
end
this could use some error checking but you get the idea, hopefully.

How to get the proper values after a html table parse with ruby/nokogiri

I have searched and searched for 3 days straight now trying to get a data scraper to work and it seems like I have successfully parsed the HTML table that looks like this:
<tr class='ds'>
<td class='ds'>Length:</td>
<td class='ds'>1/8"</td>
</tr>
<tr class='ds'>
<td class='ds'>Width:</td>
<td class='ds'>3/4"</td>
</tr>
<tr class='ds'>
<td class='ds'>Color:</td>
<td class='ds'>Red</td>
</tr>
However, I can not seem to get it to print to csv correctly.
The Ruby code is as follows:
Specifications = {
:length => ['Length:','length','Length'],
:width => ['width:','width','Width','Width:'],
:Color => ['Color:','color'],
.......
}.freeze
def specifications
#specifications ||= xml.css('tr.ds').map{|row| row.css('td.ds').map{|cell| cell.children.to_s } }.map{|record|
specification = Specifications.detect{|key, value| value.include? record.first }
[specification.to_s.titleize, record.last] }
end
And the csv is printing into one column (what seems to be the full arrays):
[["", nil], ["[:finishtype, [\"finish\", \"finish type:\", \"finish type\", \"finish type\", \"finish type:\"]]", "Metal"], ["", "1/4\""], ["[:length, [\"length:\", \"length\", \"length\"]]", "18\""], ["[:width, [\"width:\", \"width\", \"width\", \"width:\"]]", "1/2\""], ["[:styletype, [\"style:\", \"style\", \"style:\", \"style\"]]"........
I believe the issue is that I have not specified which values to return but I wasn't successful anytime I tried to specify the output. Any help would be greatly appreciated!
Try changing
[specification.to_s.titleize, record.last]
to
[specification.last.first.titleize, record.last]
The detect yields e.g. [:length, ["Length:", "length", "Length"]] which will become
"[:length, [\"Length:\", \"length\", \"Length\"]]" by to_s. With last.first you can extract just the part "Length:" of it.
In case you encounter attributes not matching to your Specification, you could just drop the values by changing to:
xml.css('tr.ds').map{|row| row.css('td.ds').map{|cell| cell.children.to_s } }.map{|record|
specification = Specifications.detect{|key, value| value.include? record.first }
[specification.last.first.titleize, record.last] if specification
}.compact

Ruby/Rails/HTML - Create New Table Row After X cells from loop

I'm using Rails to display a set of data. The problem is that data is so large I dont really do the usually for each loop since I creates this insanely long list.
My solution would be to create some form of table where after 10 records create a new cell and after 5 cells create a new row. I'm not really that comfortable with for loops in rails so I figured throw the question out.
Right now I have...
<strong> Person Data Set: </strong><br />
<% for person in #persons %>
<%= interest.name %> <br />
<% end %>
So I can I create a loop similar to this?
<strong> Person Data Set: </strong><br />
<table>
<tr>
*****for each 5 cells???? *****
<td>
*****For each 10 records?? ***
</td>
</tr>
</table>
Has anyone had to deal with an issue like this before?
There is an each_slice method. With HAML (I really don't like ERB but the idea is the same):
%strong
Person Data Set:
%br
%table
- #persons.each_slice(10) do |ten_people|
%tr
- ten_people.each_slice(5) do |five_people|
%td
- five_people.each do |person|
%p= person.name