Capybara with :js => true 导致测试失败

IT技术 javascript ruby-on-rails-3 capybara
2021-02-23 11:00:43

我是 Capybara 的新手,一般在 Rails 上测试过,所以如果这是一个简单的答案,请原谅我。

我有这个测试

it "should be able to edit an assignment" do
    visit dashboard_path
    select(@project.client + " - " + @project.name, :from => "assignment_project_id")
    select(@team_member.first_name + " " + @team_member.last_name, :from => "assignment_person_id")
    click_button "Create assignment"
    page.should have_content(@team_member.first_name)
end

它按原样通过,但是如果我添加 :js => true 它会失败

cannot select option, no option with text 'Test client - Test project' in select box 'assignment_project_id'

我正在使用 FactoryGirl 创建数据,并且当测试在没有 JS 的情况下通过时,我知道该部分正在工作。

我已经尝试过使用默认的 JS 驱动程序和 :webkit 驱动程序(安装了 capybara-webkit)

我想我不太了解为 Capybara 打开 JS 正在做什么。

为什么在 JS 上测试会失败?

3个回答

我在https://github.com/jnicklas/capybara阅读了 Capybara 自述文件,它解决了我的问题。

事务性装置仅适用于默认的 Rack::Test 驱动程序,但不适用于 Selenium 等其他驱动程序。Cucumber 会自动处理这个问题,但是对于 Test::Unit 或 RSpec,您可能必须使用 database_cleaner gem。有关详细信息,请参阅此说明(以及解决方案 2解决方案 3 的代码)。

但基本上它是一个线程问题,涉及 Capybara 在运行非 Rack 驱动程序时拥有自己的线程,这使得事务夹具功能在另一个上下文中使用第二个连接。因此驱动程序线程永远不会与正在运行的 rspec 处于同一上下文中。

幸运的是,这可以很容易地解决(至少对我来说已经解决了)在使用的 DatabaseCleaner 策略中进行动态切换:

RSpec.configure do |config|
  config.use_transactional_fixtures = false

  config.before :each do
    if Capybara.current_driver == :rack_test
      DatabaseCleaner.strategy = :transaction
    else
      DatabaseCleaner.strategy = :truncation
    end
    DatabaseCleaner.start
  end

  config.after do
    DatabaseCleaner.clean
  end
end
应该注意的是,在 EvilMartians 的共享连接向后移植的帮助下,最新版本的 Rails (5+) 甚至更早版本支持事务功能,您绝对应该研究它以节省大量时间。test-prof.evilmartians.io/#/active_record_shared_connection
2021-04-21 11:00:43
搞定了 - 谢谢!另外 - 由于 jnicklas 对邮件列表的解释,我现在明白了为什么它有效 - 感谢您的指点。
2021-05-01 11:00:43
谢谢,这篇文章真的很有帮助!:)
2021-05-02 11:00:43
完美 - 非常感谢!证实这一点也适用capybara-webkit,以及
2021-05-12 11:00:43
您只需要将策略设置为截断功能规范,就像@Aidan 的回答一样。
2021-05-15 11:00:43

brutuscat 答案的变体,修复了我们的功能规格(均使用 Capybara):

config.before(:suite) do
  DatabaseCleaner.clean_with(:truncation)
end

config.before(:each) do
  # set the default
  DatabaseCleaner.strategy = :transaction
end

config.before(:each, type: :feature) do
  DatabaseCleaner.strategy = :truncation
end

config.before(:each) do
  DatabaseCleaner.start
end

config.append_after(:each) do
  DatabaseCleaner.clean
end

现在这里描述和讨论的还有另一种处理这个问题的方法:为什么不为 Rspec + Selenium 使用共享的 ActiveRecord 连接?