active_interaction 4.1.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +128 -1
  3. data/README.md +63 -28
  4. data/lib/active_interaction/array_input.rb +77 -0
  5. data/lib/active_interaction/base.rb +14 -98
  6. data/lib/active_interaction/concerns/active_recordable.rb +3 -3
  7. data/lib/active_interaction/concerns/missable.rb +2 -2
  8. data/lib/active_interaction/errors.rb +6 -88
  9. data/lib/active_interaction/exceptions.rb +47 -0
  10. data/lib/active_interaction/filter/column.rb +59 -0
  11. data/lib/active_interaction/filter/error.rb +40 -0
  12. data/lib/active_interaction/filter.rb +44 -53
  13. data/lib/active_interaction/filters/abstract_date_time_filter.rb +9 -6
  14. data/lib/active_interaction/filters/abstract_numeric_filter.rb +7 -3
  15. data/lib/active_interaction/filters/array_filter.rb +34 -6
  16. data/lib/active_interaction/filters/boolean_filter.rb +4 -3
  17. data/lib/active_interaction/filters/date_filter.rb +1 -1
  18. data/lib/active_interaction/filters/date_time_filter.rb +1 -1
  19. data/lib/active_interaction/filters/decimal_filter.rb +1 -1
  20. data/lib/active_interaction/filters/float_filter.rb +1 -1
  21. data/lib/active_interaction/filters/hash_filter.rb +23 -15
  22. data/lib/active_interaction/filters/integer_filter.rb +1 -1
  23. data/lib/active_interaction/filters/interface_filter.rb +12 -12
  24. data/lib/active_interaction/filters/object_filter.rb +9 -3
  25. data/lib/active_interaction/filters/record_filter.rb +21 -11
  26. data/lib/active_interaction/filters/string_filter.rb +1 -1
  27. data/lib/active_interaction/filters/symbol_filter.rb +1 -1
  28. data/lib/active_interaction/filters/time_filter.rb +4 -4
  29. data/lib/active_interaction/hash_input.rb +43 -0
  30. data/lib/active_interaction/input.rb +23 -0
  31. data/lib/active_interaction/inputs.rb +157 -46
  32. data/lib/active_interaction/locale/en.yml +0 -1
  33. data/lib/active_interaction/locale/fr.yml +0 -1
  34. data/lib/active_interaction/locale/it.yml +0 -1
  35. data/lib/active_interaction/locale/ja.yml +0 -1
  36. data/lib/active_interaction/locale/pt-BR.yml +0 -1
  37. data/lib/active_interaction/modules/validation.rb +6 -17
  38. data/lib/active_interaction/version.rb +1 -1
  39. data/lib/active_interaction.rb +43 -36
  40. data/spec/active_interaction/array_input_spec.rb +166 -0
  41. data/spec/active_interaction/base_spec.rb +15 -240
  42. data/spec/active_interaction/concerns/active_modelable_spec.rb +3 -3
  43. data/spec/active_interaction/concerns/active_recordable_spec.rb +7 -7
  44. data/spec/active_interaction/concerns/hashable_spec.rb +8 -8
  45. data/spec/active_interaction/concerns/missable_spec.rb +9 -9
  46. data/spec/active_interaction/concerns/runnable_spec.rb +34 -32
  47. data/spec/active_interaction/errors_spec.rb +60 -43
  48. data/spec/active_interaction/{filter_column_spec.rb → filter/column_spec.rb} +3 -10
  49. data/spec/active_interaction/filter_spec.rb +6 -6
  50. data/spec/active_interaction/filters/abstract_date_time_filter_spec.rb +2 -2
  51. data/spec/active_interaction/filters/abstract_numeric_filter_spec.rb +2 -2
  52. data/spec/active_interaction/filters/array_filter_spec.rb +99 -16
  53. data/spec/active_interaction/filters/boolean_filter_spec.rb +12 -11
  54. data/spec/active_interaction/filters/date_filter_spec.rb +32 -27
  55. data/spec/active_interaction/filters/date_time_filter_spec.rb +34 -29
  56. data/spec/active_interaction/filters/decimal_filter_spec.rb +20 -18
  57. data/spec/active_interaction/filters/file_filter_spec.rb +7 -7
  58. data/spec/active_interaction/filters/float_filter_spec.rb +19 -17
  59. data/spec/active_interaction/filters/hash_filter_spec.rb +16 -18
  60. data/spec/active_interaction/filters/integer_filter_spec.rb +24 -22
  61. data/spec/active_interaction/filters/interface_filter_spec.rb +105 -82
  62. data/spec/active_interaction/filters/object_filter_spec.rb +52 -36
  63. data/spec/active_interaction/filters/record_filter_spec.rb +61 -39
  64. data/spec/active_interaction/filters/string_filter_spec.rb +7 -7
  65. data/spec/active_interaction/filters/symbol_filter_spec.rb +6 -6
  66. data/spec/active_interaction/filters/time_filter_spec.rb +57 -34
  67. data/spec/active_interaction/hash_input_spec.rb +58 -0
  68. data/spec/active_interaction/i18n_spec.rb +22 -17
  69. data/spec/active_interaction/inputs_spec.rb +167 -23
  70. data/spec/active_interaction/integration/array_interaction_spec.rb +3 -7
  71. data/spec/active_interaction/modules/validation_spec.rb +8 -31
  72. data/spec/spec_helper.rb +8 -0
  73. data/spec/support/concerns.rb +2 -2
  74. data/spec/support/filters.rb +27 -51
  75. data/spec/support/interactions.rb +4 -4
  76. metadata +40 -91
  77. data/lib/active_interaction/filter_column.rb +0 -57
@@ -18,11 +18,12 @@ describe ActiveInteraction::TimeFilter, :filter do
18
18
 
19
19
  context 'with a time zone' do
20
20
  before do
21
- time_zone = double
22
- allow(Time).to receive(:zone).and_return(time_zone)
23
-
24
21
  time_with_zone = double
22
+
23
+ time_zone = double
25
24
  allow(time_zone).to receive(:at).and_return(time_with_zone)
25
+
26
+ allow(Time).to receive(:zone).and_return(time_zone)
26
27
  end
27
28
 
28
29
  it 'raises an error' do
@@ -34,14 +35,14 @@ describe ActiveInteraction::TimeFilter, :filter do
34
35
  end
35
36
  end
36
37
 
37
- describe '#cast' do
38
- let(:result) { filter.send(:cast, value, nil) }
38
+ describe '#process' do
39
+ let(:result) { filter.process(value, nil) }
39
40
 
40
41
  context 'with a Time' do
41
42
  let(:value) { Time.new }
42
43
 
43
44
  it 'returns the Time' do
44
- expect(result).to eql value
45
+ expect(result.value).to eql value
45
46
  end
46
47
  end
47
48
 
@@ -49,7 +50,24 @@ describe ActiveInteraction::TimeFilter, :filter do
49
50
  let(:value) { '2011-12-13 14:15:16 +1718' }
50
51
 
51
52
  it 'returns a Time' do
52
- expect(result).to eql Time.parse(value)
53
+ expect(result.value).to eql Time.parse(value)
54
+ end
55
+
56
+ context 'with a time zone' do
57
+ before do
58
+ klass = double
59
+ allow(klass).to receive(:parse).with(value).and_return(nil)
60
+
61
+ allow(filter).to receive(:matches?).and_return(false)
62
+ allow(filter).to receive(:klass).and_return(klass)
63
+ end
64
+
65
+ it 'indicates an error the string is not parsable' do
66
+ error = result.errors.first
67
+
68
+ expect(error).to be_an_instance_of ActiveInteraction::Filter::Error
69
+ expect(error.type).to be :invalid_type
70
+ end
53
71
  end
54
72
 
55
73
  context 'with format' do
@@ -58,7 +76,7 @@ describe ActiveInteraction::TimeFilter, :filter do
58
76
  let(:value) { '13/12/2011 14:15:16 +1718' }
59
77
 
60
78
  it 'returns a Time' do
61
- expect(result).to eql Time.strptime(value, format)
79
+ expect(result.value).to eql Time.strptime(value, format)
62
80
  end
63
81
  end
64
82
  end
@@ -66,19 +84,21 @@ describe ActiveInteraction::TimeFilter, :filter do
66
84
  context 'with an invalid String' do
67
85
  let(:value) { 'invalid' }
68
86
 
69
- it 'raises an error' do
70
- expect do
71
- result
72
- end.to raise_error ActiveInteraction::InvalidValueError
87
+ it 'indicates an error' do
88
+ error = result.errors.first
89
+
90
+ expect(error).to be_an_instance_of ActiveInteraction::Filter::Error
91
+ expect(error.type).to be :invalid_type
73
92
  end
74
93
 
75
94
  context 'with format' do
76
95
  include_context 'with format'
77
96
 
78
- it do
79
- expect do
80
- result
81
- end.to raise_error ActiveInteraction::InvalidValueError
97
+ it 'indicates an error' do
98
+ error = result.errors.first
99
+
100
+ expect(error).to be_an_instance_of ActiveInteraction::Filter::Error
101
+ expect(error.type).to be :invalid_type
82
102
  end
83
103
  end
84
104
  end
@@ -93,7 +113,7 @@ describe ActiveInteraction::TimeFilter, :filter do
93
113
  end
94
114
 
95
115
  it 'returns a Time' do
96
- expect(result).to eql Time.parse(value)
116
+ expect(result.value).to eql Time.parse(value)
97
117
  end
98
118
  end
99
119
 
@@ -110,17 +130,18 @@ describe ActiveInteraction::TimeFilter, :filter do
110
130
  include_context 'optional'
111
131
 
112
132
  it 'returns the default' do
113
- expect(result).to eql options[:default]
133
+ expect(result.value).to eql options[:default]
114
134
  end
115
135
  end
116
136
 
117
137
  context 'required' do
118
138
  include_context 'required'
119
139
 
120
- it 'raises an error' do
121
- expect do
122
- result
123
- end.to raise_error ActiveInteraction::MissingValueError
140
+ it 'indicates an error' do
141
+ error = result.errors.first
142
+
143
+ expect(error).to be_an_instance_of ActiveInteraction::Filter::Error
144
+ expect(error.type).to be :missing
124
145
  end
125
146
  end
126
147
  end
@@ -129,7 +150,7 @@ describe ActiveInteraction::TimeFilter, :filter do
129
150
  let(:value) { rand(1 << 16) }
130
151
 
131
152
  it 'returns the Time' do
132
- expect(result).to eql Time.at(value)
153
+ expect(result.value).to eql Time.at(value)
133
154
  end
134
155
  end
135
156
 
@@ -143,7 +164,7 @@ describe ActiveInteraction::TimeFilter, :filter do
143
164
  end
144
165
 
145
166
  it 'returns the Time' do
146
- expect(result).to eql Time.at(value)
167
+ expect(result.value).to eql Time.at(value)
147
168
  end
148
169
  end
149
170
 
@@ -167,7 +188,7 @@ describe ActiveInteraction::TimeFilter, :filter do
167
188
 
168
189
  it 'returns a Time' do
169
190
  expect(
170
- result
191
+ result.value
171
192
  ).to eql Time.new(year, month, day, hour, min, sec)
172
193
  end
173
194
  end
@@ -176,10 +197,11 @@ describe ActiveInteraction::TimeFilter, :filter do
176
197
  context 'empty' do
177
198
  let(:value) { ActiveInteraction::GroupedInput.new }
178
199
 
179
- it 'raises an error' do
180
- expect do
181
- result
182
- end.to raise_error ActiveInteraction::InvalidValueError
200
+ it 'indicates an error' do
201
+ error = result.errors.first
202
+
203
+ expect(error).to be_an_instance_of ActiveInteraction::Filter::Error
204
+ expect(error.type).to be :invalid_type
183
205
  end
184
206
  end
185
207
 
@@ -190,10 +212,11 @@ describe ActiveInteraction::TimeFilter, :filter do
190
212
  )
191
213
  end
192
214
 
193
- it 'raises an error' do
194
- expect do
195
- result
196
- end.to raise_error ActiveInteraction::InvalidValueError
215
+ it 'indicates an error' do
216
+ error = result.errors.first
217
+
218
+ expect(error).to be_an_instance_of ActiveInteraction::Filter::Error
219
+ expect(error.type).to be :invalid_type
197
220
  end
198
221
  end
199
222
  end
@@ -201,7 +224,7 @@ describe ActiveInteraction::TimeFilter, :filter do
201
224
 
202
225
  describe '#database_column_type' do
203
226
  it 'returns :datetime' do
204
- expect(filter.database_column_type).to eql :datetime
227
+ expect(filter.database_column_type).to be :datetime
205
228
  end
206
229
  end
207
230
 
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveInteraction::HashInput do
4
+ subject(:input) do
5
+ described_class.new(filter,
6
+ value: value,
7
+ error: error,
8
+ children: children
9
+ )
10
+ end
11
+
12
+ let(:filter) do
13
+ ActiveInteraction::HashFilter.new(:h, &block)
14
+ end
15
+ let(:block) { proc { integer :i } }
16
+ let(:value) { nil }
17
+ let(:error) { nil }
18
+ let(:children) { {} }
19
+
20
+ describe '#errors' do
21
+ context 'with no errors' do
22
+ it 'returns an empty array' do
23
+ expect(input.errors).to be_empty
24
+ end
25
+ end
26
+
27
+ context 'with an error on the hash' do
28
+ let(:error) { ActiveInteraction::Filter::Error.new(filter, :invalid_type) }
29
+
30
+ it 'returns one error in the array' do
31
+ expect(input.errors.size).to be 1
32
+
33
+ error = input.errors.first
34
+ expect(error.name).to be filter.name
35
+ expect(error.type).to be :invalid_type
36
+ end
37
+ end
38
+
39
+ context 'with children with errors' do
40
+ let(:child_i) do
41
+ filter = ActiveInteraction::IntegerFilter.new(:i)
42
+ ActiveInteraction::Input.new(filter,
43
+ value: nil,
44
+ error: ActiveInteraction::Filter::Error.new(filter, :missing)
45
+ )
46
+ end
47
+ let(:children) { { i: child_i } }
48
+
49
+ it 'returns the error' do
50
+ expect(input.errors.size).to be 1
51
+
52
+ error = input.errors.first
53
+ expect(error.name).to be :"#{filter.name}.i"
54
+ expect(error.type).to be :missing
55
+ end
56
+ end
57
+ end
58
+ end
@@ -15,20 +15,23 @@ I18nInteraction = Class.new(TestInteraction) do
15
15
  end
16
16
  end
17
17
 
18
+ TYPES = ActiveInteraction::Filter
19
+ .const_get(:CLASSES)
20
+ .keys
21
+ .map(&:to_s)
22
+
18
23
  describe I18nInteraction do
19
24
  include_context 'interactions'
20
25
 
21
- TYPES = ActiveInteraction::Filter # rubocop:disable Lint/ConstantDefinitionInBlock
22
- .const_get(:CLASSES)
23
- .map { |slug, _| slug.to_s }
24
-
25
26
  shared_examples 'translation' do |locale|
26
- before do
27
- @locale = I18n.locale
27
+ around do |example|
28
+ old_locale = I18n.locale
28
29
  I18n.locale = locale
29
- end
30
30
 
31
- after { I18n.locale = @locale }
31
+ example.run
32
+
33
+ I18n.locale = old_locale
34
+ end
32
35
 
33
36
  context 'types' do
34
37
  TYPES.each do |type|
@@ -81,16 +84,12 @@ describe I18nInteraction do
81
84
  end
82
85
 
83
86
  context 'hsilgne' do
84
- before do
85
- # This must appear before including the translation examples so that the
86
- # locale is available before it is assigned.
87
- locale = :hsilgne
88
- I18n.config.available_locales = I18n.config.available_locales + [locale] unless I18n.locale_available?(locale)
89
- end
87
+ # This must appear before including the translation examples so that the
88
+ # locale is available before it is assigned.
89
+ around do |example|
90
+ old_locals = I18n.config.available_locales
91
+ I18n.config.available_locales += [:hsilgne]
90
92
 
91
- include_examples 'translation', :hsilgne
92
-
93
- before do
94
93
  I18n.backend.store_translations('hsilgne',
95
94
  active_interaction: {
96
95
  errors: {
@@ -103,6 +102,12 @@ describe I18nInteraction do
103
102
  types: TYPES.each_with_object({}) { |e, a| a[e] = e.reverse }
104
103
  }
105
104
  )
105
+
106
+ example.run
107
+
108
+ I18n.config.available_locales = old_locals
106
109
  end
110
+
111
+ include_examples 'translation', :hsilgne
107
112
  end
108
113
  end
@@ -1,11 +1,14 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe ActiveInteraction::Inputs do
4
- subject(:inputs) { described_class.new }
4
+ subject(:inputs) { described_class.new(args, base_class.new) }
5
+
6
+ let(:args) { {} }
7
+ let(:base_class) { ActiveInteraction::Base }
5
8
 
6
9
  describe '.reserved?(name)' do
7
10
  it 'returns true for anything starting with "_interaction_"' do
8
- expect(described_class.reserved?('_interaction_')).to be_truthy
11
+ expect(described_class).to be_reserved('_interaction_')
9
12
  end
10
13
 
11
14
  it 'returns true for existing instance methods' do
@@ -13,21 +16,20 @@ describe ActiveInteraction::Inputs do
13
16
  (ActiveInteraction::Base.instance_methods - Object.instance_methods) +
14
17
  (ActiveInteraction::Base.private_instance_methods - Object.private_instance_methods)
15
18
  ).each do |method|
16
- expect(described_class.reserved?(method)).to be_truthy
19
+ expect(described_class).to be_reserved(method)
17
20
  end
18
21
  end
19
22
 
20
23
  it 'returns false for anything else' do
21
- expect(described_class.reserved?(SecureRandom.hex)).to be_falsey
24
+ expect(described_class).to_not be_reserved(SecureRandom.hex)
22
25
  end
23
26
  end
24
27
 
25
- describe '.process(inputs)' do
26
- let(:inputs) { {} }
27
- let(:result) { described_class.process(inputs) }
28
+ describe '#normalized' do
29
+ let(:result) { inputs.normalized }
28
30
 
29
31
  context 'with invalid inputs' do
30
- let(:inputs) { nil }
32
+ let(:args) { nil }
31
33
 
32
34
  it 'raises an error' do
33
35
  expect { result }.to raise_error ArgumentError
@@ -35,7 +37,7 @@ describe ActiveInteraction::Inputs do
35
37
  end
36
38
 
37
39
  context 'with non-hash inputs' do
38
- let(:inputs) { [%i[k v]] }
40
+ let(:args) { [%i[k v]] }
39
41
 
40
42
  it 'raises an error' do
41
43
  expect { result }.to raise_error ArgumentError
@@ -43,15 +45,7 @@ describe ActiveInteraction::Inputs do
43
45
  end
44
46
 
45
47
  context 'with ActionController::Parameters inputs' do
46
- let(:inputs) { ActionController::Parameters.new }
47
-
48
- it 'does not raise an error' do
49
- expect { result }.to_not raise_error
50
- end
51
- end
52
-
53
- context 'with Inputs inputs' do
54
- let(:inputs) { ActiveInteraction::Inputs.new }
48
+ let(:args) { ::ActionController::Parameters.new }
55
49
 
56
50
  it 'does not raise an error' do
57
51
  expect { result }.to_not raise_error
@@ -59,17 +53,17 @@ describe ActiveInteraction::Inputs do
59
53
  end
60
54
 
61
55
  context 'with simple inputs' do
62
- before { inputs[:key] = :value }
56
+ before { args[:key] = :value }
63
57
 
64
58
  it 'sends them straight through' do
65
- expect(result).to eql inputs
59
+ expect(result).to eql args
66
60
  end
67
61
  end
68
62
 
69
63
  context 'with groupable inputs' do
70
64
  context 'without a matching simple input' do
71
65
  before do
72
- inputs.merge!(
66
+ args.merge!(
73
67
  'key(1i)' => :value1,
74
68
  'key(2i)' => :value2
75
69
  )
@@ -87,7 +81,7 @@ describe ActiveInteraction::Inputs do
87
81
 
88
82
  context 'with a matching simple input' do
89
83
  before do
90
- inputs.merge!(
84
+ args.merge!(
91
85
  'key(1i)' => :value1,
92
86
  key: :value2
93
87
  )
@@ -104,11 +98,161 @@ describe ActiveInteraction::Inputs do
104
98
  end
105
99
 
106
100
  context 'with a reserved name' do
107
- before { inputs[:_interaction_key] = :value }
101
+ before { args[:_interaction_key] = :value }
108
102
 
109
103
  it 'skips the input' do
110
104
  expect(result).to_not have_key(:_interaction_key)
111
105
  end
112
106
  end
113
107
  end
108
+
109
+ describe '#given?' do
110
+ let(:base_class) do
111
+ Class.new(ActiveInteraction::Base) do
112
+ float :x,
113
+ default: nil
114
+
115
+ def execute; end
116
+ end
117
+ end
118
+
119
+ it 'is false when the input is not given' do
120
+ expect(inputs.given?(:x)).to be false
121
+ end
122
+
123
+ it 'is true when the input is nil' do
124
+ args[:x] = nil
125
+ expect(inputs.given?(:x)).to be true
126
+ end
127
+
128
+ it 'is true when the input is given' do
129
+ args[:x] = rand
130
+ expect(inputs.given?(:x)).to be true
131
+ end
132
+
133
+ it 'symbolizes its argument' do
134
+ args[:x] = rand
135
+ expect(inputs.given?('x')).to be true
136
+ end
137
+
138
+ it 'only tracks inputs with filters' do
139
+ args[:y] = rand
140
+ expect(inputs.given?(:y)).to be false
141
+ end
142
+
143
+ context 'nested hash values' do
144
+ let(:base_class) do
145
+ Class.new(ActiveInteraction::Base) do
146
+ hash :x, default: {} do
147
+ boolean :y,
148
+ default: true
149
+ end
150
+
151
+ def execute; end
152
+ end
153
+ end
154
+
155
+ it 'is true when the nested inputs symbols are given' do
156
+ described_class.class_exec do
157
+ def execute
158
+ given?(:x, :y)
159
+ end
160
+ end
161
+
162
+ args[:x] = { y: false }
163
+ expect(inputs.given?(:x, :y)).to be true
164
+ end
165
+
166
+ it 'is true when the nested inputs strings are given' do
167
+ args['x'] = { 'y' => false }
168
+ expect(inputs.given?(:x, :y)).to be true
169
+ end
170
+
171
+ it 'is false when the nested input is not given' do
172
+ args[:x] = {}
173
+ expect(inputs.given?(:x, :y)).to be false
174
+ end
175
+
176
+ it 'is false when the first input is not given' do
177
+ expect(inputs.given?(:x, :y)).to be false
178
+ end
179
+
180
+ it 'is false when the first input is nil' do
181
+ args[:x] = nil
182
+ expect(inputs.given?(:x, :y)).to be false
183
+ end
184
+
185
+ it 'returns false if you go too far' do
186
+ args[:x] = { y: true }
187
+ expect(inputs.given?(:x, :y, :z)).to be false
188
+ end
189
+ end
190
+
191
+ context 'nested array values' do
192
+ let(:base_class) do
193
+ Class.new(ActiveInteraction::Base) do
194
+ array :x do
195
+ hash do
196
+ boolean :y, default: true
197
+ end
198
+ end
199
+
200
+ def execute; end
201
+ end
202
+ end
203
+
204
+ context 'has a positive index' do
205
+ it 'returns true if found' do
206
+ args[:x] = [{ y: true }]
207
+ expect(inputs.given?(:x, 0, :y)).to be true
208
+ end
209
+
210
+ it 'returns false if not found' do
211
+ args[:x] = []
212
+ expect(inputs.given?(:x, 0, :y)).to be false
213
+ end
214
+ end
215
+
216
+ context 'has a negative index' do
217
+ it 'returns true if found' do
218
+ args[:x] = [{ y: true }]
219
+ expect(inputs.given?(:x, -1, :y)).to be true
220
+ end
221
+
222
+ it 'returns false if not found' do
223
+ args[:x] = []
224
+ expect(inputs.given?(:x, -1, :y)).to be false
225
+ end
226
+ end
227
+
228
+ it 'returns false if you go too far' do
229
+ args[:x] = [{}]
230
+ expect(inputs.given?(:x, 10, :y)).to be false
231
+ end
232
+ end
233
+
234
+ context 'multi-part date values' do
235
+ let(:base_class) do
236
+ Class.new(ActiveInteraction::Base) do
237
+ date :thing,
238
+ default: nil
239
+
240
+ def execute; end
241
+ end
242
+ end
243
+
244
+ it 'returns true when the input is given' do
245
+ args.merge!(
246
+ 'thing(1i)' => '2020',
247
+ 'thing(2i)' => '12',
248
+ 'thing(3i)' => '31'
249
+ )
250
+ expect(inputs.given?(:thing)).to be true
251
+ end
252
+
253
+ it 'returns false if not found' do
254
+ expect(inputs.given?(:thing)).to be false
255
+ end
256
+ end
257
+ end
114
258
  end
@@ -1,10 +1,6 @@
1
1
  require 'spec_helper'
2
2
  require 'active_record'
3
- if defined?(JRUBY_VERSION)
4
- require 'activerecord-jdbcsqlite3-adapter'
5
- else
6
- require 'sqlite3'
7
- end
3
+ require 'sqlite3'
8
4
 
9
5
  ActiveRecord::Base.establish_connection(
10
6
  adapter: 'sqlite3',
@@ -36,8 +32,8 @@ end
36
32
  describe ArrayInteraction do
37
33
  include_context 'interactions'
38
34
  it_behaves_like 'an interaction', :array, -> { [] }
39
- it_behaves_like 'an interaction', :array, -> { Element.where('1 = 1') }
40
- it_behaves_like 'an interaction', :array, -> { List.create!.elements }
35
+ it_behaves_like 'an interaction', :array, -> { Element.where('1 = 1') }, ->(result) { result.to_a }
36
+ it_behaves_like 'an interaction', :array, -> { List.create!.elements }, ->(result) { result.to_a }
41
37
 
42
38
  context 'with inputs[:a]' do
43
39
  let(:a) { [[]] }
@@ -22,11 +22,11 @@ describe ActiveInteraction::Validation do
22
22
  end
23
23
  end
24
24
 
25
- context 'filter.cast returns a value' do
25
+ context 'filter returns no errors' do
26
26
  let(:inputs) { { name: 1 } }
27
27
 
28
28
  before do
29
- allow(filter).to receive(:cast).and_return(1)
29
+ allow(filter).to receive(:process).and_return(ActiveInteraction::Input.new(filter, value: 1))
30
30
  end
31
31
 
32
32
  it 'returns no errors' do
@@ -34,14 +34,15 @@ describe ActiveInteraction::Validation do
34
34
  end
35
35
  end
36
36
 
37
- context 'filter throws' do
37
+ context 'filter returns with errors' do
38
38
  before do
39
- allow(filter).to receive(:cast).and_raise(exception)
39
+ allow(filter).to receive(:process).and_return(ActiveInteraction::Input.new(filter, error: exception))
40
40
  end
41
41
 
42
- context 'InvalidValueError' do
43
- let(:exception) { ActiveInteraction::InvalidValueError }
44
- let(:filter) { ActiveInteraction::FloatFilter.new(:name, {}) }
42
+ context 'Filter::Error' do
43
+ let(:filter) { ActiveInteraction::ArrayFilter.new(:name, [1.0, 'a']) { float } }
44
+
45
+ let(:exception) { ActiveInteraction::Filter::Error.new(filter, :invalid_type) }
45
46
 
46
47
  it 'returns an :invalid_type error' do
47
48
  type = I18n.translate(
@@ -51,30 +52,6 @@ describe ActiveInteraction::Validation do
51
52
  expect(result).to eql [[filter.name, :invalid_type, { type: type }]]
52
53
  end
53
54
  end
54
-
55
- context 'MissingValueError' do
56
- let(:exception) { ActiveInteraction::MissingValueError }
57
-
58
- it 'returns a :missing error' do
59
- expect(result).to eql [[filter.name, :missing]]
60
- end
61
- end
62
-
63
- context 'InvalidNestedValueError' do
64
- let(:exception) do
65
- ActiveInteraction::InvalidNestedValueError.new(name, value)
66
- end
67
- let(:name) { SecureRandom.hex.to_sym }
68
- let(:value) { double }
69
-
70
- it 'returns an :invalid_nested error' do
71
- expect(result).to eql [[
72
- filter.name,
73
- :invalid_nested,
74
- { name: name.inspect, value: value.inspect }
75
- ]]
76
- end
77
- end
78
55
  end
79
56
  end
80
57
  end
data/spec/spec_helper.rb CHANGED
@@ -8,4 +8,12 @@ Dir['./spec/support/**/*.rb'].sort.each { |f| require f }
8
8
  RSpec.configure do |config|
9
9
  config.run_all_when_everything_filtered = true
10
10
  config.filter_run_including :focus
11
+
12
+ config.before(:suite) do
13
+ if ::ActiveRecord.respond_to?(:index_nested_attribute_errors)
14
+ ::ActiveRecord.index_nested_attribute_errors = false
15
+ else
16
+ ::ActiveRecord::Base.index_nested_attribute_errors = false
17
+ end
18
+ end
11
19
  end
@@ -1,4 +1,6 @@
1
1
  shared_context 'concerns' do |concern|
2
+ subject(:instance) { klass.new }
3
+
2
4
  let(:klass) do
3
5
  Class.new do
4
6
  include concern
@@ -8,6 +10,4 @@ shared_context 'concerns' do |concern|
8
10
  end
9
11
  end
10
12
  end
11
-
12
- subject(:instance) { klass.new }
13
13
  end