使用水豚在 table 中查找特定行

Finding a specific row in a table using capybara

我有一个用户 table,其中列出了用户的 ID、姓名、电子邮件和用户名。我试图做的是验证特定条目是否在 table 中。

所以基本上我想做的是找到 ID = 22 的行,然后验证 name = John Smithemail = john@smith.comusername = jsmith。能够设置如下所示。我不明白的是一些事情...

  1. 如何获取包含特定文本的行,即 I.E.即 user.id = 22。
  2. 获得该行后,如何使用它获取每个元素。

我想我可以做一种 for 循环,但不知道如何设置 has_selector? 条件。 (以下为伪代码)

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代码

<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>

为什么不这样做呢?:

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

一种干净利落的方法是向每个 tr 元素添加一个 "data-user-id" 属性,然后使用 tr = find('tr[data-user-id="22"]') 找到您想要的行,但如果这不是一个选项,则有多种方法去做这个。

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')

或仅使用类似

的 xpath 查找行
tr = page.find(:xpath, ".//tr[./td[@class='id'][text()='22']]")
expect(tr).to have_css('td.name', text: 'John Smith')

应该做你想做的。如果您想坚持使用循环方法(不推荐,因为它会很慢 - 而且您的循环结构方式可能无法验证任何内容)它将是

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 

这与其说是一个技术答案,不如说是一种替代方法,可以避免编写可能脆弱的内容和 overly-complicated 测试。

很多时候,我只是通过寻找一些巧妙的文本来验证页面上是否出现了某个对象。也许它在 table 中,或者它可能在响应式网格中......如果我让我的测试关心 UI 实现,它可能会在 UI 中发生变化时中断.

我的"trick"是用一些非常不寻常的文字来进行测试。虽然 "John Smith" 应该有效,但您可以使用 "John Zebra" 并且您绝对不会不小心将该文本显示在页面上。

但是当我确实需要关心 table 中出现的数据时,我对每一行使用 dom_id。在这个超级管理员的组织列表示例中,经销商组织名称出现在两行中——第一行是经销商组织的行,然后他在推荐组织的经销商列中:

table 查看代码片段...

%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)
        ...

和黄瓜测试代码片段:

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