Rspec:使用js提交表单时未更新模型

时间:2016-05-11 22:55:21

标签: ruby-on-rails rspec capybara

我有一个纸张模型。其中有两种状态:草稿已批准

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

有什么想法吗?

2 个答案:

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