在 RSpec 功能规范中测试索引视图排序顺序 (Capybara)

Testing index view sort order in RSpec feature spec (Capybara)

Rails 4.2 应用程序的索引视图在 header 处有一个 table 排序 link。如果用户单击 "E-mail" header,记录将按 E-mail 排序,依此类推。单击排序 link 时,将重新加载页面(使用 q=email+asc 之类的查询字符串)。 AJAX尚未使用。

我写了下面的测试。它有效,但我相信应该有更好的方法来测试它。

it "sorts by e-mail when the 'E-mail' column header is clicked", :focus do
  visit "/admin/users"
  expected_id_order = User.order(:email).map(&:id)
  # Once the page is reloaded (the new sort order is applied), the "stale"
  # class will disappear. Note that due to Turbolinks, only the part of
  # the DOM that is modified by a request will have its elements replaced.
  page.execute_script("$('tr.user:first').addClass('stale')")
  within "thead" do
    click_link("E-mail")
  end
  # Force Capybara to wait until the page is reloaded
  expect(page).to have_no_selector("tr.user.stale")
  actual_id_order = page.body.scan(/<tr.+id="user_(.+)".*>/).flatten
  expect(actual_id_order).to eq(expected_id_order)
end

其他详细信息:

借鉴 this blog post 的想法,您可以做类似

的事情
# get the index of the first occurrence of each users' email address in the response body
actual_order = User.order(:email).map { |user| page.body.index(user.email) }
# should already be in sorted order
expect(actual_order).to eq(actual_order.sort)

至于必须等待 .stale class 被删除,我建议改为修改您的 html 以包含某种 "this is the currently sorted column" class 在您的 tha 标签上。

<a id="email-sort-link" class="sorted asc">E-Mail</a>

然后你可以等到看到 a#email-sort-link.sorted。通常不喜欢修改代码以方便测试,但这似乎足够小,并且允许您设置 link 不同的样式以提醒用户当前排序。

最简单的方法是利用您控制测试数据的事实,相应地分配字符串,然后使用正则表达式来测试用户实际看到的输出,而不是特定的标签和 ID。

within_table('user_table') do # any method that will scope to the table
  expect(page).to have_text /user3@test\.com.+user2@test\.com.+user1@test\.com/ # initial expected ordering
  click_link("E-mail")
  expect(page).to have_text /user1@test\.com.+user2@test\.com.+user3@test\.com/ # sorted expected ordering
end

水豚会等待,不需要 JS hack,等等

我有一个特定的案例,我想使用共享示例。所以我根据 Thomas Walpole 的回答创建了以下内容。

def sort_order_regex(*sort_by_attributes)
  /#{User.order(sort_by_attributes)
         .map { |u| Regexp.quote(u.email) }
         .join(".+")}/
end

RSpec.shared_examples "sort link" do |link_text:, sort_by:|
  # Make sure your factory creates unique values for all sortable attributes
  before(:each) { FactoryGirl.create_list(:user, 3) }

  it "sorts by #{sort_by} when the #{link_text} link is clicked" do
    visit "/admin/users"
    # Check the record's order by matching the order of their e-mails (unique).
    initial_order = sort_order_regex(:first_name, :last_name)
    tested_order = sort_order_regex(sort_by)
    within_table "users_table" do
      expect(page).to have_text(initial_order)
      click_link(link_text, exact: false)
      expect(page).to have_text(tested_order)
    end
  end
end

describe "User CRUD", type: :feature, js: true do
  describe "sorting" do
    include_examples "sort link", link_text: "E-mail", sort_by: :email
    include_examples "sort link", link_text: "Role", sort_by: :role
    include_examples "sort link", link_text: "Country", sort_by: :country
    include_examples "sort link", link_text: "Quotes", sort_by: :quotes_count
  end
  #...
end

我们可以用 CSS 东西来测试它。

一个例子:

|---------------------|------------------|
|     username        |     email        |
|---------------------|------------------|
|     bot1            | bot1@mail.com    |
|---------------------|------------------|
|     bot2            | bot2@mail.com    |
|---------------------|------------------|

我们的 RSpec 可以是这样的:

RSpec.describe "returns expected sorted row data" do
  it 'returns expected sorted row data' do
    # the headers column name
    within 'tr:nth-child(1)' do
      expect(page).to have_text 'username password'
    end

    # the second row
    within 'tr:nth-child(2)' do
      expect(page).to have_text 'bot1 bot1@mail.com'
    end

    # the third row
    within 'tr:nth-child(3)' do
      expect(page).to have_text 'bot2 bot2@mail.com'
    end
  end
end