根据Capybara Docs,有两种不同的策略来处理Selenium无法访问测试中生成的数据的问题:
Monkey patch ActiveRecord:
类ActiveRecord :: Base @@ shared_connection = nil def self.connection @@ shared_connection || retrieve_connection 结束 结束 ActiveRecord :: Base.shared_connection = ActiveRecord :: Base.connection
使用截断而不是交易
我按照Avdi Grimm here的概述设置了DatabaseCleaner,虽然查看我的日志但我可以清楚地看到DatabaseCleaner正在使用截断,例如:
(7.4ms)TRUNCATE TABLE"画廊","照片","用户" RESTART IDENTITY CASCADE;
...当我运行我的功能时,我作为设置的一部分创建的任何模型都不可用于驱动程序。我可以看到场景中存在模型,但如果我将它们打印到页面上,它们就不存在了。
我可以让驱动程序查看模型的唯一方法是使用上面的ActiveRecord monkey-patch,但这似乎会引发许多奇怪的次要问题 - 测试挂起等等。
为什么驱动程序(Selenium或Capybara-Webkit)无法看到在测试中创建的模型,即使我使用带有截断策略的DatabaseCleaner,又如何让Capybara使用JavaScript驱动程序呢?
注意:使用默认驱动程序
,测试正常我的DatabaseCleaner配置:
RSpec.configure do |config|
# Clean DB completely
config.before(:suite) do
DatabaseCleaner.clean_with(:truncation)
end
# Set default strategy (non-js/Rack::Test)
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
# Set strategy for tests using JS (slower)
config.before(:each, js: true) do
DatabaseCleaner.strategy = :truncation
end
# Wrap DatabaseCleaner around each test (before & after)
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
end
end
以下是我希望使用JavaScript进行测试的功能示例:
feature "User deletes a photo" do
before {
as_signed_in_user
@gallery = create(:gallery_with_photos)
}
scenario "successfully deletes a photo from a gallery", js: true do
photo_title = @gallery.photos.first.title
puts "GALLERY #{Gallery.find(1)}" # <Gallery:0x007f9b928fe8e8>
visit gallery_path(@gallery) # JavaScript driver can't find gallery
within '.photos-list' do
click_link photo_title
end
click_link('Delete Photo')
expect(current_path).to eq( gallery_path(@gallery) )
expect(page).not_to have_link(photo_title)
end
end
使用JavaScript驱动程序时,此测试失败并显示:
1) User deletes a photo successfully deletes a photo from a gallery
Failure/Error: Unable to find matching line from backtrace
ActiveRecord::RecordNotFound:
Couldn't find Gallery with 'id'=1
正如Dave Schweisguth在评论中所建议的那样,我已经尝试将js:true
移出到功能而不是场景,而不会产生任何影响。
答案 0 :(得分:3)
确保您使用的是数据库清理程序,capybara,selenium-webdriver的最新版本
。还要确保所有这些宝石都在测试组中并且是require: false
然后在spec_helper.rb文件中,您可以通过在这些宝石之前需要rails来控制加载顺序。确保RAILS_ENV
和use_transactional_fixtures
<强> spec_helper.rb 强>
require 'rubygems'
ENV['RAILS_ENV'] ||= 'test'
# Load rails + environment
require File.expand_path('../../config/environment', __FILE__)
require 'rspec/rails'
# Load database cleaner
require 'database_cleaner'
# Load capybara and its dependencies
require 'capybara/rspec'
require 'capybara/rails'
require 'selenium-webdriver'
RSpec.configure do |config|
# Do not use transactional, let database_cleaner do the work
config.use_transactional_fixtures = false
# Database cleaner config
config.before(:suite) { DatabaseCleaner.clean_with :truncation }
config.before(:each) { DatabaseCleaner.strategy = :transaction }
config.before(:each, js: true) { DatabaseCleaner.strategy = :truncation }
config.before(:each) { DatabaseCleaner.start }
config.after(:each) { DatabaseCleaner.clean }
end
功能规范
尝试使用describe ... type: :feature
代替,并将js: true
移到最上面,如下所示:
describe "User deletes a photo", type: :feature, js: :true do
before { ... }
scenario "successfully deletes a photo from a gallery" do
...
end
end
您的代码
1-即使是为了快速调试,也不要写puts "GALLERY #{Gallery.find(1)}"
。它可能会在某些情况下引发错误并导致混淆(即让您认为问题在确实存在的情况下无法解决)。请改用puts "GALLERY #{Gallery.find(@gallery.id)}"
2-在rspec中使用实例变量不是一个好习惯,所以不要这样做:
before {
as_signed_in_user
@gallery = create(:gallery_with_photos)
}
你应该写这个
before { as_signed_in_user }
let!(:gallery) { create(:gallery_with_photos) }
请注意,我使用的是let!
,它等同于before
。因此,在您的其他规范中,您必须将@gallery
替换为gallery