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.
中验证更改的主要原因。
_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.