23
votes

I have a JS feature spec I'm trying to run with Capybara Webkit. It doesn't seem to be able to find my database records however.

The spec in question looks like this

it "should allow pledging to a Hardback level", js: true do
  book = FactoryGirl.create :book
  visit book_path(book)
  click_link "pledge-btn"
end

Unfortunately, the request to book_path(book) 404s because the book cannot be found.

If I take the :js flag off, the test passes.

I have DatabaseCleaner set up to use :truncation for JS specs as is the recommended method.

# spec/support/database_cleaner.rb
RSpec.configure do |config|
  config.use_transactional_fixtures = false

  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
    DatabaseMetadata.create!(:sanitized_at => DateTime.now) 
  end

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

I can puts the book in the test and it will be found.

it "should allow pledging to a Hardback level", js: true do
  book = FactoryGirl.create :book
  visit book_path(book)
  p Book.first
  # => .. the book instance
  click_link "pledge-btn"
end

I've also tried this shared connection method which doesn't seem to fix the problem either.

What else could be wrong?

6
Just wondering what would happen if the book = FactoryGirl.create :book was in a before(:each) do...end block?Neil Billingham
Did you set config.use_transactional_fixtures = false?Steve
if you want to know how i handle it, you can read my two cents here: gist.github.com/phoet/6683280#file-readme-mdphoet
@NeilBillingham It actually is in a before(:each) block (I simplified a little to keep the question concise). I've tried it within and without and it makes no difference.David Tuite
@Steve Yep. Sorry, should have mentioned that in the question.David Tuite

6 Answers

9
votes

You may have config.use_transactional_fixtures = true set in your spec_helper.rb. This would override what you have above.

You want to either remove this line from your spec_helper.rb or change it there to be false.

6
votes

I ran into this same issue and had a very similar config. After looking through the DatabaseCleaner README, I found this small note:

It's also recommended to use append_after to ensure DatabaseCleaner.clean runs after the after-test cleanup capybara/rspec installs.

Source

That means changing your

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

to

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

Note the append_after instead of after. This fixed my problem.

5
votes

Working on legacy project I have had such issue, it was caused by switching DatabaseCleaner strategy to :truncation like the following:

config.before(:suite) do
  DatabaseCleaner.strategy = :truncation
  DatabaseCleaner.clean

  Test::Seeder.seed!

  DatabaseCleaner.strategy = :transaction
end

so, removing DatabaseCleaner.strategy = :transaction helped in my case

3
votes

If you create records in a before(:all) block then they will be available.

before :all do
  @book = FactoryGirl.create :book
end

it "should allow pledging to a Hardback level", js: true do
  visit book_path(@book)
  click_link "pledge-btn"
end

Capybara runs the rails server in a separate process from the tests, so they each get their own connection to the database. Therefore, the server does not access to the records created in the transaction for the test.

Because they are not inside a transaction, make sure that you clean them up with DatabaseCleaner in your spec_helper.rb:

config.after(:all, :type => :feature) do
  DatabaseCleaner.clean
end
1
votes

For anyone that lands here in 2019 and beyond, I was caught out by the following code which I copied verbatim from the DatabaseCleaner readme:

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

  unless 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

This is all well and good, but I am using Rails system specs, not RSpec features and therefore this code block was never being run.

Change config.before(:each, type: :feature) to config.before(:each, type: :system) if you're using system specs!

-2
votes

I think your main issue is that your rails_helper.rb has the following line commented out:

Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } 

This means your database_cleaner.rb is never getting loaded.