我有一个纸张模型。其中有两种状态:草稿和已批准。
我在edit_paper_path上有一个表单,其中 put 与 remote:true 。
我的控制器:
def update
paper = Paper.find(params[:id])
puts paper.status # => :draft
paper.approved!
puts paper.status # => :approved
end
我的测试是:
it 'changes status to Approved', js: true do
expect {
click_button 'Approve'
}.to change { paper.status }
end
但测试失败,我注意到模型中控制器所做的更改已丢失,因此状态仍然存在:草稿。
其他:
这是我的database_cleaner配置:
RSpec.configure do |config|
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
config.before(:each, js: true) do
DatabaseCleaner.strategy = :truncation
end
config.before(:each) do
DatabaseCleaner.start
end
config.append_after(:each) do
DatabaseCleaner.clean
end
end
有什么想法吗?
答案 0 :(得分:2)
您的测试失败,因为当您的测试在内存中保存的模型上运行时,控制器会更新数据库中的记录。
您需要做的是将内存中的表示与DB同步:
it 'changes status to Approved' do
expect(paper.approved?).to be_falsy # sanity check
click_button 'Approve'
# trick to get capybara to wait for request to finish
# note that there actually needs to be a flash message
expect(page).to have_css(".flash")
paper.reload
expect(paper.approved?).to be_truthy
end
编辑Anthony E的反馈来处理竞争条件。
答案 1 :(得分:2)
Capybara AJAX请求以异步方式运行,因此在数据库中更新值之前,正在评估paper.status
。
事实上,Capybara与数据库分离,因此您应该尝试使用Capybara提供的典型has_content
/ has_css
查询方法查询DOM本身来测试您的ajax更新。
你可以通过使用sleep
来等待事务完成来解决这个问题,但这是一个hacky解决方案并且无法保证传递,具体取决于数据库提交需要多长时间
另一个选择是使用jQuery.active
查询脚本等待AJAX调用完成。这里有一篇很好的文章解释了这种方法:https://robots.thoughtbot.com/automatically-wait-for-ajax-with-capybara。