简体   繁体   中英

RSpec: Always execute before(:all) in begin/rescue

I'm writing Selenium tests, using Watir-Webdriver and RSpec, which can be a bit spotty when they're first being developed. I've run into a situation where I want to create something on the UI in before :all, however it can throw exceptions (based on timing or poor loading). When that happens I want to take a screenshot.

Here's what I have:

 RSpec.configure do |config|
   config.before(:all) do |group| #ExampleGroup
     @browser = Watir::Browser.new $BROWSER

     begin
       yield #Fails on yield, there is no block
     rescue StandardError => e
       Utilities.create_screenshot(@browser)
       raise(e)
     end
   end
 end

I run it and get an error:

LocalJumpError: no block given (yield)

The reason I assumed yielding would work is RSpec's definition of before:

def before(*args, &block)
  hooks.register :append, :before, *args, &block
end

How can I wrap the code I've put in my before :all in a begin/rescue block without having to do it on every suite?

Thanks in advanced.

The code you've written in the before hook is the &block you're referring to in RSpec::Hooks#before . The hook yields to your code, then runs your tests after the yield is complete.

As for how to make this work, I think this should do:

RSpec.configure do |config|
  # ensures tests are run in order
  config.order = 'defined'

  # initiates Watir::Browser before all tests
  config.before(:all) do
    @browser = Watir::Browser.new $BROWSER
  end

  # executes Utilities.create_screenshot if an exception is raised by RSpec 
  # and the test is tagged with the :first metadata
  config.around(:each) do |example|
    example.run
    Utilities.create_screenshot(@browser) if example.exception && example.metadata[:first]
  end
end

This configuration requires the first test be tagged with metadata:

describe Thing, :first do
  it "does something" do
    # ...
  end
end

This way, you'll only take a screenshot at the beginning of your run for a failing test, and not after every failing test. If you'd rather not mess with metadata (or prefer your tests are run in random order), you could do something like this:

RSpec.configure do |config|
  # initiates Watir::Browser before all tests
  config.before(:all) do
    @test_count = 0
    @browser = Watir::Browser.new $BROWSER
  end

  # executes Utilities.create_screenshot if an exception is raised by RSpec 
  # and the test is the first to run
  config.around(:each) do |example|
    @test_count += 1
    example.run
    Utilities.create_screenshot(@browser) if example.exception && @test_count == 1
  end
end

This works for me. Instead of begin/rescue in the before :all hook,

config.after :each do
  example_exceptions = []
  RSpec.world.example_groups.each do |example_group|
    example_group.examples.each do |example|
      example_exceptions << !example.exception.nil?
      end
    end
  has_exceptions = example_exceptions.any? {|exception| exception}
  #Handle if anything has exceptions
end

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM