activeinteractor 0.1.7 → 1.0.0.beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +36 -1
- data/README.md +397 -395
- data/lib/active_interactor.rb +12 -30
- data/lib/active_interactor/base.rb +18 -8
- data/lib/active_interactor/context.rb +4 -181
- data/lib/active_interactor/context/attributes.rb +37 -149
- data/lib/active_interactor/context/base.rb +141 -0
- data/lib/active_interactor/context/loader.rb +45 -0
- data/lib/active_interactor/error.rb +22 -15
- data/lib/active_interactor/interactor.rb +24 -57
- data/lib/active_interactor/interactor/callbacks.rb +64 -76
- data/lib/active_interactor/interactor/context.rb +97 -63
- data/lib/active_interactor/interactor/worker.rb +22 -65
- data/lib/active_interactor/organizer.rb +180 -164
- data/lib/active_interactor/version.rb +2 -3
- data/lib/rails/generators/active_interactor.rb +2 -37
- data/lib/rails/generators/active_interactor/application_interactor_generator.rb +23 -0
- data/lib/rails/generators/active_interactor/install_generator.rb +8 -12
- data/lib/rails/generators/active_interactor/templates/application_context.rb +4 -0
- data/lib/rails/generators/{templates/application_interactor.erb → active_interactor/templates/application_interactor.rb} +0 -0
- data/lib/rails/generators/active_interactor/templates/application_organizer.rb +4 -0
- data/lib/rails/generators/active_interactor/templates/initializer.erb +5 -0
- data/lib/rails/generators/interactor/context/rspec_generator.rb +19 -0
- data/lib/rails/generators/interactor/context/templates/rspec.erb +7 -0
- data/lib/rails/generators/interactor/context/templates/test_unit.erb +9 -0
- data/lib/rails/generators/interactor/context/test_unit_generator.rb +19 -0
- data/lib/rails/generators/interactor/context_generator.rb +19 -0
- data/lib/rails/generators/interactor/interactor_generator.rb +8 -3
- data/lib/rails/generators/interactor/organizer_generator.rb +8 -3
- data/lib/rails/generators/interactor/rspec_generator.rb +4 -3
- data/lib/rails/generators/interactor/templates/context.erb +4 -0
- data/lib/rails/generators/{templates → interactor/templates}/interactor.erb +0 -0
- data/lib/rails/generators/{templates → interactor/templates}/organizer.erb +1 -1
- data/lib/rails/generators/{templates → interactor/templates}/rspec.erb +0 -0
- data/lib/rails/generators/{templates → interactor/templates}/test_unit.erb +0 -0
- data/lib/rails/generators/interactor/test_unit_generator.rb +4 -3
- data/spec/active_interactor/base_spec.rb +51 -0
- data/spec/active_interactor/context/base_spec.rb +229 -0
- data/spec/active_interactor/error_spec.rb +43 -0
- data/spec/active_interactor/interactor/worker_spec.rb +89 -0
- data/spec/active_interactor/organizer_spec.rb +178 -0
- data/spec/active_interactor_spec.rb +26 -0
- data/spec/integration/basic_callback_integration_spec.rb +355 -0
- data/spec/integration/basic_context_integration_spec.rb +73 -0
- data/spec/integration/basic_integration_spec.rb +220 -0
- data/spec/integration/basic_validations_integration_spec.rb +204 -0
- data/spec/spec_helper.rb +44 -0
- data/spec/support/helpers/factories.rb +41 -0
- data/spec/support/shared_examples/a_class_with_interactor_callback_methods_example.rb +99 -0
- data/spec/support/shared_examples/a_class_with_interactor_context_methods_example.rb +58 -0
- data/spec/support/shared_examples/a_class_with_interactor_methods_example.rb +21 -0
- data/spec/support/shared_examples/a_class_with_organizer_callback_methods_example.rb +39 -0
- data/spec/support/spec_helpers.rb +7 -0
- metadata +68 -138
- data/lib/active_interactor/configuration.rb +0 -38
- data/lib/active_interactor/interactor/execution.rb +0 -24
- data/lib/rails/generators/templates/initializer.erb +0 -15
@@ -1,39 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
|
6
|
-
require 'active_interactor'
|
7
|
-
|
8
|
-
module ActiveInteractor
|
9
|
-
module Generators
|
10
|
-
module Generator
|
11
|
-
extend ActiveSupport::Concern
|
12
|
-
|
13
|
-
class_methods do
|
14
|
-
def base_root
|
15
|
-
__dir__
|
16
|
-
end
|
17
|
-
|
18
|
-
def source_root
|
19
|
-
File.expand_path('templates', __dir__)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def app_dir_name
|
24
|
-
ActiveInteractor.configuration.dir_name
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
class Base < ::Rails::Generators::Base
|
29
|
-
include Generator
|
30
|
-
end
|
31
|
-
|
32
|
-
class NamedBase < ::Rails::Generators::NamedBase
|
33
|
-
include Generator
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
Dir[File.expand_path('active_interactor/*.rb', __dir__)].each { |file| require file }
|
39
|
-
Dir[File.expand_path('interactor/*.rb', __dir__)].each { |file| require file }
|
3
|
+
Dir[File.expand_path('active_interactor/*.rb', __dir__)].sort.each { |file| require file }
|
4
|
+
Dir[File.expand_path('interactor/*.rb', __dir__)].sort.each { |file| require file }
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators/base'
|
4
|
+
|
5
|
+
module ActiveInteractor
|
6
|
+
module Generators
|
7
|
+
class ApplicationInteractorGenerator < ::Rails::Generators::Base
|
8
|
+
source_root File.expand_path('templates', __dir__)
|
9
|
+
|
10
|
+
def create_application_interactor
|
11
|
+
template 'application_interactor.rb', Rails.root.join('app', 'interactors', 'application_interactor.rb')
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_application_organizer
|
15
|
+
template 'application_organizer.rb', Rails.root.join('app', 'interactors', 'application_organizer.rb')
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_application_context
|
19
|
+
template 'application_context.rb', Rails.root.join('app', 'interactors', 'application_context.rb')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,30 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require 'rails/generators/base'
|
4
4
|
|
5
5
|
module ActiveInteractor
|
6
6
|
module Generators
|
7
|
-
class InstallGenerator < Base
|
7
|
+
class InstallGenerator < ::Rails::Generators::Base
|
8
|
+
source_root File.expand_path('templates', __dir__)
|
8
9
|
desc 'Install ActiveInteractor'
|
9
|
-
argument :directory, type: :string, default: 'interactors', banner: 'directory'
|
10
10
|
|
11
11
|
def create_initializer
|
12
12
|
template 'initializer.erb', Rails.root.join('config', 'initializers', 'active_interactor.rb')
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
def create_interactor_concerns
|
20
|
-
create_file Rails.root.join('app', directory, 'concerns', '.keep')
|
15
|
+
def create_application_interactor_and_context
|
16
|
+
generate :'active_interactor:application_interactor'
|
21
17
|
end
|
22
18
|
|
23
19
|
def autoload_interactors
|
24
20
|
application do
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
<<-CONFIG
|
22
|
+
# autoload interactors
|
23
|
+
config.autoload_paths += %w[app/interactors]
|
28
24
|
|
29
25
|
CONFIG
|
30
26
|
end
|
File without changes
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators/named_base'
|
4
|
+
|
5
|
+
module Interactor
|
6
|
+
module Context
|
7
|
+
module Generators
|
8
|
+
class RspecGenerator < ::Rails::Generators::NamedBase
|
9
|
+
source_root File.expand_path('templates', __dir__)
|
10
|
+
desc 'Generate an interactor spec'
|
11
|
+
|
12
|
+
def create_spec
|
13
|
+
file_path = Rails.root.join('spec/interactors', File.join(class_path), "#{file_name}_context_spec.rb")
|
14
|
+
template 'rspec.erb', file_path
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators/named_base'
|
4
|
+
|
5
|
+
module Interactor
|
6
|
+
module Context
|
7
|
+
module Generators
|
8
|
+
class TestUnitGenerator < ::Rails::Generators::NamedBase
|
9
|
+
source_root File.expand_path('templates', __dir__)
|
10
|
+
desc 'Generate an interactor unit test'
|
11
|
+
|
12
|
+
def create_test
|
13
|
+
file_path = Rails.root.join('test/interactors', File.join(class_path), "#{file_name}_context_test.rb")
|
14
|
+
template 'test_unit.erb', file_path
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators/named_base'
|
4
|
+
|
5
|
+
module Interactor
|
6
|
+
module Generators
|
7
|
+
class ContextGenerator < ::Rails::Generators::NamedBase
|
8
|
+
source_root File.expand_path('templates', __dir__)
|
9
|
+
desc 'Generate an interactor context'
|
10
|
+
argument :interactors, type: :array, default: [], banner: 'name name'
|
11
|
+
|
12
|
+
def create_context
|
13
|
+
template 'context.erb', Rails.root.join('app/interactors', File.join(class_path), "#{file_name}_context.rb")
|
14
|
+
end
|
15
|
+
|
16
|
+
hook_for :test_framework, in: :'interactor:context'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,12 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require 'rails/generators/named_base'
|
4
4
|
|
5
|
-
class InteractorGenerator <
|
5
|
+
class InteractorGenerator < ::Rails::Generators::NamedBase
|
6
|
+
source_root File.expand_path('templates', __dir__)
|
6
7
|
desc 'Generate an interactor'
|
7
8
|
|
8
9
|
def create_interactor
|
9
|
-
template 'interactor.erb', Rails.root.join('app',
|
10
|
+
template 'interactor.erb', Rails.root.join('app/interactors', File.join(class_path), "#{file_name}.rb")
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_context
|
14
|
+
generate :'interactor:context', class_name
|
10
15
|
end
|
11
16
|
|
12
17
|
hook_for :test_framework, in: :interactor
|
@@ -1,15 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require 'rails/generators/named_base'
|
4
4
|
|
5
5
|
module Interactor
|
6
6
|
module Generators
|
7
|
-
class OrganizerGenerator <
|
7
|
+
class OrganizerGenerator < ::Rails::Generators::NamedBase
|
8
|
+
source_root File.expand_path('templates', __dir__)
|
8
9
|
desc 'Generate an interactor organizer'
|
9
10
|
argument :interactors, type: :array, default: [], banner: 'name name'
|
10
11
|
|
11
12
|
def create_organizer
|
12
|
-
template 'organizer.erb', Rails.root.join('app',
|
13
|
+
template 'organizer.erb', Rails.root.join('app/interactors', File.join(class_path), "#{file_name}.rb")
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_context
|
17
|
+
generate :'interactor:context', class_name
|
13
18
|
end
|
14
19
|
|
15
20
|
hook_for :test_framework, in: :interactor
|
@@ -1,14 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require 'rails/generators/named_base'
|
4
4
|
|
5
5
|
module Interactor
|
6
6
|
module Generators
|
7
|
-
class RspecGenerator <
|
7
|
+
class RspecGenerator < ::Rails::Generators::NamedBase
|
8
|
+
source_root File.expand_path('templates', __dir__)
|
8
9
|
desc 'Generate an interactor spec'
|
9
10
|
|
10
11
|
def create_spec
|
11
|
-
template 'rspec.erb', Rails.root.join('spec',
|
12
|
+
template 'rspec.erb', Rails.root.join('spec/interactors', File.join(class_path), "#{file_name}_spec.rb")
|
12
13
|
end
|
13
14
|
end
|
14
15
|
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -1,14 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require 'rails/generators/named_base'
|
4
4
|
|
5
5
|
module Interactor
|
6
6
|
module Generators
|
7
|
-
class TestUnitGenerator <
|
7
|
+
class TestUnitGenerator < ::Rails::Generators::NamedBase
|
8
|
+
source_root File.expand_path('templates', __dir__)
|
8
9
|
desc 'Generate an interactor unit test'
|
9
10
|
|
10
11
|
def create_test
|
11
|
-
template 'test_unit.erb', Rails.root.join('test',
|
12
|
+
template 'test_unit.erb', Rails.root.join('test/interactors', File.join(class_path), "#{file_name}_test.rb")
|
12
13
|
end
|
13
14
|
end
|
14
15
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe ActiveInteractor::Base do
|
6
|
+
let(:interactor_class) { described_class }
|
7
|
+
include_examples 'a class with interactor methods'
|
8
|
+
include_examples 'a class with interactor callback methods'
|
9
|
+
include_examples 'a class with interactor context methods'
|
10
|
+
|
11
|
+
describe '.contextualize_with' do
|
12
|
+
subject { described_class.contextualize_with(klass) }
|
13
|
+
|
14
|
+
context 'with an class that does not exist' do
|
15
|
+
let(:klass) { 'SomeClassThatDoesNotExist' }
|
16
|
+
|
17
|
+
it { expect { subject }.to raise_error(ActiveInteractor::Error::InvalidContextClass) }
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'with context class TestContext' do
|
21
|
+
before { build_context }
|
22
|
+
|
23
|
+
context 'when passed as a string' do
|
24
|
+
let(:klass) { 'TestContext' }
|
25
|
+
|
26
|
+
it 'assigns the context class' do
|
27
|
+
subject
|
28
|
+
expect(described_class.context_class).to eq TestContext
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when passed as a symbol' do
|
33
|
+
let(:klass) { :test_context }
|
34
|
+
|
35
|
+
it 'assigns the context class' do
|
36
|
+
subject
|
37
|
+
expect(described_class.context_class).to eq TestContext
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when passed as a constant' do
|
42
|
+
let(:klass) { TestContext }
|
43
|
+
|
44
|
+
it 'assigns the context class' do
|
45
|
+
subject
|
46
|
+
expect(described_class.context_class).to eq TestContext
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,229 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe ActiveInteractor::Context::Base do
|
6
|
+
after(:each) { described_class.instance_variable_set('@__attributes', []) }
|
7
|
+
|
8
|
+
describe '#attributes' do
|
9
|
+
context 'when no arguments are passed' do
|
10
|
+
subject { described_class.attributes }
|
11
|
+
it { is_expected.to eq [] }
|
12
|
+
|
13
|
+
context 'when an attribute :foo was previously defined' do
|
14
|
+
before { described_class.instance_variable_set('@__attributes', %i[foo]) }
|
15
|
+
|
16
|
+
it { is_expected.to eq %i[foo] }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when given arguments :foo and :bar' do
|
21
|
+
subject { described_class.attributes(:foo, :bar) }
|
22
|
+
|
23
|
+
it { is_expected.to eq %i[bar foo] }
|
24
|
+
|
25
|
+
context 'when an attribute :foo was previously defined' do
|
26
|
+
before { described_class.instance_variable_set('@__attributes', %i[foo]) }
|
27
|
+
|
28
|
+
it { is_expected.to eq %i[bar foo] }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe '.attributes' do
|
34
|
+
subject { instance.attributes }
|
35
|
+
|
36
|
+
context 'with class attributes []' do
|
37
|
+
context 'with an instance having attributes { :foo => "foo", :bar => "bar", :baz => "baz" }' do
|
38
|
+
let(:instance) { described_class.new(foo: 'foo', bar: 'bar', baz: 'baz') }
|
39
|
+
|
40
|
+
it { is_expected.to be_a Hash }
|
41
|
+
it { is_expected.to be_empty }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'with class attributes [:foo, :bar, :baz]' do
|
46
|
+
before { described_class.attributes(:foo, :bar, :baz) }
|
47
|
+
|
48
|
+
context 'with an instance having attributes { :foo => "foo", :bar => "bar", :baz => "baz" }' do
|
49
|
+
let(:instance) { described_class.new(foo: 'foo', bar: 'bar', baz: 'baz') }
|
50
|
+
|
51
|
+
it { is_expected.to be_a Hash }
|
52
|
+
it { is_expected.to eq(bar: 'bar', baz: 'baz', foo: 'foo') }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '#called!' do
|
58
|
+
subject do
|
59
|
+
instance.called!(interactor1)
|
60
|
+
instance.called!(interactor2)
|
61
|
+
end
|
62
|
+
|
63
|
+
let(:instance) { described_class.new }
|
64
|
+
let(:interactor1) { double(:interactor1) }
|
65
|
+
let(:interactor2) { double(:interactor2) }
|
66
|
+
|
67
|
+
it 'is expected to append interactors to instance variable _called' do
|
68
|
+
expect { subject }.to change { instance.send(:_called) }
|
69
|
+
.from([])
|
70
|
+
.to([interactor1, interactor2])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '#fail!' do
|
75
|
+
subject { instance.fail!(errors) }
|
76
|
+
let(:instance) { described_class.new }
|
77
|
+
|
78
|
+
context 'with errors equal to nil' do
|
79
|
+
let(:errors) { nil }
|
80
|
+
|
81
|
+
it { expect { subject }.to raise_error(ActiveInteractor::Error::ContextFailure) }
|
82
|
+
|
83
|
+
it 'is expected not to merge errors' do
|
84
|
+
expect(instance.errors).not_to receive(:merge!)
|
85
|
+
subject
|
86
|
+
rescue ActiveInteractor::Error::ContextFailure # rubocop:disable Lint/SuppressedException
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'is expected to be a failure' do
|
90
|
+
subject
|
91
|
+
rescue ActiveInteractor::Error::ContextFailure
|
92
|
+
expect(instance).to be_a_failure
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'with errors from another instance on the attribute :foo' do
|
97
|
+
let(:errors) { instance2.errors }
|
98
|
+
let(:instance2) { described_class.new }
|
99
|
+
|
100
|
+
before { instance2.errors.add(:foo, 'foo') }
|
101
|
+
|
102
|
+
it { expect { subject }.to raise_error(ActiveInteractor::Error::ContextFailure) }
|
103
|
+
|
104
|
+
it 'is expected to merge errors' do
|
105
|
+
subject
|
106
|
+
rescue ActiveInteractor::Error::ContextFailure
|
107
|
+
expect(instance.errors[:foo]).to eq instance2.errors[:foo]
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'is expected to be a failure' do
|
111
|
+
subject
|
112
|
+
rescue ActiveInteractor::Error::ContextFailure
|
113
|
+
expect(instance).to be_a_failure
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'with errors "foo"' do
|
118
|
+
let(:errors) { 'foo' }
|
119
|
+
|
120
|
+
it { expect { subject }.to raise_error(ActiveInteractor::Error::ContextFailure) }
|
121
|
+
|
122
|
+
it 'is expected to have error on :context equal to "foo"' do
|
123
|
+
subject
|
124
|
+
rescue ActiveInteractor::Error::ContextFailure
|
125
|
+
expect(instance.errors[:context]).to include 'foo'
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'is expected to be a failure' do
|
129
|
+
subject
|
130
|
+
rescue ActiveInteractor::Error::ContextFailure
|
131
|
+
expect(instance).to be_a_failure
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe '#new' do
|
137
|
+
subject { described_class.new(attributes) }
|
138
|
+
|
139
|
+
context 'with a previous instance having attributes { :foo => "foo" }' do
|
140
|
+
let(:attributes) { described_class.new(foo: 'foo') }
|
141
|
+
|
142
|
+
it { is_expected.to be_a described_class }
|
143
|
+
it { is_expected.to have_attributes(foo: 'foo') }
|
144
|
+
|
145
|
+
context 'having instance variable @_called equal to ["foo"]' do
|
146
|
+
before { attributes.instance_variable_set('@_called', %w[foo]) }
|
147
|
+
|
148
|
+
it { is_expected.to be_a described_class }
|
149
|
+
it { is_expected.to have_attributes(foo: 'foo') }
|
150
|
+
it 'is expected to preserve @_called instance variable' do
|
151
|
+
expect(subject.instance_variable_get('@_called')).to eq %w[foo]
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'having instance variable @_failed equal to true' do
|
156
|
+
before { attributes.instance_variable_set('@_failed', true) }
|
157
|
+
|
158
|
+
it { is_expected.to be_a described_class }
|
159
|
+
it { is_expected.to have_attributes(foo: 'foo') }
|
160
|
+
it 'is expected to preserve @_failed instance variable' do
|
161
|
+
expect(subject.instance_variable_get('@_failed')).to eq true
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
context 'having instance variable @_rolled_back equal to true' do
|
166
|
+
before { attributes.instance_variable_set('@_rolled_back', true) }
|
167
|
+
|
168
|
+
it { is_expected.to be_a described_class }
|
169
|
+
it { is_expected.to have_attributes(foo: 'foo') }
|
170
|
+
it 'is expected to preserve @_rolled_back instance variable' do
|
171
|
+
expect(subject.instance_variable_get('@_rolled_back')).to eq true
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe '#failure?' do
|
178
|
+
subject { instance.failure? }
|
179
|
+
let(:instance) { described_class.new }
|
180
|
+
|
181
|
+
it { is_expected.to eq false }
|
182
|
+
|
183
|
+
context 'when context has failed' do
|
184
|
+
before { instance.instance_variable_set('@_failed', true) }
|
185
|
+
|
186
|
+
it { is_expected.to eq true }
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
describe '#rollback!' do
|
191
|
+
subject { instance.rollback! }
|
192
|
+
let(:instance) { described_class.new }
|
193
|
+
|
194
|
+
context 'with #called! interactors' do
|
195
|
+
let(:interactor1) { double(:interactor1) }
|
196
|
+
let(:interactor2) { double(:interactor2) }
|
197
|
+
|
198
|
+
before do
|
199
|
+
allow(instance).to receive(:_called).and_return([interactor1, interactor2])
|
200
|
+
end
|
201
|
+
|
202
|
+
it 'is expected to rollback each interactor in reverse order' do
|
203
|
+
expect(interactor2).to receive(:rollback).once.with(no_args).ordered
|
204
|
+
expect(interactor1).to receive(:rollback).once.with(no_args).ordered
|
205
|
+
subject
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'is expected to ignore subsequent attempts' do
|
209
|
+
expect(interactor2).to receive(:rollback).once
|
210
|
+
expect(interactor1).to receive(:rollback).once
|
211
|
+
subject
|
212
|
+
subject
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
describe '#success?' do
|
218
|
+
subject { instance.success? }
|
219
|
+
let(:instance) { described_class.new }
|
220
|
+
|
221
|
+
it { is_expected.to eq true }
|
222
|
+
|
223
|
+
context 'when context has failed' do
|
224
|
+
before { instance.instance_variable_set('@_failed', true) }
|
225
|
+
|
226
|
+
it { is_expected.to eq false }
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|