RSpec.describe Dry::Transaction::StepAdapters::Try do subject { described_class.new } let(:operation) { -> (input) { raise(Test::NotValidError, 'not a string') unless input.is_a? String input.upcase } } let(:step) { Dry::Transaction::Step.new(subject, :step, :step, operation, options) } let(:options) { { catch: Test::NotValidError } } before do Test::NotValidError = Class.new(StandardError) Test::BetterNamingError = Class.new(StandardError) end describe "#call" do context "without the :catch option" do let(:options) { { } } it "raises an ArgumentError" do expect do subject.call(step, {}) end.to raise_error(ArgumentError) end end context "with the :catch option" do context "when the error was raised" do it "return a Left Monad" do expect(subject.call(step, 1234)).to be_a Dry::Monads::Either::Left end it "return the raised error as output" do result = subject.call(step, 1234) expect(result.value).to be_a Test::NotValidError expect(result.value.message).to eql 'not a string' end context "when using the :raise option" do let(:options) { { catch: Test::NotValidError, raise: Test::BetterNamingError } } it "return a Left Monad" do expect(subject.call(step, 1234)).to be_a Dry::Monads::Either::Left end it "return the error specified by :raise as output" do result = subject.call(step, 1234) expect(result.value).to be_a Test::BetterNamingError expect(result.value.message).to eql 'not a string' end end end context "when the error was NOT raised" do it "return a Right Monad" do expect(subject.call(step, 'input')).to be_a Dry::Monads::Either::Right end it "return the result of the operation as output" do expect(subject.call(step, 'input').value).to eql 'INPUT' end context "when using the :raise option" do let(:options) { { catch: Test::NotValidError, raise: Test::BetterNamingError } } it "return a Right Monad" do expect(subject.call(step, 'input')).to be_a Dry::Monads::Either::Right end it "return the result of the operation as output" do expect(subject.call(step, 'input').value).to eql 'INPUT' end end end end end end