Skip to content

Commit

Permalink
Don't use around hook for before/after hooks.
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed Jul 27, 2024
1 parent 7dc8963 commit 6f0fd4b
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 26 deletions.
12 changes: 10 additions & 2 deletions lib/sus/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,16 @@ def inspect
"\#<Sus::Base for #{self.class.description.inspect}>"
end

# A hook which is called before the test is executed.
#
# If you override this method, you must call super.
def before
end

def after
# A hook which is called after the test is executed.
#
# If you override this method, you must call super.
def after(error = nil)
end

# Wrap logic around the test being executed.
Expand All @@ -31,8 +37,10 @@ def around(&block)
self.before

return block.call
rescue => error
raise
ensure
self.after
self.after(error)
end

def assert(...)
Expand Down
27 changes: 12 additions & 15 deletions lib/sus/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,38 +78,35 @@ def each(&block)

# Include an around method to the context class, that invokes the given block before running the test.
#
# Before hooks are called in the reverse order they are defined, in other words the last defined before hook is called first.
# Before hooks are usually invoked in the order they are defined, i.e. the first defined hook is invoked first.
#
# @parameter hook [Proc] The block to execute before each test.
def before(&hook)
wrapper = Module.new

wrapper.define_method(:around) do |&block|
super() do
instance_exec(&hook)
block.call
end
wrapper.define_method(:before) do
super()

instance_exec(&hook)
end

self.include(wrapper)
end

# Include an around method to the context class, that invokes the given block after running the test.
#
# After hooks are called in the order they are defined, in other words the last defined after hook is called last.
# After hooks are usually invoked in the reverse order they are defined, i.e. the last defined hook is invoked first.
#
# @parameter hook [Proc] The block to execute after each test. An `error` argument is passed if the test failed with an exception.
def after(&hook)
wrapper = Module.new

wrapper.define_method(:around) do |&block|
super() do
block.call
rescue => error
raise
ensure
instance_exec(error, &hook)
end
wrapper.define_method(:after) do |error|
instance_exec(error, &hook)
rescue => error
raise
ensure
super(error)
end

self.include(wrapper)
Expand Down
2 changes: 1 addition & 1 deletion lib/sus/mock.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def wrap(method, &hook)
end

module Mocks
def after
def after(error = nil)
super

@mocks&.each_value(&:clear)
Expand Down
33 changes: 33 additions & 0 deletions test/sus/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,39 @@
it "has a full name" do
expect(instance.full_name).to be == "describe test"
end

with "before hooks" do
let(:events) {Array.new}

before do
events << :before1
end

before do
events << :before2
end

it "invokes before hooks" do
expect(events).to be == [:before1, :before2]
end
end

with "after hooks" do
let(:events) {Array.new}

after do
events << :after1
expect(events).to be == [:example, :after2, :after1]
end

after do
events << :after2
end

it "invokes after hooks" do
events << :example
end
end
end

describe Sus::With do
Expand Down
2 changes: 1 addition & 1 deletion test/sus/have.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def before
@socket = Socket.new(:INET, :STREAM)
end

def after
def after(error = nil)
@socket.close

super
Expand Down
59 changes: 53 additions & 6 deletions test/sus/include_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,23 @@

AContextWithHooks = Sus::Shared("a context with hooks") do
before do
events << :shared_before
events << :context_before
end

after do
events << :shared_after
events << :context_after
end

around do |&block|
events << :context_around_before

super() do
events << :shared_around_before

events << :context_around_super_before
block.call
events << :context_around_super_after
end

events << :context_around_after
end
end

Expand All @@ -35,7 +39,7 @@
end
end

with "a shared context with arguments" do
with "a shared context with hooks" do
let(:events) {Array.new}

include AContextWithHooks
Expand All @@ -44,8 +48,51 @@
events << :example_before
end

after do
events << :example_after
end

around do |&block|
events << :example_around_before

super() do
events << :example_around_super_before
block.call
events << :example_around_super_after
end

events << :example_around_after

# This is the full sequence of events:
expect(events).to be == [
:example_around_before,
:context_around_before,
:context_before,
:example_before,
:context_around_super_before,
:example_around_super_before,
:example,
:example_around_super_after,
:context_around_super_after,
:example_after,
:context_after,
:context_around_after,
:example_around_after,
]
end

it "can include a shared context" do
expect(events).to be == [:example_before, :shared_around_before, :shared_before]
events << :example

expect(events).to be == [
:example_around_before,
:context_around_before,
:context_before,
:example_before,
:context_around_super_before,
:example_around_super_before,
:example,
]
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion test/sus/it.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def before
self.before_hook_invoked = true
end

def after
def after(error = nil)
self.after_hook_invoked = true
end

Expand Down

0 comments on commit 6f0fd4b

Please sign in to comment.