Rails 使用 RSpec 和 Capybara 进行应用测试。我收到错误 Capybara::ElementNotFound

Rails app testing with RSpec and Capybara. I get Error Capybara::ElementNotFound

_customers_table.html.erb

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Phone number</th>
      <th>Description</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @customers.each do |customer| %>
      <tr>
        <td><%= customer.name %></td>
        <td><%= customer.phone_number %></td>
        <td><%= customer.description %></td>
        <td><%= link_to customer.status.humanize, toggle_status_customer_path(customer), class: "move-to-black" %></td>
        <td><%= link_to 'Show', customer %></td>
        <td><%= link_to 'Edit', edit_customer_path(customer) %></td>
        <td><%= link_to 'Destroy', customer, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>


creating_customer_spec.rb

require 'rails_helper'

describe "creating new customer", type: :feature do
  let(:customer) { customer = FactoryBot.create(:customer) }

  it 'should create new customer' do
    visit '/customers/new'
    fill_in 'Name', with: customer.name
    fill_in 'Phone number', with: customer.phone_number
    click_button 'Create Customer'
    expect(page).to have_content "#{customer.name}"
  end

  it 'should change customer status' do
    visit '/'
    click_on customer.status.humanize
    expect(customer).to have_status "move_to_white_list"
  end
end


第一个例子 'should create new customer' 通过了,但是第二个 'should change customer status'

出错了
Capybara::ElementNotFound:
       Unable to find link or button "Move to black list"

该元素存在,您可以在图像上看到它。 如果有人能提供帮助,我将不胜感激。enter image description here

I changed the second example, now it works.This is my mistake I didn’t explain it well, the “black list” table is on a different view and when the status changes, it moves to another page so actualy it's not possible to find it there.

    require 'rails_helper'

describe "creating new customer", type: :feature do
  let!(:customer) { customer = FactoryBot.create(:customer) }

  it 'should create new customer' do
    visit '/customers/new'
    fill_in 'Name', with: customer.name
    fill_in 'Phone number', with: customer.phone_number
    click_button 'Create Customer'
    expect(page).to have_content "#{customer.name}"
  end

  it 'should change customer status' do
    visit '/customers'
    click_on customer.status.humanize
    expect(page).to have_content "Customer #{customer.name} moved to black list"

    visit '/black_list'
    expect(customer.reload.status).to eq "move_to_white_list"
  end
end

您这里有很多问题。首先,您将在创建客户实例之前转到页面,这意味着它不会显示在页面上。这是因为 let 延迟评估 - 参见 https://relishapp.com/rspec/rspec-core/v/3-8/docs/helper-methods/let-and-let - 并且只会在测试中第一次调用客户时创建客户。

visit '/' # <= no customer instance exists here
click_on customer.status.humanize # <= customer instance actually created here

您可以通过使用始终创建客户实例的非延迟评估版本 let! 或在调用 visit

之前调用 customer 来解决此问题

其次,您的测试正在修改数据库中的客户实例,但从不重新加载内存中的实例(因此永远不会看到新状态)

expect(customer.reload).to have_status "move_to_white_list"

第三,如果您使用的是支持异步行为的驱动程序(除 rack-test 之外的任何驱动程序),则不能保证由操作方法(click_on 等)引起的任何副作用都会有在方法调用 returns 之前完成。这意味着您的期望很可能会在客户实例状态更改之前被调用。要修复 have_status 匹配器需要编写为具有重试行为(就像 Capybara 提供的所有匹配器所具有的那样)并且在匹配器中也具有重新加载行为。这就是为什么在 system/feature 测试中验证数据库更改通常不是一个好主意,而是坚持在 UI.

中验证更改的主要原因。