spec/integration_spec.rb in interactor-3.0.1 vs spec/integration_spec.rb in interactor-3.1.0

- old
+ new

@@ -24,10 +24,16 @@ # │ └─ interactor4c # └─ interactor5 let(:organizer) { build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do + around do |interactor| + context.steps << :around_before + interactor.call + context.steps << :around_after + end + before do context.steps << :before end after do @@ -36,10 +42,16 @@ end } let(:organizer2) { build_organizer(organize: [interactor2a, interactor2b, interactor2c]) do + around do |interactor| + context.steps << :around_before2 + interactor.call + context.steps << :around_after2 + end + before do context.steps << :before2 end after do @@ -48,10 +60,16 @@ end } let(:interactor2a) { build_interactor do + around do |interactor| + context.steps << :around_before2a + interactor.call + context.steps << :around_after2a + end + before do context.steps << :before2a end after do @@ -68,10 +86,16 @@ end } let(:interactor2b) { build_interactor do + around do |interactor| + context.steps << :around_before2b + interactor.call + context.steps << :around_after2b + end + before do context.steps << :before2b end after do @@ -88,10 +112,16 @@ end } let(:interactor2c) { build_interactor do + around do |interactor| + context.steps << :around_before2c + interactor.call + context.steps << :around_after2c + end + before do context.steps << :before2c end after do @@ -108,10 +138,16 @@ end } let(:interactor3) { build_interactor do + around do |interactor| + context.steps << :around_before3 + interactor.call + context.steps << :around_after3 + end + before do context.steps << :before3 end after do @@ -128,10 +164,16 @@ end } let(:organizer4) { build_organizer(organize: [interactor4a, interactor4b, interactor4c]) do + around do |interactor| + context.steps << :around_before4 + interactor.call + context.steps << :around_after4 + end + before do context.steps << :before4 end after do @@ -140,10 +182,16 @@ end } let(:interactor4a) { build_interactor do + around do |interactor| + context.steps << :around_before4a + interactor.call + context.steps << :around_after4a + end + before do context.steps << :before4a end after do @@ -160,10 +208,16 @@ end } let(:interactor4b) { build_interactor do + around do |interactor| + context.steps << :around_before4b + interactor.call + context.steps << :around_after4b + end + before do context.steps << :before4b end after do @@ -180,10 +234,16 @@ end } let(:interactor4c) { build_interactor do + around do |interactor| + context.steps << :around_before4c + interactor.call + context.steps << :around_after4c + end + before do context.steps << :before4c end after do @@ -200,10 +260,16 @@ end } let(:interactor5) { build_interactor do + around do |interactor| + context.steps << :around_before5 + interactor.call + context.steps << :around_after5 + end + before do context.steps << :before5 end after do @@ -218,40 +284,47 @@ context.steps << :rollback5 end end } - let(:context) { Interactor::Context.build(steps: []) } + let(:context) { Interactor::Context.new(steps: []) } context "when successful" do it "calls and runs hooks in the proper sequence" do expect { organizer.call(context) }.to change { context.steps }.from([]).to([ - :before, - :before2, - :before2a, :call2a, :after2a, - :before2b, :call2b, :after2b, - :before2c, :call2c, :after2c, - :after2, - :before3, :call3, :after3, - :before4, - :before4a, :call4a, :after4a, - :before4b, :call4b, :after4b, - :before4c, :call4c, :after4c, - :after4, - :before5, :call5, :after5, - :after + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :call3, :after3, :around_after3, + :around_before4, :before4, + :around_before4a, :before4a, :call4a, :after4a, :around_after4a, + :around_before4b, :before4b, :call4b, :after4b, :around_after4b, + :around_before4c, :before4c, :call4c, :after4c, :around_after4c, + :after4, :around_after4, + :around_before5, :before5, :call5, :after5, :around_after5, + :after, :around_after ]) end end - context "when a before hook fails" do + context "when an around hook fails early" do let(:organizer) { build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do + around do |interactor| + context.fail! + context.steps << :around_before + interactor.call + context.steps << :around_after + end + before do context.fail! context.steps << :before end @@ -268,15 +341,22 @@ context.steps } end end - context "when a before hook errors" do + context "when an around hook errors early" do let(:organizer) { build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do - before do + around do |interactor| raise "foo" + context.steps << :around_before + interactor.call + context.steps << :around_after + end + + before do + context.fail! context.steps << :before end after do context.steps << :after @@ -297,13 +377,87 @@ organizer.call(context) }.to raise_error("foo") end end + context "when a before hook fails" do + let(:organizer) { + build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do + around do |interactor| + context.steps << :around_before + interactor.call + context.steps << :around_after + end + + before do + context.fail! + context.steps << :before + end + + after do + context.steps << :after + end + end + } + + it "aborts" do + expect { + organizer.call(context) + }.to change { + context.steps + }.from([]).to([ + :around_before + ]) + end + end + + context "when a before hook errors" do + let(:organizer) { + build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do + around do |interactor| + context.steps << :around_before + interactor.call + context.steps << :around_after + end + + before do + raise "foo" + context.steps << :before + end + + after do + context.steps << :after + end + end + } + + it "aborts" do + expect { + organizer.call(context) rescue nil + }.to change { + context.steps + }.from([]).to([ + :around_before + ]) + end + + it "raises the error" do + expect { + organizer.call(context) + }.to raise_error("foo") + end + end + context "when an after hook fails" do let(:organizer) { build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do + around do |interactor| + context.steps << :around_before + interactor.call + context.steps << :around_after + end + before do context.steps << :before end after do @@ -311,29 +465,29 @@ context.steps << :after end end } - it "rolls back successfully called interactors" do + it "rolls back successfully called interactors and the failed interactor" do expect { organizer.call(context) }.to change { context.steps }.from([]).to([ - :before, - :before2, - :before2a, :call2a, :after2a, - :before2b, :call2b, :after2b, - :before2c, :call2c, :after2c, - :after2, - :before3, :call3, :after3, - :before4, - :before4a, :call4a, :after4a, - :before4b, :call4b, :after4b, - :before4c, :call4c, :after4c, - :after4, - :before5, :call5, :after5, + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :call3, :after3, :around_after3, + :around_before4, :before4, + :around_before4a, :before4a, :call4a, :after4a, :around_after4a, + :around_before4b, :before4b, :call4b, :after4b, :around_after4b, + :around_before4c, :before4c, :call4c, :after4c, :around_after4c, + :after4, :around_after4, + :around_before5, :before5, :call5, :after5, :around_after5, :rollback5, :rollback4c, :rollback4b, :rollback4a, :rollback3, @@ -345,10 +499,16 @@ end context "when an after hook errors" do let(:organizer) { build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do + around do |interactor| + context.steps << :around_before + interactor.call + context.steps << :around_after + end + before do context.steps << :before end after do @@ -356,29 +516,29 @@ context.steps << :after end end } - it "aborts" do + it "rolls back successfully called interactors and the failed interactor" do expect { organizer.call(context) rescue nil }.to change { context.steps }.from([]).to([ - :before, - :before2, - :before2a, :call2a, :after2a, - :before2b, :call2b, :after2b, - :before2c, :call2c, :after2c, - :after2, - :before3, :call3, :after3, - :before4, - :before4a, :call4a, :after4a, - :before4b, :call4b, :after4b, - :before4c, :call4c, :after4c, - :after4, - :before5, :call5, :after5, + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :call3, :after3, :around_after3, + :around_before4, :before4, + :around_before4a, :before4a, :call4a, :after4a, :around_after4a, + :around_before4b, :before4b, :call4b, :after4b, :around_after4b, + :around_before4c, :before4c, :call4c, :after4c, :around_after4c, + :after4, :around_after4, + :around_before5, :before5, :call5, :after5, :around_after5, :rollback5, :rollback4c, :rollback4b, :rollback4a, :rollback3, @@ -393,13 +553,229 @@ organizer.call(context) }.to raise_error("foo") end end + context "when an around hook fails late" do + let(:organizer) { + build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do + around do |interactor| + context.steps << :around_before + interactor.call + context.fail! + context.steps << :around_after + end + + before do + context.steps << :before + end + + after do + context.steps << :after + end + end + } + + it "rolls back successfully called interactors and the failed interactor" do + expect { + organizer.call(context) + }.to change { + context.steps + }.from([]).to([ + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :call3, :after3, :around_after3, + :around_before4, :before4, + :around_before4a, :before4a, :call4a, :after4a, :around_after4a, + :around_before4b, :before4b, :call4b, :after4b, :around_after4b, + :around_before4c, :before4c, :call4c, :after4c, :around_after4c, + :after4, :around_after4, + :around_before5, :before5, :call5, :after5, :around_after5, + :after, + :rollback5, + :rollback4c, + :rollback4b, + :rollback4a, + :rollback3, + :rollback2c, + :rollback2b, + :rollback2a + ]) + end + end + + context "when an around hook errors late" do + let(:organizer) { + build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do + around do |interactor| + context.steps << :around_before + interactor.call + raise "foo" + context.steps << :around_after + end + + before do + context.steps << :before + end + + after do + context.steps << :after + end + end + } + + it "rolls back successfully called interactors and the failed interactor" do + expect { + organizer.call(context) rescue nil + }.to change { + context.steps + }.from([]).to([ + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :call3, :after3, :around_after3, + :around_before4, :before4, + :around_before4a, :before4a, :call4a, :after4a, :around_after4a, + :around_before4b, :before4b, :call4b, :after4b, :around_after4b, + :around_before4c, :before4c, :call4c, :after4c, :around_after4c, + :after4, :around_after4, + :around_before5, :before5, :call5, :after5, :around_after5, + :after, + :rollback5, + :rollback4c, + :rollback4b, + :rollback4a, + :rollback3, + :rollback2c, + :rollback2b, + :rollback2a + ]) + end + + it "raises the error" do + expect { + organizer.call(context) + }.to raise_error("foo") + end + end + + context "when a nested around hook fails early" do + let(:interactor3) { + build_interactor do + around do |interactor| + context.fail! + context.steps << :around_before3 + interactor.call + context.steps << :around_after3 + end + + before do + context.steps << :before3 + end + + after do + context.steps << :after3 + end + + def call + context.steps << :call3 + end + + def rollback + context.steps << :rollback3 + end + end + } + + it "rolls back successfully called interactors" do + expect { + organizer.call(context) + }.to change { + context.steps + }.from([]).to([ + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :rollback2c, + :rollback2b, + :rollback2a + ]) + end + end + + context "when a nested around hook errors early" do + let(:interactor3) { + build_interactor do + around do |interactor| + raise "foo" + context.steps << :around_before3 + interactor.call + context.steps << :around_after3 + end + + before do + context.steps << :before3 + end + + after do + context.steps << :after3 + end + + def call + context.steps << :call3 + end + + def rollback + context.steps << :rollback3 + end + end + } + + it "rolls back successfully called interactors" do + expect { + organizer.call(context) rescue nil + }.to change { + context.steps + }.from([]).to([ + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :rollback2c, + :rollback2b, + :rollback2a + ]) + end + + it "raises the error" do + expect { + organizer.call(context) + }.to raise_error("foo") + end + end + context "when a nested before hook fails" do let(:interactor3) { build_interactor do + around do |interactor| + context.steps << :around_before3 + interactor.call + context.steps << :around_after3 + end + before do context.fail! context.steps << :before3 end @@ -421,26 +797,33 @@ expect { organizer.call(context) }.to change { context.steps }.from([]).to([ - :before, - :before2, - :before2a, :call2a, :after2a, - :before2b, :call2b, :after2b, - :before2c, :call2c, :after2c, - :after2, + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :rollback2c, :rollback2b, :rollback2a ]) end end context "when a nested before hook errors" do let(:interactor3) { build_interactor do + around do |interactor| + context.steps << :around_before3 + interactor.call + context.steps << :around_after3 + end + before do raise "foo" context.steps << :before3 end @@ -462,16 +845,17 @@ expect { organizer.call(context) rescue nil }.to change { context.steps }.from([]).to([ - :before, - :before2, - :before2a, :call2a, :after2a, - :before2b, :call2b, :after2b, - :before2c, :call2c, :after2c, - :after2, + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :rollback2c, :rollback2b, :rollback2a ]) end @@ -484,10 +868,16 @@ end context "when a nested call fails" do let(:interactor3) { build_interactor do + around do |interactor| + context.steps << :around_before3 + interactor.call + context.steps << :around_after3 + end + before do context.steps << :before3 end after do @@ -509,27 +899,33 @@ expect { organizer.call(context) }.to change { context.steps }.from([]).to([ - :before, - :before2, - :before2a, :call2a, :after2a, - :before2b, :call2b, :after2b, - :before2c, :call2c, :after2c, - :after2, - :before3, + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :rollback2c, :rollback2b, :rollback2a ]) end end context "when a nested call errors" do let(:interactor3) { build_interactor do + around do |interactor| + context.steps << :around_before3 + interactor.call + context.steps << :around_after3 + end + before do context.steps << :before3 end after do @@ -551,17 +947,17 @@ expect { organizer.call(context) rescue nil }.to change { context.steps }.from([]).to([ - :before, - :before2, - :before2a, :call2a, :after2a, - :before2b, :call2b, :after2b, - :before2c, :call2c, :after2c, - :after2, - :before3, + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :rollback2c, :rollback2b, :rollback2a ]) end @@ -574,10 +970,16 @@ end context "when a nested after hook fails" do let(:interactor3) { build_interactor do + around do |interactor| + context.steps << :around_before3 + interactor.call + context.steps << :around_after3 + end + before do context.steps << :before3 end after do @@ -599,17 +1001,17 @@ expect { organizer.call(context) }.to change { context.steps }.from([]).to([ - :before, - :before2, - :before2a, :call2a, :after2a, - :before2b, :call2b, :after2b, - :before2c, :call2c, :after2c, - :after2, - :before3, :call3, + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :call3, :rollback3, :rollback2c, :rollback2b, :rollback2a ]) @@ -617,10 +1019,16 @@ end context "when a nested after hook errors" do let(:interactor3) { build_interactor do + around do |interactor| + context.steps << :around_before3 + interactor.call + context.steps << :around_after3 + end + before do context.steps << :before3 end after do @@ -642,17 +1050,17 @@ expect { organizer.call(context) rescue nil }.to change { context.steps }.from([]).to([ - :before, - :before2, - :before2a, :call2a, :after2a, - :before2b, :call2b, :after2b, - :before2c, :call2c, :after2c, - :after2, - :before3, :call3, + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :call3, :rollback3, :rollback2c, :rollback2b, :rollback2a ]) @@ -663,13 +1071,233 @@ organizer.call(context) }.to raise_error("foo") end end + context "when a nested around hook fails late" do + let(:interactor3) { + build_interactor do + around do |interactor| + context.steps << :around_before3 + interactor.call + context.fail! + context.steps << :around_after3 + end + + before do + context.steps << :before3 + end + + after do + context.steps << :after3 + end + + def call + context.steps << :call3 + end + + def rollback + context.steps << :rollback3 + end + end + } + + it "rolls back successfully called interactors and the failed interactor" do + expect { + organizer.call(context) + }.to change { + context.steps + }.from([]).to([ + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :call3, :after3, + :rollback3, + :rollback2c, + :rollback2b, + :rollback2a + ]) + end + end + + context "when a nested around hook errors late" do + let(:interactor3) { + build_interactor do + around do |interactor| + context.steps << :around_before3 + interactor.call + raise "foo" + context.steps << :around_after3 + end + + before do + context.steps << :before3 + end + + after do + context.steps << :after3 + end + + def call + context.steps << :call3 + end + + def rollback + context.steps << :rollback3 + end + end + } + + it "rolls back successfully called interactors and the failed interactor" do + expect { + organizer.call(context) rescue nil + }.to change { + context.steps + }.from([]).to([ + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :call3, :after3, + :rollback3, + :rollback2c, + :rollback2b, + :rollback2a + ]) + end + + it "raises the error" do + expect { + organizer.call(context) + }.to raise_error("foo") + end + end + + context "when a deeply nested around hook fails early" do + let(:interactor4b) { + build_interactor do + around do |interactor| + context.fail! + context.steps << :around_before4b + interactor.call + context.steps << :around_after4b + end + + before do + context.steps << :before4b + end + + after do + context.steps << :after4b + end + + def call + context.steps << :call4b + end + + def rollback + context.steps << :rollback4b + end + end + } + + it "rolls back successfully called interactors" do + expect { + organizer.call(context) + }.to change { + context.steps + }.from([]).to([ + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :call3, :after3, :around_after3, + :around_before4, :before4, + :around_before4a, :before4a, :call4a, :after4a, :around_after4a, + :rollback4a, + :rollback3, + :rollback2c, + :rollback2b, + :rollback2a + ]) + end + end + + context "when a deeply nested around hook errors early" do + let(:interactor4b) { + build_interactor do + around do |interactor| + raise "foo" + context.steps << :around_before4b + interactor.call + context.steps << :around_after4b + end + + before do + context.steps << :before4b + end + + after do + context.steps << :after4b + end + + def call + context.steps << :call4b + end + + def rollback + context.steps << :rollback4b + end + end + } + + it "rolls back successfully called interactors" do + expect { + organizer.call(context) rescue nil + }.to change { + context.steps + }.from([]).to([ + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :call3, :after3, :around_after3, + :around_before4, :before4, + :around_before4a, :before4a, :call4a, :after4a, :around_after4a, + :rollback4a, + :rollback3, + :rollback2c, + :rollback2b, + :rollback2a + ]) + end + + it "raises the error" do + expect { + organizer.call(context) + }.to raise_error("foo") + end + end + context "when a deeply nested before hook fails" do let(:interactor4b) { build_interactor do + around do |interactor| + context.steps << :around_before4b + interactor.call + context.steps << :around_after4b + end + before do context.fail! context.steps << :before4b end @@ -691,19 +1319,20 @@ expect { organizer.call(context) }.to change { context.steps }.from([]).to([ - :before, - :before2, - :before2a, :call2a, :after2a, - :before2b, :call2b, :after2b, - :before2c, :call2c, :after2c, - :after2, - :before3, :call3, :after3, - :before4, - :before4a, :call4a, :after4a, + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :call3, :after3, :around_after3, + :around_before4, :before4, + :around_before4a, :before4a, :call4a, :after4a, :around_after4a, + :around_before4b, :rollback4a, :rollback3, :rollback2c, :rollback2b, :rollback2a @@ -712,10 +1341,16 @@ end context "when a deeply nested before hook errors" do let(:interactor4b) { build_interactor do + around do |interactor| + context.steps << :around_before4b + interactor.call + context.steps << :around_after4b + end + before do raise "foo" context.steps << :before4b end @@ -737,19 +1372,20 @@ expect { organizer.call(context) rescue nil }.to change { context.steps }.from([]).to([ - :before, - :before2, - :before2a, :call2a, :after2a, - :before2b, :call2b, :after2b, - :before2c, :call2c, :after2c, - :after2, - :before3, :call3, :after3, - :before4, - :before4a, :call4a, :after4a, + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :call3, :after3, :around_after3, + :around_before4, :before4, + :around_before4a, :before4a, :call4a, :after4a, :around_after4a, + :around_before4b, :rollback4a, :rollback3, :rollback2c, :rollback2b, :rollback2a @@ -764,10 +1400,16 @@ end context "when a deeply nested call fails" do let(:interactor4b) { build_interactor do + around do |interactor| + context.steps << :around_before4b + interactor.call + context.steps << :around_after4b + end + before do context.steps << :before4b end after do @@ -789,20 +1431,20 @@ expect { organizer.call(context) }.to change { context.steps }.from([]).to([ - :before, - :before2, - :before2a, :call2a, :after2a, - :before2b, :call2b, :after2b, - :before2c, :call2c, :after2c, - :after2, - :before3, :call3, :after3, - :before4, - :before4a, :call4a, :after4a, - :before4b, + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :call3, :after3, :around_after3, + :around_before4, :before4, + :around_before4a, :before4a, :call4a, :after4a, :around_after4a, + :around_before4b, :before4b, :rollback4a, :rollback3, :rollback2c, :rollback2b, :rollback2a @@ -811,10 +1453,16 @@ end context "when a deeply nested call errors" do let(:interactor4b) { build_interactor do + around do |interactor| + context.steps << :around_before4b + interactor.call + context.steps << :around_after4b + end + before do context.steps << :before4b end after do @@ -836,20 +1484,20 @@ expect { organizer.call(context) rescue nil }.to change { context.steps }.from([]).to([ - :before, - :before2, - :before2a, :call2a, :after2a, - :before2b, :call2b, :after2b, - :before2c, :call2c, :after2c, - :after2, - :before3, :call3, :after3, - :before4, - :before4a, :call4a, :after4a, - :before4b, + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :call3, :after3, :around_after3, + :around_before4, :before4, + :around_before4a, :before4a, :call4a, :after4a, :around_after4a, + :around_before4b, :before4b, :rollback4a, :rollback3, :rollback2c, :rollback2b, :rollback2a @@ -864,10 +1512,16 @@ end context "when a deeply nested after hook fails" do let(:interactor4b) { build_interactor do + around do |interactor| + context.steps << :around_before4b + interactor.call + context.steps << :around_after4b + end + before do context.steps << :before4b end after do @@ -889,20 +1543,20 @@ expect { organizer.call(context) }.to change { context.steps }.from([]).to([ - :before, - :before2, - :before2a, :call2a, :after2a, - :before2b, :call2b, :after2b, - :before2c, :call2c, :after2c, - :after2, - :before3, :call3, :after3, - :before4, - :before4a, :call4a, :after4a, - :before4b, :call4b, + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :call3, :after3, :around_after3, + :around_before4, :before4, + :around_before4a, :before4a, :call4a, :after4a, :around_after4a, + :around_before4b, :before4b, :call4b, :rollback4b, :rollback4a, :rollback3, :rollback2c, :rollback2b, @@ -912,10 +1566,16 @@ end context "when a deeply nested after hook errors" do let(:interactor4b) { build_interactor do + around do |interactor| + context.steps << :around_before4b + interactor.call + context.steps << :around_after4b + end + before do context.steps << :before4b end after do @@ -937,19 +1597,133 @@ expect { organizer.call(context) rescue nil }.to change { context.steps }.from([]).to([ - :before, - :before2, - :before2a, :call2a, :after2a, - :before2b, :call2b, :after2b, - :before2c, :call2c, :after2c, - :after2, - :before3, :call3, :after3, - :before4, - :before4a, :call4a, :after4a, - :before4b, :call4b, + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :call3, :after3, :around_after3, + :around_before4, :before4, + :around_before4a, :before4a, :call4a, :after4a, :around_after4a, + :around_before4b, :before4b, :call4b, + :rollback4b, + :rollback4a, + :rollback3, + :rollback2c, + :rollback2b, + :rollback2a + ]) + end + + it "raises the error" do + expect { + organizer.call(context) + }.to raise_error("foo") + end + end + + context "when a deeply nested around hook fails late" do + let(:interactor4b) { + build_interactor do + around do |interactor| + context.steps << :around_before4b + interactor.call + context.fail! + context.steps << :around_after4b + end + + before do + context.steps << :before4b + end + + after do + context.steps << :after4b + end + + def call + context.steps << :call4b + end + + def rollback + context.steps << :rollback4b + end + end + } + + it "rolls back successfully called interactors and the failed interactor" do + expect { + organizer.call(context) + }.to change { + context.steps + }.from([]).to([ + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :call3, :after3, :around_after3, + :around_before4, :before4, + :around_before4a, :before4a, :call4a, :after4a, :around_after4a, + :around_before4b, :before4b, :call4b, :after4b, + :rollback4b, + :rollback4a, + :rollback3, + :rollback2c, + :rollback2b, + :rollback2a + ]) + end + end + + context "when a deeply nested around hook errors late" do + let(:interactor4b) { + build_interactor do + around do |interactor| + context.steps << :around_before4b + interactor.call + raise "foo" + context.steps << :around_after4b + end + + before do + context.steps << :before4b + end + + after do + context.steps << :after4b + end + + def call + context.steps << :call4b + end + + def rollback + context.steps << :rollback4b + end + end + } + + it "rolls back successfully called interactors and the failed interactor" do + expect { + organizer.call(context) rescue nil + }.to change { + context.steps + }.from([]).to([ + :around_before, :before, + :around_before2, :before2, + :around_before2a, :before2a, :call2a, :after2a, :around_after2a, + :around_before2b, :before2b, :call2b, :after2b, :around_after2b, + :around_before2c, :before2c, :call2c, :after2c, :around_after2c, + :after2, :around_after2, + :around_before3, :before3, :call3, :after3, :around_after3, + :around_before4, :before4, + :around_before4a, :before4a, :call4a, :after4a, :around_after4a, + :around_before4b, :before4b, :call4b, :after4b, :rollback4b, :rollback4a, :rollback3, :rollback2c, :rollback2b,