Rspec: 用js提交表单时模型没有更新

Rspec: model not updated when submitting form with js

我有一个模型。其中有两个状态:draftapproved.

我在 edit_paper_path 上有一个表格,它使用 remote: true.

创建一个 put

我的控制器:

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

有什么想法吗?

您的测试失败,因为当您的测试在内存中的模型上运行时控制器更新了数据库中的记录。

您需要做的是将内存中的表示与数据库同步:

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 的反馈进行编辑以处理竞争条件。

Capybara AJAX 请求 运行 异步,因此 paper.status 在数据库中更新值之前正在评估。

事实上,Capybara 与数据库分离,因此您应该尝试使用典型的 has_content/[=12= 查询 DOM 本身来测试您的 ajax 更新] Capybara提供的查询方式

您可以通过使用 sleep 等待事务完成来解决此问题,但这是一个有点棘手的解决方案,并且不能保证通过,具体取决于数据库提交所需的时间发生。

另一种选择是使用 jQuery.active 查询脚本等到 AJAX 调用完成。这里有一篇很好的文章解释了这种方法:https://robots.thoughtbot.com/automatically-wait-for-ajax-with-capybara.