Skip to content
This repository has been archived by the owner on Jul 17, 2022. It is now read-only.

Add support for config.around(:all) and config.around(:all_nested) #2

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Provides around(:all) hooks for RSpec.
In your Gemfile:

``` ruby
gem 'rspec_around_all', git: 'git://gist.github.com/2005175.git'
gem 'rspec_around_all', require: false
```

In a spec:
Expand Down
33 changes: 28 additions & 5 deletions lib/rspec_around_all.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,48 @@ def run_examples
def to_proc
proc { run_examples }
end

def class
__getobj__.class
end
end

def around(scope = :each, &block)
return around_all &block if scope == :all
# let RSpec handle around(:each) hooks...
return super(scope, &block) unless scope == :all
return super(scope, &block) unless scope == :all_nested
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I'd like to see a new scope (:all_nested) introduced here in this helper gem -- I'd like to keep this gem as minimal as possible. If all the other changes in this PR were merged, would you be able to achieve this same result via logic in your own spec configuration/setup instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really see any value in config.before/after/around(:all) blocks. Do you have any use case where it could be useful? I only really care about config.around(:all_nested). Maybe we could rename :all_nested to :group or :context. What do you think?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change here (introducing :all_nested scope) is not limited to config.around() usage. I'm wondering if we can leave all of the changes in this method out of this PR, if you could then do nesting of around-alls in your configuration without requiring further changes here.

around_all do |group|
group.children.each {|c| c.around(:all_nested, &block) }
block[group]
end
end

group, fiber = self, nil
before(:all) do
private

FIBERS_STACK = []

def around_all(&block)
prepend_before(:all) do |group|
fiber = Fiber.new(&block)
fiber.resume(FiberAwareGroup.new(group))
FIBERS_STACK << fiber
fiber.resume(FiberAwareGroup.new(group.class))
end

after(:all) do
prepend_after(:all) do
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be append_after to properly nest? (spec coverage to validate this would be useful)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it validated, but I've also thought about that. Maybe I should use prepend just in config.around but append for calls inside groups. I'll give it a try shortly.

fiber = FIBERS_STACK.pop
fiber.resume
end
end
end

RSpec.configure do |c|
c.extend RSpecAroundAll

# Add config.around(:all):
# c.extend overrides the original Object#extend method.
# See discussion in https://github.com/rspec/rspec-core/issues/1031#issuecomment-22264638
Object.instance_method(:extend).bind(c).call RSpecAroundAll
# Ruby 2 alternative:
# RSpec::Core::Configuration.send :prepend, RSpecAroundAll
end

50 changes: 50 additions & 0 deletions spec/rspec_around_all_spec.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
require_relative '../lib/rspec_around_all'

RSpec.configure do |c|
[:all, :all_nested].each do |all_type|
c.around(all_type) do |group|
(group.run_examples; next) unless order = group.metadata[:order]
count = group.metadata[:count][all_type] += 1
order << "config.before(:#{all_type}) #{count}"
group.run_examples
order << "config.after(:#{all_type}) #{count}"
end
end
end

module RSpec
module Core
describe "around(:all) hook" do
Expand Down Expand Up @@ -89,6 +101,44 @@ def self.transactionally
order.should eq([:before, :e1, :after, :before, :e2, :after])
end
end

describe "config.around(:all) hook", order: [], count: {all_nested: 0, all: 0} do
order = nil
context "part 1" do
around(:all) do |g|
order = g.metadata[:order]
order << 'inner.before(:all)'
g.run_examples
order << 'inner.after(:all)'
end

specify { order << 'first' }
specify { order << 'second' }

example "blocks are executed in the right order" do
expect(order).to eq [
'config.before(:all_nested) 1',
'config.before(:all) 1',
'config.before(:all_nested) 2',
'inner.before(:all)',
'first',
'second',
]
end
end

# this context won't pass if run alone (rspec -e "part 2") since it depends on part 1 to run before it

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's a different way you can structure this to avoid this problem: rather than creating nested example groups directly here, define an example that, within it, defines an example group with all the nesting that you need. You can define an example group (using ExampleGroup.describe) that contains both contexts and runs them all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That approach doesn't work either. Try to run the spec with rspec -e "around(:all) hook" and you'll see it doesn't work as expected.

context "part 2" do
example "before and after hooks order is correct" do
expect(order[-3..-1]).to eq [
'inner.after(:all)', # part 1
'config.after(:all_nested) 2', # inner config.around
'config.before(:all_nested) 3', # config.before part 2
]
end
end

end
end
end