Recently I added few integration tests in my projects using Capybara and Selenium webdriver and ran into banging my head against inconsistencies with test database. I create some records in test DB which were completely invisible to Selenium-driven browser-based tests.
The problem is: the tests are being wrapped in database transactions, so any code running outside the actual test process (like, say, a server process servicing a Selenium-driven browser request) does not see the database records.
Here are the steps to fix this problem -
First of all, and this is very important, go into spec/spec_helper.rb and change this line:
config.use_transactional_fixtures = true
config.use_transactional_fixtures = false
This will disable rspec-rails implicit wrapping of tests in a database transaction. Without disabling this, none of the following configuration will matter.
Now configure database_cleaner. [database_cleaner(database cleaner)] is a gem that abstracts away the various ORM APIs for getting the DB into a “blank slate” state.
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.after(:each) do DatabaseCleaner.clean end end
Let’s take that step by step.
config.before(:suite) do DatabaseCleaner.clean_with(:truncation) end
This means: before the entire test suite runs, clear the test database completely.
config.before(:each) do DatabaseCleaner.strategy = :transaction end
This sets the default database cleaning strategy to be transactions. Transactions are very fast.
config.before(:each, :js => true) do DatabaseCleaner.strategy = :truncation end
This line only runs before examples which have been flagged js: true. By default, these are the only tests for which Capybara fires up a test server process and drives an actual browser window via the Selenium backend. For these types of tests, transactions won’t work, so this code overrides the setting and chooses the “truncation” strategy instead.
config.before(:each) do DatabaseCleaner.start end config.after(:each) do DatabaseCleaner.clean end
These lines hook up database_cleaner around the beginning and end of each test, telling it to execute whatever cleanup strategy we selected beforehand.
And that’s it!