Database_cleaner with Rails, Rspec, Capybara. Annoying Deletion. How to control them?

634 Views Asked by At

To make it simple, I have a model Canvas and a model Block.

On each of my canvas-view (which is just a basic table), I have some forms intended to update some blocks contents.

I want to test with RSPEC and Capybara whether or not changes are properly commited.

So I've got this line :

page.driver.execute_script("document.getElementById('block_#{(index+1).to_s}').submit();")

Which sends to my BlocksController

class BlocksController < ApplicationController
  def update
    b=Block.find_by_id_case_and_canvas_id(params[:block][:id_case], params[:block][:canvas_id]) 
    b.update_attributes(params[:block])
    redirect_to "/canvas/"+b.canvas_id.to_s
  end
end

And I can assure you that my canvas-view and all my controllers/models works properly.

But tests fail with this error :

NoMethodError: undefined method `update_attributes' for nil:NilClass

So I've taken a look into my test logs and saw that Database_cleaner seems to delete some tables before I've finished my work :

Processing by BlocksController#update as HTML
  Block Load (0.4ms)  SELECT "blocks".* FROM "blocks" WHERE "blocks"."canvas_id" = 1 AND "blocks"."id_case" = 1 LIMIT 1
  Parameters: {"utf8"=>"✓", "block"=>{"content"=>"1234567890", "id_case"=>"1", "canvas_id"=>"1"}, "id"=>"1"}
   (141.8ms)  DELETE FROM "blocks";
  Block Load (0.5ms)  SELECT "blocks".* FROM "blocks" WHERE "blocks"."id_case" = 1 AND "blocks"."canvas_id" = 1 LIMIT 1

And most of the time, as you can see, the UPDATE request isn't even tried. (I saw it one time by running tests again and again).

So my question is, do someone know how to retard those deletions ?

Thank you a lot !

PS :

Database Cleaner is configured just as in this link :

http://devblog.avdi.org/2012/08/31/configuring-database_cleaner-with-rails-rspec-capybara-and-selenium/

I've tried to change strategies several times but nothing helped.

2

There are 2 best solutions below

0
On

Your problem may be related with the fact that the tests are being wrapped in database transactions, so any process runing outside of it (like selenium) does not see it. You should configure your js tests to be cleaned by a truncation strategy:

First, if you use ActiveRecord, set:

config.use_transactional_fixtures = false

And the configure like following (basically, setting :transaction strategy when possible, and using :truncation only for :js tests):

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

This is taken from (and you can see more information in there):

http://devblog.avdi.org/2012/08/31/configuring-database_cleaner-with-rails-rspec-capybara-and-selenium/

0
On

Your test cases should not depends on data created by another test cases. All your test have to be able to work in isolation.

As you're using DatabaseCleaner you have to bootstrap all needed data for particular test. Usually it can be described using before block or let.

So in your case you have to create Block instance using factory_girl (in case you're using it) or as usual:

FactoryGirl.create :block, canvas_id: 1, case_id: 1
# or
Block.create canvas_id: 1, case_id: 1

hint: For Capybara 2.x there is aliases for methods:

before => background

let => given