active_interaction 4.0.6 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +156 -7
  3. data/CONTRIBUTING.md +11 -3
  4. data/README.md +260 -219
  5. data/lib/active_interaction/array_input.rb +77 -0
  6. data/lib/active_interaction/base.rb +14 -98
  7. data/lib/active_interaction/concerns/active_recordable.rb +3 -3
  8. data/lib/active_interaction/concerns/missable.rb +2 -2
  9. data/lib/active_interaction/errors.rb +6 -88
  10. data/lib/active_interaction/exceptions.rb +47 -0
  11. data/lib/active_interaction/filter/column.rb +59 -0
  12. data/lib/active_interaction/filter/error.rb +40 -0
  13. data/lib/active_interaction/filter.rb +44 -53
  14. data/lib/active_interaction/filters/abstract_date_time_filter.rb +9 -6
  15. data/lib/active_interaction/filters/abstract_numeric_filter.rb +7 -3
  16. data/lib/active_interaction/filters/array_filter.rb +40 -6
  17. data/lib/active_interaction/filters/boolean_filter.rb +4 -3
  18. data/lib/active_interaction/filters/date_filter.rb +1 -1
  19. data/lib/active_interaction/filters/date_time_filter.rb +1 -1
  20. data/lib/active_interaction/filters/decimal_filter.rb +1 -1
  21. data/lib/active_interaction/filters/float_filter.rb +1 -1
  22. data/lib/active_interaction/filters/hash_filter.rb +23 -15
  23. data/lib/active_interaction/filters/integer_filter.rb +1 -1
  24. data/lib/active_interaction/filters/interface_filter.rb +12 -12
  25. data/lib/active_interaction/filters/object_filter.rb +9 -3
  26. data/lib/active_interaction/filters/record_filter.rb +21 -11
  27. data/lib/active_interaction/filters/string_filter.rb +1 -1
  28. data/lib/active_interaction/filters/symbol_filter.rb +1 -1
  29. data/lib/active_interaction/filters/time_filter.rb +4 -4
  30. data/lib/active_interaction/hash_input.rb +43 -0
  31. data/lib/active_interaction/input.rb +23 -0
  32. data/lib/active_interaction/inputs.rb +161 -46
  33. data/lib/active_interaction/locale/en.yml +0 -1
  34. data/lib/active_interaction/locale/fr.yml +0 -1
  35. data/lib/active_interaction/locale/it.yml +0 -1
  36. data/lib/active_interaction/locale/ja.yml +0 -1
  37. data/lib/active_interaction/locale/pt-BR.yml +0 -1
  38. data/lib/active_interaction/modules/validation.rb +6 -17
  39. data/lib/active_interaction/version.rb +1 -1
  40. data/lib/active_interaction.rb +41 -36
  41. data/spec/active_interaction/array_input_spec.rb +166 -0
  42. data/spec/active_interaction/base_spec.rb +34 -248
  43. data/spec/active_interaction/concerns/active_modelable_spec.rb +3 -3
  44. data/spec/active_interaction/concerns/active_recordable_spec.rb +7 -7
  45. data/spec/active_interaction/concerns/hashable_spec.rb +8 -8
  46. data/spec/active_interaction/concerns/missable_spec.rb +9 -9
  47. data/spec/active_interaction/concerns/runnable_spec.rb +34 -32
  48. data/spec/active_interaction/errors_spec.rb +60 -43
  49. data/spec/active_interaction/{filter_column_spec.rb → filter/column_spec.rb} +3 -10
  50. data/spec/active_interaction/filter_spec.rb +6 -6
  51. data/spec/active_interaction/filters/abstract_date_time_filter_spec.rb +2 -2
  52. data/spec/active_interaction/filters/abstract_numeric_filter_spec.rb +2 -2
  53. data/spec/active_interaction/filters/array_filter_spec.rb +109 -16
  54. data/spec/active_interaction/filters/boolean_filter_spec.rb +12 -11
  55. data/spec/active_interaction/filters/date_filter_spec.rb +32 -27
  56. data/spec/active_interaction/filters/date_time_filter_spec.rb +34 -29
  57. data/spec/active_interaction/filters/decimal_filter_spec.rb +20 -18
  58. data/spec/active_interaction/filters/file_filter_spec.rb +7 -7
  59. data/spec/active_interaction/filters/float_filter_spec.rb +19 -17
  60. data/spec/active_interaction/filters/hash_filter_spec.rb +16 -18
  61. data/spec/active_interaction/filters/integer_filter_spec.rb +24 -22
  62. data/spec/active_interaction/filters/interface_filter_spec.rb +105 -82
  63. data/spec/active_interaction/filters/object_filter_spec.rb +52 -36
  64. data/spec/active_interaction/filters/record_filter_spec.rb +61 -39
  65. data/spec/active_interaction/filters/string_filter_spec.rb +7 -7
  66. data/spec/active_interaction/filters/symbol_filter_spec.rb +6 -6
  67. data/spec/active_interaction/filters/time_filter_spec.rb +57 -34
  68. data/spec/active_interaction/hash_input_spec.rb +58 -0
  69. data/spec/active_interaction/i18n_spec.rb +22 -17
  70. data/spec/active_interaction/inputs_spec.rb +170 -18
  71. data/spec/active_interaction/integration/array_interaction_spec.rb +3 -7
  72. data/spec/active_interaction/integration/record_integration_spec.rb +5 -0
  73. data/spec/active_interaction/modules/validation_spec.rb +8 -31
  74. data/spec/spec_helper.rb +9 -0
  75. data/spec/support/concerns.rb +2 -2
  76. data/spec/support/filters.rb +27 -51
  77. data/spec/support/interactions.rb +4 -4
  78. metadata +50 -50
  79. data/lib/active_interaction/filter_column.rb +0 -57
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
2
  require 'action_controller'
3
+ require 'active_support/core_ext/kernel/reporting'
3
4
 
4
5
  InteractionWithFilter = Class.new(TestInteraction) do
5
6
  float :thing
@@ -34,10 +35,10 @@ InterruptInteraction = Class.new(TestInteraction) do
34
35
  end
35
36
 
36
37
  describe ActiveInteraction::Base do
37
- include_context 'interactions'
38
-
39
38
  subject(:interaction) { described_class.new(inputs) }
40
39
 
40
+ include_context 'interactions'
41
+
41
42
  describe '.new(inputs = {})' do
42
43
  it 'does not set instance vars for reserved input names' do
43
44
  key = :execute
@@ -83,7 +84,7 @@ describe ActiveInteraction::Base do
83
84
  before { inputs[:thing] = 1 }
84
85
 
85
86
  it 'sets the attribute to the filtered value' do
86
- expect(interaction.thing).to eql 1.0
87
+ expect(interaction.thing).to be 1.0
87
88
  end
88
89
  end
89
90
 
@@ -181,8 +182,8 @@ describe ActiveInteraction::Base do
181
182
 
182
183
  it 'warns when redefining a filter' do
183
184
  klass = Class.new(described_class)
184
- expect(klass).to receive(:warn).with(/\AWARNING:/)
185
- klass.boolean :thing
185
+ allow(klass).to receive(:warn)
186
+ expect(klass.boolean(:thing)).to have_received(:warn).with(/\AWARNING:/)
186
187
  end
187
188
 
188
189
  describe '.run(inputs = {})' do
@@ -204,18 +205,18 @@ describe ActiveInteraction::Base do
204
205
  before { inputs[:thing] = thing }
205
206
 
206
207
  context 'failing runtime validations' do
207
- before do
208
- @execute = described_class.instance_method(:execute)
208
+ around do |example|
209
+ old_method = described_class.instance_method(:execute)
209
210
  described_class.send(:define_method, :execute) do
210
211
  errors.add(:thing, 'is invalid')
211
212
  errors.add(:thing, :invalid)
212
213
  true
213
214
  end
214
- end
215
215
 
216
- after do
216
+ example.run
217
+
217
218
  silence_warnings do
218
- described_class.send(:define_method, :execute, @execute)
219
+ described_class.send(:define_method, :execute, old_method)
219
220
  end
220
221
  end
221
222
 
@@ -279,7 +280,7 @@ describe ActiveInteraction::Base do
279
280
  let(:inputs) { { thing: 1, other: other_val } }
280
281
 
281
282
  it 'casts filtered inputs' do
282
- expect(interaction.inputs[:thing]).to eql 1.0
283
+ expect(interaction.inputs[:thing]).to be 1.0
283
284
  end
284
285
 
285
286
  it 'strips non-filtered inputs' do
@@ -293,17 +294,28 @@ describe ActiveInteraction::Base do
293
294
  let(:z) { rand }
294
295
 
295
296
  context 'with valid composition' do
296
- before do
297
- inputs[:x] = x
298
- inputs[:z] = z
299
- end
297
+ context 'when inputs is a hash' do
298
+ let(:inputs) { { x: x, z: z } }
300
299
 
301
- it 'is valid' do
302
- expect(outcome).to be_valid
300
+ it 'is valid' do
301
+ expect(outcome).to be_valid
302
+ end
303
+
304
+ it 'returns the sum' do
305
+ expect(result).to eql x + z
306
+ end
303
307
  end
304
308
 
305
- it 'returns the sum' do
306
- expect(result).to eql x + z
309
+ context 'when inputs is an ActiveInteraction::Inputs' do
310
+ let(:inputs) { ActiveInteraction::Inputs.new({ x: x, z: z }, described_class.new) }
311
+
312
+ it 'is valid' do
313
+ expect(outcome).to be_valid
314
+ end
315
+
316
+ it 'returns the sum' do
317
+ expect(result).to eql x + z
318
+ end
307
319
  end
308
320
  end
309
321
 
@@ -332,232 +344,6 @@ describe ActiveInteraction::Base do
332
344
  end
333
345
  end
334
346
 
335
- describe '#given?' do
336
- let(:described_class) do
337
- Class.new(TestInteraction) do
338
- float :x,
339
- default: nil
340
-
341
- def execute
342
- given?(:x)
343
- end
344
- end
345
- end
346
-
347
- it 'is false when the input is not given' do
348
- expect(result).to be false
349
- end
350
-
351
- it 'is true when the input is nil' do
352
- inputs[:x] = nil
353
- expect(result).to be true
354
- end
355
-
356
- it 'is true when the input is given' do
357
- inputs[:x] = rand
358
- expect(result).to be true
359
- end
360
-
361
- it 'symbolizes its argument' do
362
- described_class.class_exec do
363
- def execute
364
- given?('x')
365
- end
366
- end
367
-
368
- inputs[:x] = rand
369
- expect(result).to be true
370
- end
371
-
372
- it 'only tracks inputs with filters' do
373
- described_class.class_exec do
374
- def execute
375
- given?(:y)
376
- end
377
- end
378
-
379
- inputs[:y] = rand
380
- expect(result).to be false
381
- end
382
-
383
- context 'nested hash values' do
384
- let(:described_class) do
385
- Class.new(TestInteraction) do
386
- hash :x, default: {} do
387
- boolean :y,
388
- default: true
389
- end
390
-
391
- def execute; end
392
- end
393
- end
394
-
395
- it 'is true when the nested inputs symbols are given' do
396
- described_class.class_exec do
397
- def execute
398
- given?(:x, :y)
399
- end
400
- end
401
-
402
- inputs[:x] = { y: false }
403
- expect(result).to be true
404
- end
405
-
406
- it 'is true when the nested inputs strings are given' do
407
- described_class.class_exec do
408
- def execute
409
- given?(:x, :y)
410
- end
411
- end
412
-
413
- inputs['x'] = { 'y' => false }
414
- expect(result).to be true
415
- end
416
-
417
- it 'is false when the nested input is not given' do
418
- described_class.class_exec do
419
- def execute
420
- given?(:x, :y)
421
- end
422
- end
423
-
424
- inputs[:x] = {}
425
- expect(result).to be false
426
- end
427
-
428
- it 'is false when the first input is not given' do
429
- described_class.class_exec do
430
- def execute
431
- given?(:x, :y)
432
- end
433
- end
434
-
435
- expect(result).to be false
436
- end
437
-
438
- it 'is false when the first input is nil' do
439
- described_class.class_exec do
440
- def execute
441
- given?(:x, :y)
442
- end
443
- end
444
-
445
- inputs[:x] = nil
446
- expect(result).to be false
447
- end
448
-
449
- it 'returns false if you go too far' do
450
- described_class.class_exec do
451
- def execute
452
- given?(:x, :y, :z)
453
- end
454
- end
455
-
456
- inputs[:x] = { y: true }
457
- expect(result).to be false
458
- end
459
- end
460
-
461
- context 'nested array values' do
462
- let(:described_class) do
463
- Class.new(TestInteraction) do
464
- array :x do
465
- hash do
466
- boolean :y, default: true
467
- end
468
- end
469
-
470
- def execute; end
471
- end
472
- end
473
-
474
- context 'has a positive index' do
475
- it 'returns true if found' do
476
- described_class.class_exec do
477
- def execute
478
- given?(:x, 0, :y)
479
- end
480
- end
481
-
482
- inputs[:x] = [{ y: true }]
483
- expect(result).to be true
484
- end
485
-
486
- it 'returns false if not found' do
487
- described_class.class_exec do
488
- def execute
489
- given?(:x, 0, :y)
490
- end
491
- end
492
-
493
- inputs[:x] = []
494
- expect(result).to be false
495
- end
496
- end
497
-
498
- context 'has a negative index' do
499
- it 'returns true if found' do
500
- described_class.class_exec do
501
- def execute
502
- given?(:x, -1, :y)
503
- end
504
- end
505
-
506
- inputs[:x] = [{ y: true }]
507
- expect(result).to be true
508
- end
509
-
510
- it 'returns false if not found' do
511
- described_class.class_exec do
512
- def execute
513
- given?(:x, -1, :y)
514
- end
515
- end
516
-
517
- inputs[:x] = []
518
- expect(result).to be false
519
- end
520
- end
521
-
522
- it 'returns false if you go too far' do
523
- described_class.class_exec do
524
- def execute
525
- given?(:x, 10, :y)
526
- end
527
- end
528
-
529
- inputs[:x] = [{}]
530
- expect(result).to be false
531
- end
532
- end
533
-
534
- context 'multi-part date values' do
535
- let(:described_class) do
536
- Class.new(TestInteraction) do
537
- date :thing,
538
- default: nil
539
-
540
- def execute
541
- given?(:thing)
542
- end
543
- end
544
- end
545
-
546
- it 'returns true when the input is given' do
547
- inputs.merge!(
548
- 'thing(1i)' => '2020',
549
- 'thing(2i)' => '12',
550
- 'thing(3i)' => '31'
551
- )
552
- expect(result).to be true
553
- end
554
-
555
- it 'returns false if not found' do
556
- expect(result).to be false
557
- end
558
- end
559
- end
560
-
561
347
  context 'inheritance' do
562
348
  context 'filters' do
563
349
  let(:described_class) { InteractionWithFilter }
@@ -680,7 +466,7 @@ describe ActiveInteraction::Base do
680
466
  context 'callbacks' do
681
467
  let(:described_class) { Class.new(TestInteraction) }
682
468
 
683
- %w[type_check validate execute].each do |name|
469
+ %w[filter validate execute].each do |name|
684
470
  %w[before after around].map(&:to_sym).each do |type|
685
471
  it "runs the #{type} #{name} callback" do
686
472
  called = false
@@ -691,9 +477,9 @@ describe ActiveInteraction::Base do
691
477
  end
692
478
  end
693
479
 
694
- context 'with errors during type_check' do
480
+ context 'with errors during filter' do
695
481
  before do
696
- described_class.set_callback(:type_check, :before) do
482
+ described_class.set_callback(:filter, :before) do
697
483
  errors.add(:base)
698
484
  end
699
485
  end
@@ -15,19 +15,19 @@ shared_examples_for 'ActiveModel' do
15
15
  end
16
16
 
17
17
  describe ActiveInteraction::ActiveModelable do
18
- include_context 'concerns', ActiveInteraction::ActiveModelable
18
+ include_context 'concerns', described_class
19
19
 
20
20
  it_behaves_like 'ActiveModel'
21
21
 
22
22
  describe '.i18n_scope' do
23
23
  it 'returns the scope' do
24
- expect(klass.i18n_scope).to eql :active_interaction
24
+ expect(klass.i18n_scope).to be :active_interaction
25
25
  end
26
26
  end
27
27
 
28
28
  describe '#i18n_scope' do
29
29
  it 'returns the scope' do
30
- expect(instance.i18n_scope).to eql :active_interaction
30
+ expect(instance.i18n_scope).to be :active_interaction
31
31
  end
32
32
  end
33
33
 
@@ -23,27 +23,27 @@ describe ActiveInteraction::ActiveRecordable do
23
23
  context 'name is an input name' do
24
24
  let(:name) { described_class.filters.keys.first }
25
25
 
26
- it 'returns a FilterColumn' do
27
- expect(column).to be_a ActiveInteraction::FilterColumn
26
+ it 'returns a Filter::Column' do
27
+ expect(column).to be_a ActiveInteraction::Filter::Column
28
28
  end
29
29
 
30
- it 'returns a FilterColumn of type boolean' do
31
- expect(column.type).to eql :float
30
+ it 'returns a Filter::Column of type boolean' do
31
+ expect(column.type).to be :float
32
32
  end
33
33
  end
34
34
  end
35
35
 
36
36
  describe '#has_attribute?' do
37
37
  it 'returns true if the filter exists' do
38
- expect(outcome.has_attribute?(:thing)).to be_truthy
38
+ expect(outcome).to have_attribute(:thing)
39
39
  end
40
40
 
41
41
  it 'works with strings' do
42
- expect(outcome.has_attribute?('thing')).to be_truthy
42
+ expect(outcome).to have_attribute('thing')
43
43
  end
44
44
 
45
45
  it 'returns false if the filter does not exist' do
46
- expect(outcome.has_attribute?(:not_a_filter)).to be_falsey
46
+ expect(outcome).to_not have_attribute(:not_a_filter)
47
47
  end
48
48
  end
49
49
  end
@@ -1,11 +1,11 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ActiveInteraction::Hashable do
4
- include_context 'concerns', ActiveInteraction::Hashable
4
+ include_context 'concerns', described_class
5
5
 
6
6
  describe '#hash(*args, &block)' do
7
7
  context 'with no arguments' do
8
- let(:hash) { subject.hash }
8
+ let(:hash) { instance.hash }
9
9
 
10
10
  it 'returns an Integer' do
11
11
  expect(hash).to be_an Integer
@@ -14,28 +14,28 @@ describe ActiveInteraction::Hashable do
14
14
 
15
15
  context 'with arguments' do
16
16
  let(:arguments) { [:attribute, {}] }
17
- let(:hash) { subject.hash(*arguments) }
17
+ let(:hash) { instance.hash(*arguments) }
18
18
 
19
- before { allow(subject).to receive(:method_missing) }
19
+ before { allow(instance).to receive(:method_missing) }
20
20
 
21
21
  it 'calls method_missing' do
22
22
  hash
23
- expect(subject).to have_received(:method_missing).once
23
+ expect(instance).to have_received(:method_missing).once
24
24
  .with(:hash, *arguments)
25
25
  end
26
26
 
27
27
  context 'with a block' do
28
28
  let(:block) { proc {} }
29
- let(:hash) { subject.hash(*arguments, &block) }
29
+ let(:hash) { instance.hash(*arguments, &block) }
30
30
 
31
31
  it 'calls method_missing' do
32
32
  hash
33
- expect(subject).to have_received(:method_missing).once
33
+ expect(instance).to have_received(:method_missing).once
34
34
  .with(:hash, *arguments)
35
35
  end
36
36
 
37
37
  it 'passes the block to method_missing' do
38
- allow(subject).to receive(:method_missing) do |*, &other_block|
38
+ allow(instance).to receive(:method_missing) do |*, &other_block|
39
39
  expect(other_block).to equal block
40
40
  end
41
41
  hash(&block)
@@ -1,14 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ActiveInteraction::Missable do
4
- include_context 'concerns', ActiveInteraction::Missable
4
+ include_context 'concerns', described_class
5
5
 
6
6
  describe '#respond_to?(slug, include_all = false)' do
7
7
  context 'with invalid slug' do
8
8
  let(:slug) { :slug }
9
9
 
10
10
  it 'returns false' do
11
- expect(instance.respond_to?(slug)).to be_falsey
11
+ expect(instance).to_not respond_to(slug)
12
12
  end
13
13
  end
14
14
 
@@ -16,7 +16,7 @@ describe ActiveInteraction::Missable do
16
16
  let(:slug) { :boolean }
17
17
 
18
18
  it 'returns true' do
19
- expect(instance.respond_to?(slug)).to be_truthy
19
+ expect(instance).to respond_to(slug)
20
20
  end
21
21
  end
22
22
  end
@@ -45,7 +45,7 @@ describe ActiveInteraction::Missable do
45
45
 
46
46
  it 'calls super' do
47
47
  expect do
48
- instance.method_missing(slug)
48
+ instance.public_send(slug)
49
49
  end.to raise_error NameError
50
50
  end
51
51
  end
@@ -55,12 +55,12 @@ describe ActiveInteraction::Missable do
55
55
  let(:slug) { :boolean }
56
56
 
57
57
  it 'returns self' do
58
- expect(instance.method_missing(slug)).to eql instance
58
+ expect(instance.public_send(slug)).to eql instance
59
59
  end
60
60
 
61
61
  it 'yields' do
62
62
  expect do |b|
63
- instance.method_missing(slug, &b)
63
+ instance.public_send(slug, &b)
64
64
  end.to yield_with_args(filter, [], {})
65
65
  end
66
66
 
@@ -69,7 +69,7 @@ describe ActiveInteraction::Missable do
69
69
 
70
70
  it 'yields' do
71
71
  expect do |b|
72
- instance.method_missing(:boolean, *names, &b)
72
+ instance.public_send(:boolean, *names, &b)
73
73
  end.to yield_with_args(filter, names, {})
74
74
  end
75
75
  end
@@ -79,7 +79,7 @@ describe ActiveInteraction::Missable do
79
79
 
80
80
  it 'yields' do
81
81
  expect do |b|
82
- instance.method_missing(:boolean, options, &b)
82
+ instance.public_send(:boolean, options, &b)
83
83
  end.to yield_with_args(filter, [], options)
84
84
  end
85
85
  end
@@ -90,7 +90,7 @@ describe ActiveInteraction::Missable do
90
90
 
91
91
  it 'yields' do
92
92
  expect do |b|
93
- instance.method_missing(:boolean, *names, options, &b)
93
+ instance.public_send(:boolean, *names, options, &b)
94
94
  end.to yield_with_args(filter, names, options)
95
95
  end
96
96
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ActiveInteraction::Runnable do
4
- include_context 'concerns', ActiveInteraction::Runnable
4
+ include_context 'concerns', described_class
5
5
 
6
6
  class WrappableFailingInteraction # rubocop:disable Lint/ConstantDefinitionInBlock
7
7
  include ActiveInteraction::Runnable
@@ -230,49 +230,51 @@ describe ActiveInteraction::Runnable do
230
230
  end
231
231
  end
232
232
 
233
- context 'caches the validity and result of the run' do
234
- let(:klass) do
235
- Class.new(ActiveInteraction::Base) do
236
- invalid = [false, true].cycle
233
+ context 'caches the result of the run' do
234
+ context 'when it is invalid' do
235
+ let(:klass) do
236
+ Class.new(ActiveInteraction::Base) do
237
+ invalid = [false, true].cycle
237
238
 
238
- validate do |interaction|
239
- interaction.errors.add(:base, 'failed') unless invalid.next
240
- end
239
+ validate do |interaction|
240
+ interaction.errors.add(:base, 'failed') unless invalid.next
241
+ end
241
242
 
242
- def execute
243
- true
243
+ def execute
244
+ true
245
+ end
244
246
  end
245
247
  end
246
- end
247
248
 
248
- it 'is invalid' do
249
- expect(outcome).to_not be_valid
250
- expect(outcome.result).to be_nil
251
- expect(outcome).to_not be_valid
252
- expect(outcome.result).to be_nil
249
+ it 'fails' do
250
+ expect(outcome).to_not be_valid
251
+ expect(outcome.result).to be_nil
252
+ expect(outcome).to_not be_valid
253
+ expect(outcome.result).to be_nil
254
+ end
253
255
  end
254
- end
255
256
 
256
- context 'caches the validity and result of the run' do
257
- let(:klass) do
258
- Class.new(ActiveInteraction::Base) do
259
- valid = [true, false].cycle
257
+ context 'when it is valid' do
258
+ let(:klass) do
259
+ Class.new(ActiveInteraction::Base) do
260
+ valid = [true, false].cycle
260
261
 
261
- validate do |interaction|
262
- interaction.errors.add(:base, 'failed') unless valid.next
263
- end
262
+ validate do |interaction|
263
+ interaction.errors.add(:base, 'failed') unless valid.next
264
+ end
264
265
 
265
- def execute
266
- true
266
+ def execute
267
+ true
268
+ end
267
269
  end
268
270
  end
269
- end
270
271
 
271
- it 'is valid' do
272
- expect(outcome).to be_valid
273
- expect(outcome.result).to be true
274
- expect(outcome).to be_valid
275
- expect(outcome.result).to be true
272
+ it 'succeeds' do
273
+ expect(outcome).to be_valid
274
+ expect(outcome.result).to be true
275
+ expect(outcome).to be_valid
276
+ expect(outcome.result).to be true
277
+ end
276
278
  end
277
279
  end
278
280