James Martineau
James Martineau

Reputation: 951

RSpec - How do nested before :all and before :each blocks interact?

I encountered an issue with some Web UI Automation using RSpec and Selenium/Capybara/SitePrism. It's related to the combination of before :all and before :each clauses that occur in the code, and perhaps especially in my spec_helper file.

Up until now, I've been running rspec against one spec file at a time. Each spec file required a spec_helper file, which included the following:

spec_helper.rb:
  RSpec.configure do |config|
    config.before(:all) do
      # 1) Code to configure WebDriver and launch Browser is here
    end
  end

The spec files themselves contain their own before blocks for various reasons. Most of them contain something like the following:

test_a_spec.rb:
  describe "Page A" do
    before :all do
      # 2) Log in to web site, maybe load the test page in question
    end
    it "does this thing" do
      # 3) Test this thing
    end
    it "does that thing" do
      # 4) Test that thing
    end
  end

This worked fine as long as I was running RSpec against individual spec files. When I tried tagging some of my examples and then running against the whole spec folder, I had a problem. The before :all block in spec_helper.rb didn't prepend itself to every file, as I thought it would, but instead ran once at the beginning. All the spec files after the first were expecting a clean browser to be launched by spec_helper and to do the log in part themselves, but the browser wasn't clean and was already logged in, so that wasn't good.

Changing the before :all in spec_helper.rb to a before :each seemed like the natural solution, so I did, and suddently my tests instantly failed with an error claiming that rack-test requires a rack application, but none was given. This happened to some of my tests but not all, and through process of elimination I realized it was only tests that had their own before :all blocks that were failing. It appears that the before :all in the spec file is superceding the before :each in the spec_helper file. So it was trying to log in before it had launched a browser.

This vexes me. I am terribly vexed. I had sort of assumed two things:

Questions:

1) What kind of behavior is my spec_helper file actually producing? If I were to take that same behavior and put it into one of the spec files itself, for instance, what would that look like? Would the before :each with the browser launch code wrap around all the code in the spec file in some sort of implicit describe block? Does the before :each get inserted into the outermost describe block, and therefore have to compete with the spec file's before :all block?

2) I could "solve" this by abandoning all before :all blocks in my tests, but I like the flexibility of the way things are, and since this is UI Automation and speed is a factor, I don't really want to be opening a new browser and logging in for each describe, even though I'm aware that this would be ideal for keeping every test separated from the others. Do I have to/want to do just that?

Thanks!

Upvotes: 2

Views: 2968

Answers (2)

Andrew Schlei
Andrew Schlei

Reputation: 377

The RSpec documentation (http://rspec.info/documentation/3.3/rspec-core/RSpec/Core/Hooks.html#before-instance_method) provides some very useful information about how before blocks interact and the order in which they are run, but they do recommend avoiding before(:context) [aka before(:all)].

FYI, note that the after blocks are run in the reverse order fin which before blocks are.

Upvotes: 0

Peter Alfvin
Peter Alfvin

Reputation: 29399

To address the part of your question not already covered by https://stackoverflow.com/a/22489263/1008891, the require method will not reload any file already loaded previously, as described in https://stackoverflow.com/a/22489263/1008891. This contrasts with the load method, which acts like a "copy/paste" of the file contents wherever it is used.

I'm not saying that if you changed all your requires to loads that you'd get the same result as running the individual files, as there may be other global state that affects the behavior you're seeing.

Upvotes: 2

Related Questions