Capybaraのdriverの切り替えに合わせて、database_cleanerのstrategyを動的に切替える
環境
- rails (4.2.1)
- capybara (2.4.4)
- database_cleaner (1.4.1)
やりたいこと
- Capybaraでpoltergeistなどのjsdriverを利用しつつも、テストの実行速度をできるだけあげたい
Capybaraでjsを含む画面をテストしようとしてぶつかる問題
-
Capybaraでpoltergeistなどのjsdriverを利用する場合、rspecとは別のサーバプロセスが起動してテストが実行されます。
-
specのletやbeforeで設定したテストデータはrspecのプロセスでセットアップされるため、テストやDBクリアの戦略をtransactionにしていると、jsdriverからテストデータが見えない。
(transactionにしているとテスト実行後にrollbackされる(commitされない)ため別プロセスからはデータが見えない。) -
そのため、jsdriverを使用するテストではDBクリアの戦略をtruncationにする必要があります。こうするとテストデータのセットアップではcommitして、テスト実行後にtruncationが行われDBがクリアされるので、別のプロセスからテストデータが見えるようになります。(connectionをshareするやり方もあるみたいです。)
-
しかし、DBのクリアをtruncationで行うとtransactionより実行コストがかかるため、jsdriverを使用しないテストでもtruncationを利用するとテスト全体が遅くなってしまいます。
-
以下のコードの1)と2)はrspecの実行プロセス内、3)は別サーバプロセスから実行される。
# 1)
let!(:user) { create(:user) }
before { user.posts << create(:post) }
# 2)
context 'use rack test' do
# do something
end
# 3)
context 'use js driver', js: true do
# do something
end
設定内容
rspecのcofigurationでbefore(:each)毎にDatabaseClearnerのstrategyを切り替えるようにすることで、jsdriverが必要なところだけtruncationでDBクリアされるようになります。
Capybara.javascript_driver = :poltergeist
RSpec.configure do |config|
config.use_transactional_fixtures = false
config.before :suite do
DatabaseCleaner.strategy = :transaction
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.after(:each) do
DatabaseCleaner.clean
end
end