B Seven
B Seven

Reputation: 45941

Is there a way to run a nested before filter first in RSpec?

describe 'Feature' do
  before do
    setup
  end

  describe 'Success' do
    before do
      setup_for_success
    end

    specify 'It works' do
      ...
    end
  end
end

RSpec will always run the setup before setup_for_success. It there a way to run setup_for_success first?

Upvotes: 3

Views: 3430

Answers (3)

BorZ
BorZ

Reputation: 51

It seems a little weird you put in a nested context what you need in the outer one. I suspect that you don't need that setup in all of the nested contexts. If that's the case you need to filtering your hooks.

RSpec.describe 'Feature' do
  before :each, success: true do
    setup_for_success
  end

  before :each do
    setup
  end

  describe 'Success', success: true do
    specify 'It works' do
      ...
    end
  end

  describe 'Fail' do
    specify 'Won´t work' do
      ...
    end
  end
end

You can do this without nesting:

RSpec.describe 'Feature' do
  before :each, success: true do
    setup_for_success
  end

  before :each do
    setup
  end

  specify 'It works', success: true do
    ...
  end

  specify 'Won´t work' do
    ...
  end
end

Here is the link to the docs:

https://relishapp.com/rspec/rspec-core/docs/hooks/filters

Upvotes: 4

PJSCopeland
PJSCopeland

Reputation: 3006

before filters are appended in the order they're specified. Since RSpec 2.10.0, you can prepend them instead by making them prepend_before filters.

Likewise, after filters are prepended by default, but you can append_after them instead.

Your code would end up as follows (compacted for brevity):

describe 'Feature' do
  before { setup }

  describe 'Success' do
    prepend_before { setup_for_success }

    it 'works' { ... }
  end
end

Upvotes: 4

James Milani
James Milani

Reputation: 1943

You can do this by scoping a before(:all) to run before a before(:each) try this:

describe 'Feature' do
  before(:each) do
    puts "second"
  end

  describe 'Success' do
    before(:all) do
      puts "first"
    end

    specify 'It works' do
      ...
    end
  end
end

# =>
10:29:54 - INFO - Running: spec
Run options: include {:focus=>true}
first
second
.

Finished in 0.25793 seconds (files took 2.52 seconds to load)
1 example, 0 failures

EDIT:

In Rspec 2, the actions run in this order:

before suite
before all
before each
after each
after all
after suite

Here's a link to the docs showing the order that the methods are called in: https://www.relishapp.com/rspec/rspec-core/v/2-2/docs/hooks/before-and-after-hooks#before/after-blocks-are-run-in-order

Apparently in Rspec 3.5, the before block calls have a different naming that also works. They run in this order:

before :suite
before :context
before :example
after  :example
after  :context
after  :suite

describe 'Feature' do
  before(:example) do
    puts "second"
  end

  describe 'Success' do
    before(:context) do
      puts "first"
    end

    specify 'It works' do
      ...
    end
  end
end

10:59:45 - INFO - Running: spec
Run options: include {:focus=>true}
first
second
.

Finished in 0.06367 seconds (files took 2.57 seconds to load)
1 example, 0 failures

Here's the newer docs: http://www.relishapp.com/rspec/rspec-core/v/3-5/docs/hooks/before-and-after-hooks

Upvotes: 6

Related Questions