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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -1
  3. data/README.md +397 -395
  4. data/lib/active_interactor.rb +12 -30
  5. data/lib/active_interactor/base.rb +18 -8
  6. data/lib/active_interactor/context.rb +4 -181
  7. data/lib/active_interactor/context/attributes.rb +37 -149
  8. data/lib/active_interactor/context/base.rb +141 -0
  9. data/lib/active_interactor/context/loader.rb +45 -0
  10. data/lib/active_interactor/error.rb +22 -15
  11. data/lib/active_interactor/interactor.rb +24 -57
  12. data/lib/active_interactor/interactor/callbacks.rb +64 -76
  13. data/lib/active_interactor/interactor/context.rb +97 -63
  14. data/lib/active_interactor/interactor/worker.rb +22 -65
  15. data/lib/active_interactor/organizer.rb +180 -164
  16. data/lib/active_interactor/version.rb +2 -3
  17. data/lib/rails/generators/active_interactor.rb +2 -37
  18. data/lib/rails/generators/active_interactor/application_interactor_generator.rb +23 -0
  19. data/lib/rails/generators/active_interactor/install_generator.rb +8 -12
  20. data/lib/rails/generators/active_interactor/templates/application_context.rb +4 -0
  21. data/lib/rails/generators/{templates/application_interactor.erb → active_interactor/templates/application_interactor.rb} +0 -0
  22. data/lib/rails/generators/active_interactor/templates/application_organizer.rb +4 -0
  23. data/lib/rails/generators/active_interactor/templates/initializer.erb +5 -0
  24. data/lib/rails/generators/interactor/context/rspec_generator.rb +19 -0
  25. data/lib/rails/generators/interactor/context/templates/rspec.erb +7 -0
  26. data/lib/rails/generators/interactor/context/templates/test_unit.erb +9 -0
  27. data/lib/rails/generators/interactor/context/test_unit_generator.rb +19 -0
  28. data/lib/rails/generators/interactor/context_generator.rb +19 -0
  29. data/lib/rails/generators/interactor/interactor_generator.rb +8 -3
  30. data/lib/rails/generators/interactor/organizer_generator.rb +8 -3
  31. data/lib/rails/generators/interactor/rspec_generator.rb +4 -3
  32. data/lib/rails/generators/interactor/templates/context.erb +4 -0
  33. data/lib/rails/generators/{templates → interactor/templates}/interactor.erb +0 -0
  34. data/lib/rails/generators/{templates → interactor/templates}/organizer.erb +1 -1
  35. data/lib/rails/generators/{templates → interactor/templates}/rspec.erb +0 -0
  36. data/lib/rails/generators/{templates → interactor/templates}/test_unit.erb +0 -0
  37. data/lib/rails/generators/interactor/test_unit_generator.rb +4 -3
  38. data/spec/active_interactor/base_spec.rb +51 -0
  39. data/spec/active_interactor/context/base_spec.rb +229 -0
  40. data/spec/active_interactor/error_spec.rb +43 -0
  41. data/spec/active_interactor/interactor/worker_spec.rb +89 -0
  42. data/spec/active_interactor/organizer_spec.rb +178 -0
  43. data/spec/active_interactor_spec.rb +26 -0
  44. data/spec/integration/basic_callback_integration_spec.rb +355 -0
  45. data/spec/integration/basic_context_integration_spec.rb +73 -0
  46. data/spec/integration/basic_integration_spec.rb +220 -0
  47. data/spec/integration/basic_validations_integration_spec.rb +204 -0
  48. data/spec/spec_helper.rb +44 -0
  49. data/spec/support/helpers/factories.rb +41 -0
  50. data/spec/support/shared_examples/a_class_with_interactor_callback_methods_example.rb +99 -0
  51. data/spec/support/shared_examples/a_class_with_interactor_context_methods_example.rb +58 -0
  52. data/spec/support/shared_examples/a_class_with_interactor_methods_example.rb +21 -0
  53. data/spec/support/shared_examples/a_class_with_organizer_callback_methods_example.rb +39 -0
  54. data/spec/support/spec_helpers.rb +7 -0
  55. metadata +68 -138
  56. data/lib/active_interactor/configuration.rb +0 -38
  57. data/lib/active_interactor/interactor/execution.rb +0 -24
  58. data/lib/rails/generators/templates/initializer.erb +0 -15
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe ActiveInteractor::Error::ContextFailure do
6
+ subject { described_class.new }
7
+
8
+ it { is_expected.to respond_to :context }
9
+
10
+ context 'when context is equal to nil' do
11
+ subject { described_class.new(nil) }
12
+
13
+ it { is_expected.to have_attributes(message: 'Context failed!') }
14
+ end
15
+
16
+ context 'when context is an instance of "TestContext"' do
17
+ before { build_context }
18
+ subject { described_class.new(TestContext.new) }
19
+
20
+ it { is_expected.to have_attributes(message: 'TestContext failed!') }
21
+ it 'is expected to have an instance of TestContext' do
22
+ expect(subject.context).to be_a TestContext
23
+ end
24
+ end
25
+ end
26
+
27
+ RSpec.describe ActiveInteractor::Error::InvalidContextClass do
28
+ subject { described_class.new }
29
+
30
+ it { is_expected.to respond_to :class_name }
31
+
32
+ context 'when class_name is equal to nil' do
33
+ subject { described_class.new(nil) }
34
+
35
+ it { is_expected.to have_attributes(message: 'invalid context class ') }
36
+ end
37
+
38
+ context 'when class_name is equal to "MyContect"' do
39
+ subject { described_class.new('MyContext') }
40
+
41
+ it { is_expected.to have_attributes(message: 'invalid context class MyContext') }
42
+ end
43
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe ActiveInteractor::Interactor::Worker do
6
+ context 'with interactor class TestInteractor' do
7
+ before { build_interactor }
8
+ let(:interactor) { TestInteractor.new }
9
+
10
+ describe '#execute_perform' do
11
+ subject { described_class.new(interactor).execute_perform }
12
+
13
+ it { is_expected.to be_an TestInteractor.context_class }
14
+
15
+ context 'when context fails' do
16
+ before do
17
+ allow_any_instance_of(TestInteractor).to receive(:perform)
18
+ .and_raise(ActiveInteractor::Error::ContextFailure)
19
+ end
20
+
21
+ it { expect { subject }.not_to raise_error }
22
+ it { is_expected.to be_an TestInteractor.context_class }
23
+ end
24
+ end
25
+
26
+ describe '#execute_perform!' do
27
+ subject { described_class.new(interactor).execute_perform! }
28
+
29
+ it { is_expected.to be_an TestInteractor.context_class }
30
+
31
+ it 'is expected to run perform callbacks on interactor' do
32
+ expect_any_instance_of(TestInteractor).to receive(:run_callbacks)
33
+ .with(:perform)
34
+ subject
35
+ end
36
+
37
+ it 'calls #perform on interactor instance' do
38
+ expect_any_instance_of(TestInteractor).to receive(:perform)
39
+ subject
40
+ end
41
+
42
+ context 'when interactor context is invalid on :calling' do
43
+ before do
44
+ allow_any_instance_of(TestInteractor.context_class).to receive(:valid?)
45
+ .with(:calling)
46
+ .and_return(false)
47
+ end
48
+
49
+ it { expect { subject }.to raise_error(ActiveInteractor::Error::ContextFailure) }
50
+ it 'rollsback the interactor context' do
51
+ expect_any_instance_of(TestInteractor).to receive(:context_rollback!)
52
+ expect { subject }.to raise_error(ActiveInteractor::Error::ContextFailure)
53
+ end
54
+ end
55
+
56
+ context 'when interactor context is invalid on :called' do
57
+ before do
58
+ allow_any_instance_of(TestInteractor.context_class).to receive(:valid?)
59
+ .with(:calling)
60
+ .and_return(true)
61
+ allow_any_instance_of(TestInteractor.context_class).to receive(:valid?)
62
+ .with(:called)
63
+ .and_return(false)
64
+ end
65
+
66
+ it { expect { subject }.to raise_error(ActiveInteractor::Error::ContextFailure) }
67
+ it 'rollsback the interactor context' do
68
+ expect_any_instance_of(TestInteractor).to receive(:context_rollback!)
69
+ expect { subject }.to raise_error(ActiveInteractor::Error::ContextFailure)
70
+ end
71
+ end
72
+ end
73
+
74
+ describe '#execute_rollback' do
75
+ subject { described_class.new(interactor).execute_rollback }
76
+
77
+ it 'is expected to run rollback callbacks on interactor' do
78
+ expect_any_instance_of(TestInteractor).to receive(:run_callbacks)
79
+ .with(:rollback)
80
+ subject
81
+ end
82
+
83
+ it 'calls #context_rollback on interactor instance' do
84
+ expect_any_instance_of(TestInteractor).to receive(:context_rollback!)
85
+ subject
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,178 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe ActiveInteractor::Organizer 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
+ include_examples 'a class with organizer callback methods'
11
+
12
+ describe '.contextualize_with' do
13
+ subject { described_class.contextualize_with(klass) }
14
+
15
+ context 'with an class that does not exist' do
16
+ let(:klass) { 'SomeClassThatDoesNotExist' }
17
+
18
+ it { expect { subject }.to raise_error(ActiveInteractor::Error::InvalidContextClass) }
19
+ end
20
+
21
+ context 'with context class TestContext' do
22
+ before { build_context }
23
+
24
+ context 'when passed as a string' do
25
+ let(:klass) { 'TestContext' }
26
+
27
+ it 'assigns the context class' do
28
+ subject
29
+ expect(described_class.context_class).to eq TestContext
30
+ end
31
+ end
32
+
33
+ context 'when passed as a symbol' do
34
+ let(:klass) { :test_context }
35
+
36
+ it 'assigns the context class' do
37
+ subject
38
+ expect(described_class.context_class).to eq TestContext
39
+ end
40
+ end
41
+
42
+ context 'when passed as a constant' do
43
+ let(:klass) { TestContext }
44
+
45
+ it 'assigns the context class' do
46
+ subject
47
+ expect(described_class.context_class).to eq TestContext
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ describe '.organize' do
54
+ subject { interactor_class }
55
+ context 'with two existing interactors' do
56
+ let!(:interactor1) { build_interactor('TestInteractor1') }
57
+ let!(:interactor2) { build_interactor('TestInteractor2') }
58
+
59
+ context 'when interactors are passed as contants' do
60
+ let(:interactor_class) do
61
+ build_organizer do
62
+ organize TestInteractor1, TestInteractor2
63
+ end
64
+ end
65
+
66
+ it { is_expected.to have_attributes(organized: [TestInteractor1, TestInteractor2]) }
67
+ end
68
+
69
+ context 'when interactors are passed as symbols' do
70
+ let(:interactor_class) do
71
+ build_organizer do
72
+ organize :test_interactor_1, :test_interactor_2
73
+ end
74
+ end
75
+
76
+ it { is_expected.to have_attributes(organized: [TestInteractor1, TestInteractor2]) }
77
+
78
+ context 'having a non existance interactor' do
79
+ let(:interactor_class) do
80
+ build_organizer do
81
+ organize :test_interactor_1, :interactor_that_doesnt_exist, :test_interactor_2
82
+ end
83
+ end
84
+
85
+ it { is_expected.to have_attributes(organized: [TestInteractor1, TestInteractor2]) }
86
+ end
87
+ end
88
+
89
+ context 'when interactors are passed as strings' do
90
+ let(:interactor_class) do
91
+ build_organizer do
92
+ organize 'TestInteractor1', 'TestInteractor2'
93
+ end
94
+ end
95
+
96
+ it { is_expected.to have_attributes(organized: [TestInteractor1, TestInteractor2]) }
97
+
98
+ context 'having a non existance interactor' do
99
+ let(:interactor_class) do
100
+ build_organizer do
101
+ organize 'TestInteractor1', 'InteractorThatDoesntExist', 'TestInteractor2'
102
+ end
103
+ end
104
+
105
+ it { is_expected.to have_attributes(organized: [TestInteractor1, TestInteractor2]) }
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ describe '#perform' do
112
+ subject { interactor_class.perform }
113
+ context 'with two existing interactors' do
114
+ let!(:interactor1) { build_interactor('TestInteractor1') }
115
+ let!(:interactor2) { build_interactor('TestInteractor2') }
116
+ let(:interactor_class) do
117
+ build_organizer do
118
+ organize TestInteractor1, TestInteractor2
119
+ end
120
+ end
121
+
122
+ it { is_expected.to be_a interactor_class.context_class }
123
+ it 'is expected to call #perform on both interactors' do
124
+ expect_any_instance_of(interactor1).to receive(:perform)
125
+ expect_any_instance_of(interactor2).to receive(:perform)
126
+ subject
127
+ end
128
+
129
+ context 'when the first interactor context fails' do
130
+ let!(:interactor1) do
131
+ build_interactor('TestInteractor1') do
132
+ def perform
133
+ context.fail!
134
+ end
135
+ end
136
+ end
137
+
138
+ it { expect { subject }.not_to raise_error }
139
+ it { is_expected.to be_a interactor_class.context_class }
140
+ it 'is expected to call #perform on the first interactor' do
141
+ expect_any_instance_of(interactor1).to receive(:perform)
142
+ subject
143
+ end
144
+ it 'is expected to not call #perform on the second interactor' do
145
+ expect_any_instance_of(interactor2).not_to receive(:perform)
146
+ subject
147
+ end
148
+ it 'is expected to call #rollback on the first interactor' do
149
+ expect_any_instance_of(interactor1).to receive(:rollback)
150
+ subject
151
+ end
152
+ end
153
+
154
+ context 'when the second interactor context fails' do
155
+ let!(:interactor2) do
156
+ build_interactor('TestInteractor2') do
157
+ def perform
158
+ context.fail!
159
+ end
160
+ end
161
+ end
162
+
163
+ it { expect { subject }.not_to raise_error }
164
+ it { is_expected.to be_a interactor_class.context_class }
165
+ it 'is expected to call #perform on both interactors' do
166
+ expect_any_instance_of(interactor1).to receive(:perform)
167
+ expect_any_instance_of(interactor2).to receive(:perform)
168
+ subject
169
+ end
170
+ it 'is expected to call #rollback on both interactors' do
171
+ expect_any_instance_of(interactor1).to receive(:rollback)
172
+ expect_any_instance_of(interactor2).to receive(:rollback)
173
+ subject
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe ActiveInteractor do
6
+ describe '::VERSION' do
7
+ subject { described_class::VERSION }
8
+
9
+ it { is_expected.to be_a String }
10
+ end
11
+
12
+ describe '.logger' do
13
+ subject { described_class.logger }
14
+
15
+ it { is_expected.to be_a Logger }
16
+ end
17
+
18
+ describe '.logger=' do
19
+ subject { described_class.logger = logger }
20
+ let!(:original_logger) { described_class.logger }
21
+ let(:logger) { double(:logger) }
22
+ after { described_class.logger = original_logger }
23
+
24
+ it { expect { subject }.to change { described_class.logger }.to(logger) }
25
+ end
26
+ end
@@ -0,0 +1,355 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'Basic Callback Integration', type: :integration do
6
+ describe 'An interactor with after context validation callbacks' do
7
+ let(:interactor_class) do
8
+ build_interactor do
9
+ context_validates :test_field, presence: true
10
+ after_context_validation :downcase_test_field
11
+
12
+ private
13
+
14
+ def downcase_test_field
15
+ context.test_field = context.test_field.downcase
16
+ end
17
+ end
18
+ end
19
+
20
+ include_examples 'a class with interactor methods'
21
+ include_examples 'a class with interactor callback methods'
22
+ include_examples 'a class with interactor context methods'
23
+
24
+ describe '.perform' do
25
+ subject { interactor_class.perform(context_attributes) }
26
+
27
+ context 'with valid context attributes' do
28
+ let(:context_attributes) { { test_field: 'TEST' } }
29
+
30
+ it { is_expected.to be_a interactor_class.context_class }
31
+ it { is_expected.to be_successful }
32
+ it { is_expected.to have_attributes(test_field: 'test') }
33
+ end
34
+ end
35
+ end
36
+
37
+ describe 'An interactor with conditional after context validation callbacks' do
38
+ let(:interactor_class) do
39
+ build_interactor do
40
+ context_validates :test_field, presence: true
41
+ after_context_validation :downcase_test_field, if: -> { context.should_downcase }
42
+
43
+ private
44
+
45
+ def downcase_test_field
46
+ context.test_field = context.test_field.downcase
47
+ end
48
+ end
49
+ end
50
+
51
+ include_examples 'a class with interactor methods'
52
+ include_examples 'a class with interactor callback methods'
53
+ include_examples 'a class with interactor context methods'
54
+
55
+ describe '.perform' do
56
+ subject { interactor_class.perform(context_attributes) }
57
+
58
+ context 'with :test_field "TEST" and :should_downcase true' do
59
+ let(:context_attributes) { { test_field: 'TEST', should_downcase: true } }
60
+
61
+ it { is_expected.to be_a interactor_class.context_class }
62
+ it { is_expected.to be_successful }
63
+ it { is_expected.to have_attributes(test_field: 'test') }
64
+ end
65
+
66
+ context 'with :test_field "TEST" and :should_downcase false' do
67
+ let(:context_attributes) { { test_field: 'TEST', should_downcase: false } }
68
+
69
+ it { is_expected.to be_a interactor_class.context_class }
70
+ it { is_expected.to be_successful }
71
+ it { is_expected.to have_attributes(test_field: 'TEST') }
72
+ end
73
+ end
74
+ end
75
+
76
+ describe 'An interactor with after perform callbacks' do
77
+ let(:interactor_class) do
78
+ build_interactor do
79
+ after_perform :test_after_perform
80
+
81
+ private
82
+
83
+ def test_after_perform; end
84
+ end
85
+ end
86
+
87
+ include_examples 'a class with interactor methods'
88
+ include_examples 'a class with interactor callback methods'
89
+ include_examples 'a class with interactor context methods'
90
+
91
+ describe '.perform' do
92
+ subject { interactor_class.perform }
93
+
94
+ it { is_expected.to be_a interactor_class.context_class }
95
+ it { is_expected.to be_successful }
96
+ it 'is expected to call #test_after_perform' do
97
+ expect_any_instance_of(interactor_class).to receive(:test_after_perform)
98
+ subject
99
+ end
100
+ end
101
+ end
102
+
103
+ describe 'An interactor with after rollback callbacks' do
104
+ let(:interactor_class) do
105
+ build_interactor do
106
+ after_rollback :test_after_rollback
107
+
108
+ def perform
109
+ context.fail!
110
+ end
111
+
112
+ private
113
+
114
+ def test_after_rollback; end
115
+ end
116
+ end
117
+
118
+ include_examples 'a class with interactor methods'
119
+ include_examples 'a class with interactor callback methods'
120
+ include_examples 'a class with interactor context methods'
121
+
122
+ describe '.perform' do
123
+ subject { interactor_class.perform }
124
+
125
+ it { is_expected.to be_a interactor_class.context_class }
126
+ it 'is expected to call #test_after_rollback' do
127
+ expect_any_instance_of(interactor_class).to receive(:test_after_rollback)
128
+ subject
129
+ end
130
+ end
131
+ end
132
+
133
+ describe 'An interactor with around perform callbacks' do
134
+ let(:interactor_class) do
135
+ build_interactor do
136
+ around_perform :test_around_perform
137
+
138
+ def perform
139
+ context.perform_step << 2
140
+ end
141
+
142
+ private
143
+
144
+ def test_around_perform
145
+ context.perform_step = []
146
+ context.perform_step << 1
147
+ yield
148
+ context.perform_step << 3
149
+ end
150
+ end
151
+ end
152
+
153
+ include_examples 'a class with interactor methods'
154
+ include_examples 'a class with interactor callback methods'
155
+ include_examples 'a class with interactor context methods'
156
+
157
+ describe '.perform' do
158
+ subject { interactor_class.perform }
159
+
160
+ it { is_expected.to be_a interactor_class.context_class }
161
+ it { is_expected.to have_attributes(perform_step: [1, 2, 3]) }
162
+ end
163
+ end
164
+
165
+ describe 'An interactor with around rollback callbacks' do
166
+ let(:interactor_class) do
167
+ build_interactor do
168
+ around_rollback :test_around_rollback
169
+
170
+ def perform
171
+ context.fail!
172
+ end
173
+
174
+ def rollback
175
+ context.rollback_step << 2
176
+ end
177
+
178
+ private
179
+
180
+ def test_around_rollback
181
+ context.rollback_step = []
182
+ context.rollback_step << 1
183
+ yield
184
+ context.rollback_step << 3
185
+ end
186
+ end
187
+ end
188
+
189
+ include_examples 'a class with interactor methods'
190
+ include_examples 'a class with interactor callback methods'
191
+ include_examples 'a class with interactor context methods'
192
+
193
+ describe '.perform' do
194
+ subject { interactor_class.perform }
195
+
196
+ it { is_expected.to be_a interactor_class.context_class }
197
+ it { is_expected.to have_attributes(rollback_step: [1, 2, 3]) }
198
+ end
199
+ end
200
+
201
+ describe 'An interactor with before perform callbacks' do
202
+ let(:interactor_class) do
203
+ build_interactor do
204
+ before_perform :test_before_perform
205
+
206
+ private
207
+
208
+ def test_before_perform; end
209
+ end
210
+ end
211
+
212
+ include_examples 'a class with interactor methods'
213
+ include_examples 'a class with interactor callback methods'
214
+ include_examples 'a class with interactor context methods'
215
+
216
+ describe '.perform' do
217
+ subject { interactor_class.perform }
218
+
219
+ it { is_expected.to be_a interactor_class.context_class }
220
+ it { is_expected.to be_successful }
221
+ it 'is expected to call #test_before_perform' do
222
+ expect_any_instance_of(interactor_class).to receive(:test_before_perform)
223
+ subject
224
+ end
225
+ end
226
+ end
227
+
228
+ describe 'An interactor with before rollback callbacks' do
229
+ let(:interactor_class) do
230
+ build_interactor do
231
+ before_rollback :test_before_rollback
232
+
233
+ def perform
234
+ context.fail!
235
+ end
236
+
237
+ private
238
+
239
+ def test_before_rollback; end
240
+ end
241
+ end
242
+
243
+ include_examples 'a class with interactor methods'
244
+ include_examples 'a class with interactor callback methods'
245
+ include_examples 'a class with interactor context methods'
246
+
247
+ describe '.perform' do
248
+ subject { interactor_class.perform }
249
+
250
+ it { is_expected.to be_a interactor_class.context_class }
251
+ it 'is expected to call #test_before_rollback' do
252
+ expect_any_instance_of(interactor_class).to receive(:test_before_rollback)
253
+ subject
254
+ end
255
+ end
256
+ end
257
+
258
+ describe 'An organizer with after each callbacks' do
259
+ let!(:interactor1) { build_interactor('TestInteractor1') }
260
+ let!(:interactor2) { build_interactor('TestInteractor2') }
261
+ let(:interactor_class) do
262
+ build_organizer do
263
+ after_each_perform :test_after_each_perform
264
+ organize TestInteractor1, TestInteractor2
265
+
266
+ private
267
+
268
+ def test_after_each_perform; end
269
+ end
270
+ end
271
+
272
+ include_examples 'a class with interactor methods'
273
+ include_examples 'a class with interactor callback methods'
274
+ include_examples 'a class with interactor context methods'
275
+ include_examples 'a class with organizer callback methods'
276
+
277
+ describe '.perform' do
278
+ subject { interactor_class.perform }
279
+
280
+ it { is_expected.to be_a interactor_class.context_class }
281
+ it 'is expected to call #test_after_each_perform twice' do
282
+ expect_any_instance_of(interactor_class).to receive(:test_after_each_perform)
283
+ .exactly(:twice)
284
+ subject
285
+ end
286
+ end
287
+ end
288
+
289
+ describe 'An organizer with around each callbacks' do
290
+ let!(:interactor1) { build_interactor('TestInteractor1') }
291
+ let!(:interactor2) { build_interactor('TestInteractor2') }
292
+ let(:interactor_class) do
293
+ build_organizer do
294
+ around_each_perform :test_around_each_perform
295
+ organize TestInteractor1, TestInteractor2
296
+
297
+ private
298
+
299
+ def find_index
300
+ (context.around_each_step.last || 0) + 1
301
+ end
302
+
303
+ def test_around_each_perform
304
+ context.around_each_step ||= []
305
+ context.around_each_step << find_index
306
+ yield
307
+ context.around_each_step << find_index
308
+ end
309
+ end
310
+ end
311
+
312
+ include_examples 'a class with interactor methods'
313
+ include_examples 'a class with interactor callback methods'
314
+ include_examples 'a class with interactor context methods'
315
+ include_examples 'a class with organizer callback methods'
316
+
317
+ describe '.perform' do
318
+ subject { interactor_class.perform }
319
+
320
+ it { is_expected.to be_a interactor_class.context_class }
321
+ it { is_expected.to have_attributes(around_each_step: [1, 2, 3, 4]) }
322
+ end
323
+ end
324
+
325
+ describe 'An organizer with before each callbacks' do
326
+ let!(:interactor1) { build_interactor('TestInteractor1') }
327
+ let!(:interactor2) { build_interactor('TestInteractor2') }
328
+ let(:interactor_class) do
329
+ build_organizer do
330
+ before_each_perform :test_before_each_perform
331
+ organize TestInteractor1, TestInteractor2
332
+
333
+ private
334
+
335
+ def test_before_each_perform; end
336
+ end
337
+ end
338
+
339
+ include_examples 'a class with interactor methods'
340
+ include_examples 'a class with interactor callback methods'
341
+ include_examples 'a class with interactor context methods'
342
+ include_examples 'a class with organizer callback methods'
343
+
344
+ describe '.perform' do
345
+ subject { interactor_class.perform }
346
+
347
+ it { is_expected.to be_a interactor_class.context_class }
348
+ it 'is expected to call #test_before_each_perform twice' do
349
+ expect_any_instance_of(interactor_class).to receive(:test_before_each_perform)
350
+ .exactly(:twice)
351
+ subject
352
+ end
353
+ end
354
+ end
355
+ end