module Interactor describe Hooks do describe "#with_hooks" do def build_hooked(&block) hooked = Class.new.send(:include, Interactor::Hooks) hooked.class_eval do attr_reader :steps def self.process new.tap(&:process).steps end def initialize @steps = [] end def process with_hooks { steps << :process } end end hooked.class_eval(&block) if block hooked end context "with an around hook method" do let(:hooked) { build_hooked do around :add_around_before_and_around_after private def add_around_before_and_around_after(hooked) steps << :around_before hooked.call steps << :around_after end end } it "runs the around hook method" do expect(hooked.process).to eq([ :around_before, :process, :around_after, ]) end end context "with an around hook block" do let(:hooked) { build_hooked do around do |hooked| steps << :around_before hooked.call steps << :around_after end end } it "runs the around hook block" do expect(hooked.process).to eq([ :around_before, :process, :around_after, ]) end end context "with an around hook method and block in one call" do let(:hooked) { build_hooked do around :add_around_before1_and_around_after1 do |hooked| steps << :around_before2 hooked.call steps << :around_after2 end private def add_around_before1_and_around_after1(hooked) steps << :around_before1 hooked.call steps << :around_after1 end end } it "runs the around hook method and block in order" do expect(hooked.process).to eq([ :around_before1, :around_before2, :process, :around_after2, :around_after1, ]) end end context "with an around hook method and block in multiple calls" do let(:hooked) { build_hooked do around do |hooked| steps << :around_before1 hooked.call steps << :around_after1 end around :add_around_before2_and_around_after2 private def add_around_before2_and_around_after2(hooked) steps << :around_before2 hooked.call steps << :around_after2 end end } it "runs the around hook block and method in order" do expect(hooked.process).to eq([ :around_before1, :around_before2, :process, :around_after2, :around_after1, ]) end end context "with a before hook method" do let(:hooked) { build_hooked do before :add_before private def add_before steps << :before end end } it "runs the before hook method" do expect(hooked.process).to eq([ :before, :process, ]) end end context "with a before hook block" do let(:hooked) { build_hooked do before do steps << :before end end } it "runs the before hook block" do expect(hooked.process).to eq([ :before, :process, ]) end end context "with a before hook method and block in one call" do let(:hooked) { build_hooked do before :add_before1 do steps << :before2 end private def add_before1 steps << :before1 end end } it "runs the before hook method and block in order" do expect(hooked.process).to eq([ :before1, :before2, :process, ]) end end context "with a before hook method and block in multiple calls" do let(:hooked) { build_hooked do before do steps << :before1 end before :add_before2 private def add_before2 steps << :before2 end end } it "runs the before hook block and method in order" do expect(hooked.process).to eq([ :before1, :before2, :process, ]) end end context "with an after hook method" do let(:hooked) { build_hooked do after :add_after private def add_after steps << :after end end } it "runs the after hook method" do expect(hooked.process).to eq([ :process, :after, ]) end end context "with an after hook block" do let(:hooked) { build_hooked do after do steps << :after end end } it "runs the after hook block" do expect(hooked.process).to eq([ :process, :after, ]) end end context "with an after hook method and block in one call" do let(:hooked) { build_hooked do after :add_after1 do steps << :after2 end private def add_after1 steps << :after1 end end } it "runs the after hook method and block in order" do expect(hooked.process).to eq([ :process, :after2, :after1, ]) end end context "with an after hook method and block in multiple calls" do let(:hooked) { build_hooked do after do steps << :after1 end after :add_after2 private def add_after2 steps << :after2 end end } it "runs the after hook block and method in order" do expect(hooked.process).to eq([ :process, :after2, :after1, ]) end end context "with around, before and after hooks" do let(:hooked) { build_hooked do around do |hooked| steps << :around_before1 hooked.call steps << :around_after1 end around do |hooked| steps << :around_before2 hooked.call steps << :around_after2 end before do steps << :before1 end before do steps << :before2 end after do steps << :after1 end after do steps << :after2 end end } it "runs hooks in the proper order" do expect(hooked.process).to eq([ :around_before1, :around_before2, :before1, :before2, :process, :after2, :after1, :around_after2, :around_after1, ]) end end end end end