4

How can I tag an example group so that the database isn't cleaned between each example, but is cleaned before and after the whole group? And untagged specs should clean the database between each example.

I would like to write:

describe 'my_dirty_group', :dont_clean do
  ...
end

So in my spec_helper.rb I put:

  config.use_transactional_fixtures = false

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

  config.before(:suite, dont_clean: true) do
    DatabaseCleaner.clean
  end

  config.after(:suite, dont_clean: true) do
    DatabaseCleaner.clean
  end

  config.before(:each, dont_clean: nil) do
    DatabaseCleaner.start
  end

  config.before(:each, dont_clean: nil) do
    DatabaseCleaner.clean
  end

The problem is that the dont_clean: nil (or false) blocks in spec_helper don't run when the metadata tag is not specified. Is there another way to check for presence of :dont_clean before cleaning between examples?

rigyt
  • 2,219
  • 3
  • 28
  • 40

2 Answers2

3

Summary

You can set custom metadata on the whole example block, and then access the metadata within your RSpec config with self.class.metadata for use with conditional logic.

Code

Using these gem versions:

$ bundle exec gem list | grep -E '^rails |^rspec-core |^database'
database_cleaner (1.4.0)
rails (4.2.0)
rspec-core (3.2.0)

The following works for me:

File: spec/spec_helper.rb

RSpec.configure do |config|

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

  config.before(:all) do
    # Clean before each example group if clean_as_group is set
    if self.class.metadata[:clean_as_group]
      DatabaseCleaner.clean
    end
  end

  config.after(:all) do
    # Clean after each example group if clean_as_group is set
    if self.class.metadata[:clean_as_group]
      DatabaseCleaner.clean
    end
  end

  config.before(:each) do
    # Clean before each example unless clean_as_group is set
    unless self.class.metadata[:clean_as_group]
      DatabaseCleaner.start
    end
  end

  config.after(:each) do
    # Clean before each example unless clean_as_group is set
    unless self.class.metadata[:clean_as_group]
      DatabaseCleaner.clean
    end
  end

end

File: spec/models/foo_spec.rb

require 'spec_helper'

describe 'a particular resource saved to the database', clean_as_group: true do

  it 'should initially be empty' do
    expect(Foo.count).to eq(0)
    foo = Foo.create()
  end

  it 'should NOT get cleaned between examples within a group' do
    expect(Foo.count).to eq(1)
  end

end 

describe 'that same resource again' do

  it 'should get cleaned between example groups' do
    expect(Foo.count).to eq(0)
    foo = Foo.create()
  end

  it 'should get cleaned between examples within a group in the absence of metadata' do
    expect(Foo.count).to eq(0)
  end

end 
admgc
  • 273
  • 3
  • 9
  • I think it will not work when there are multiple `contexts` in `describe` block. Please advise, what should be done in such case, where we want to clean before all `contexts`. – rhunal Dec 21 '17 at 09:19
0

You can check on example.metadata inside the blocks, although I haven't been able to figure out how to do this for before(:suite)

method
  • 782
  • 4
  • 10