From bba1bcce74913698363b20fc74412d4d378faefc Mon Sep 17 00:00:00 2001 From: Eliot Sykes Date: Tue, 14 Jul 2015 17:30:56 +0100 Subject: [PATCH] Explain & strengthen RSpec+Capybara config The configuration is a tad more robust in 2 ways: - It checks the Capybara driver isn't rack_test - this is the more reliable check. Using the `js: true` flag is only one of the ways in which a driver can be set. For example the `:driver` metadata option is an alternative way of setting the capybara driver. - Setting `config.use_transactional_fixtures = false` in the database cleaner configuration is not always enough alone. If the config is still set in `rails_helper.rb` to `config.use_transactional_fixtures = true`, that can take precedence. The linked to configuration raises an error if this error is detected. --- README.markdown | 57 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/README.markdown b/README.markdown index d56069c..afe9eae 100644 --- a/README.markdown +++ b/README.markdown @@ -221,7 +221,30 @@ end ### RSpec with Capybara Example -If you're using Capybara with RSpec and using an external browser (not using RackTest) you'll almost certainly need to use truncation rather than transactions for tests tagged `:js`. +You'll typically discover a feature spec is incorrectly using transaction +instead of truncation strategy when the data created in the spec is not +visible in the app-under-test. + +A frequently occurring example of this is when, after creating a user in a +spec, the spec mysteriously fails to login with the user. This happens because +the user is created inside of an uncommitted transaction on one database +connection, while the login attempt is made using a separate database +connection. This separate database connection cannot access the +uncommitted user data created over the first database connection due to +transaction isolation. + +For feature specs using a Capybara driver for an external +JavaScript-capable browser (in practice this is all drivers except +`:rack_test`), the Rack app under test and the specs do not share a +database connection. + +When a spec and app-under-test do not share a database connection, +you'll likely need to use the truncation strategy instead of the +transaction strategy. + +See the suggested config below to temporarily enable truncation strategy +for affected feature specs only. This config continues to use transaction +strategy for all other specs. ```ruby RSpec.configure do |config| @@ -229,11 +252,39 @@ RSpec.configure do |config| config.use_transactional_fixtures = false config.before(:suite) do + if config.use_transactional_fixtures? + raise(<<-MSG) + Delete line `config.use_transactional_fixtures = true` from rails_helper.rb + (or set it to false) to prevent uncommitted transactions being used in + JavaScript-dependent specs. + + During testing, the app-under-test that the browser driver connects to + uses a different database connection to the database connection used by + the spec. The app's database connection would not be able to access + uncommitted transaction data setup over the spec's database connection. + MSG + end DatabaseCleaner.clean_with(:truncation) + end + + config.before(:each) do + DatabaseCleaner.strategy = :transaction end - config.before(:each) do |example| - DatabaseCleaner.strategy = example.metadata[:js] ? :truncation : :transaction + config.before(:each, type: :feature) do + # :rack_test driver's Rack app under test shares database connection + # with the specs, so continue to use transaction strategy for speed. + driver_shares_db_connection_with_specs = Capybara.current_driver == :rack_test + + if !driver_shares_db_connection_with_specs + # Driver is probably for an external browser with an app + # under test that does *not* share a database connection with the + # specs, so use truncation strategy. + DatabaseCleaner.strategy = :truncation + end + end + + config.before(:each) do DatabaseCleaner.start end