active_interaction 4.1.0 → 5.1.1

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 +150 -1
  3. data/CONTRIBUTING.md +11 -3
  4. data/README.md +256 -215
  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 +40 -52
  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 +27 -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 +43 -44
  79. data/lib/active_interaction/filter_column.rb +0 -57
@@ -14,11 +14,7 @@ class RecordThing
14
14
  end
15
15
 
16
16
  def self.finds_bad_value(_)
17
- ''
18
- end
19
-
20
- def self.passthrough(obj)
21
- obj
17
+ Object.new
22
18
  end
23
19
  end
24
20
 
@@ -27,23 +23,19 @@ BackupRecordThing = RecordThing
27
23
 
28
24
  describe ActiveInteraction::RecordFilter, :filter do
29
25
  include_context 'filters'
30
- it_behaves_like 'a filter'
31
-
32
26
  before do
33
27
  options[:class] = RecordThing
34
28
  end
35
29
 
36
- describe '#cast' do
37
- before do
38
- options[:finder] = :finder
39
- end
30
+ it_behaves_like 'a filter'
40
31
 
32
+ describe '#process' do
41
33
  let(:value) { RecordThing.new }
42
- let(:result) { filter.send(:cast, value, nil) }
34
+ let(:result) { filter.process(value, nil) }
43
35
 
44
36
  context 'with an instance of the class' do
45
37
  it 'returns the instance' do
46
- expect(result).to eql value
38
+ expect(result.value).to eql value
47
39
  end
48
40
 
49
41
  context 'with an instance that is a subclass' do
@@ -51,18 +43,18 @@ describe ActiveInteraction::RecordFilter, :filter do
51
43
  let(:value) { subclass.new }
52
44
 
53
45
  it 'returns the instance' do
54
- expect(result).to eql value
46
+ expect(result.value).to eql value
55
47
  end
56
48
  end
57
49
 
58
50
  it 'handles reconstantizing' do
59
- expect(result).to eql value
51
+ expect(result.value).to eql value
60
52
 
61
53
  Object.send(:remove_const, :RecordThing)
62
54
  RecordThing = BackupRecordThing # rubocop:disable Lint/ConstantDefinitionInBlock
63
55
  value = RecordThing.new
64
56
 
65
- expect(filter.send(:cast, value, nil)).to eql value
57
+ expect(filter.process(value, nil).value).to eql value
66
58
  end
67
59
 
68
60
  it 'handles reconstantizing subclasses' do
@@ -73,11 +65,12 @@ describe ActiveInteraction::RecordFilter, :filter do
73
65
  class SubRecordThing < RecordThing; end # rubocop:disable Lint/ConstantDefinitionInBlock
74
66
  value = SubRecordThing.new
75
67
 
76
- expect(filter.send(:cast, value, nil)).to eql value
68
+ expect(filter.process(value, nil).value).to eql value
77
69
  end
78
70
 
79
71
  context 'without the class available' do
80
72
  before { Object.send(:remove_const, :RecordThing) }
73
+
81
74
  after { RecordThing = BackupRecordThing } # rubocop:disable Lint/ConstantDefinitionInBlock
82
75
 
83
76
  it 'does not raise an error on initialization' do
@@ -92,7 +85,7 @@ describe ActiveInteraction::RecordFilter, :filter do
92
85
  end
93
86
 
94
87
  it 'returns the instance' do
95
- expect(result).to eql value
88
+ expect(result.value).to eql value
96
89
  end
97
90
  end
98
91
 
@@ -102,7 +95,7 @@ describe ActiveInteraction::RecordFilter, :filter do
102
95
  end
103
96
 
104
97
  it 'returns the instance' do
105
- expect(result).to eql value
98
+ expect(result.value).to eql value
106
99
  end
107
100
  end
108
101
 
@@ -112,7 +105,7 @@ describe ActiveInteraction::RecordFilter, :filter do
112
105
  before { options[:class] = RecordThings }
113
106
 
114
107
  it 'returns the instance' do
115
- expect(result).to eql value
108
+ expect(result.value).to eql value
116
109
  end
117
110
  end
118
111
 
@@ -129,48 +122,77 @@ describe ActiveInteraction::RecordFilter, :filter do
129
122
  end
130
123
 
131
124
  context 'with a value that does not match the class' do
132
- let(:value) { '' }
125
+ let(:value) { 1 }
133
126
 
134
- it 'calls the finder' do
135
- expect(result).to eql RecordThing.finder(value)
127
+ it 'calls the default finder' do
128
+ allow(RecordThing).to receive(:find)
129
+ result
130
+ expect(RecordThing).to have_received(:find).with(value)
136
131
  end
137
132
 
138
133
  context 'with a custom finder' do
134
+ before do
135
+ options[:finder] = :finder
136
+ end
137
+
139
138
  it 'calls the custom finder' do
140
- expect(result).to eql RecordThing.finder(value)
139
+ allow(RecordThing).to receive(:finder)
140
+ result
141
+ expect(RecordThing).to have_received(:finder).with(value)
141
142
  end
142
143
  end
143
- end
144
- end
145
144
 
146
- describe '#clean' do
147
- context 'with a value that does not match the class' do
148
145
  context 'that returns a nil' do
149
- let(:value) { '' }
146
+ let(:value) { 1 }
150
147
 
151
148
  before do
152
149
  options[:default] = RecordThing.new
153
150
  options[:finder] = :finds_nil
154
151
  end
155
152
 
156
- it 'raises an error' do
157
- expect do
158
- filter.clean(value, nil)
159
- end.to raise_error ActiveInteraction::InvalidValueError
153
+ it 'indicates an error' do
154
+ error = filter.process(value, nil).errors.first
155
+
156
+ expect(error).to be_an_instance_of ActiveInteraction::Filter::Error
157
+ expect(error.type).to be :invalid_type
160
158
  end
161
159
  end
162
160
 
163
161
  context 'that returns an invalid value' do
164
- let(:value) { '' }
162
+ let(:value) { 1 }
165
163
 
166
164
  before do
167
165
  options[:finder] = :finds_bad_value
168
166
  end
169
167
 
170
- it 'raises an error' do
171
- expect do
172
- filter.clean(value, nil)
173
- end.to raise_error ActiveInteraction::InvalidValueError
168
+ it 'indicates an error' do
169
+ error = filter.process(value, nil).errors.first
170
+
171
+ expect(error).to be_an_instance_of ActiveInteraction::Filter::Error
172
+ expect(error.type).to be :invalid_type
173
+ end
174
+ end
175
+ end
176
+
177
+ context 'with a blank String' do
178
+ let(:value) { ' ' }
179
+
180
+ context 'optional' do
181
+ include_context 'optional'
182
+
183
+ it 'returns the default' do
184
+ expect(filter.process(value, nil).value).to eql options[:default]
185
+ end
186
+ end
187
+
188
+ context 'required' do
189
+ include_context 'required'
190
+
191
+ it 'indicates an error' do
192
+ error = filter.process(value, nil).errors.first
193
+
194
+ expect(error).to be_an_instance_of ActiveInteraction::Filter::Error
195
+ expect(error.type).to be :missing
174
196
  end
175
197
  end
176
198
  end
@@ -178,7 +200,7 @@ describe ActiveInteraction::RecordFilter, :filter do
178
200
 
179
201
  describe '#database_column_type' do
180
202
  it 'returns :string' do
181
- expect(filter.database_column_type).to eql :string
203
+ expect(filter.database_column_type).to be :string
182
204
  end
183
205
  end
184
206
  end
@@ -10,14 +10,14 @@ describe ActiveInteraction::StringFilter, :filter do
10
10
  end
11
11
  end
12
12
 
13
- describe '#cast' do
14
- let(:result) { filter.send(:cast, value, nil) }
13
+ describe '#process' do
14
+ let(:result) { filter.process(value, nil) }
15
15
 
16
16
  context 'with a String' do
17
17
  let(:value) { SecureRandom.hex }
18
18
 
19
19
  it 'returns the String' do
20
- expect(result).to eql value
20
+ expect(result.value).to eql value
21
21
  end
22
22
  end
23
23
 
@@ -31,7 +31,7 @@ describe ActiveInteraction::StringFilter, :filter do
31
31
  end
32
32
 
33
33
  it 'returns the String' do
34
- expect(result).to eql value.to_str
34
+ expect(result.value).to eql value.to_str
35
35
  end
36
36
  end
37
37
 
@@ -39,14 +39,14 @@ describe ActiveInteraction::StringFilter, :filter do
39
39
  let(:value) { " #{SecureRandom.hex} " }
40
40
 
41
41
  it 'returns the stripped string' do
42
- expect(result).to eql value.strip
42
+ expect(result.value).to eql value.strip
43
43
  end
44
44
 
45
45
  context 'without strip' do
46
46
  include_context 'without strip'
47
47
 
48
48
  it 'returns the String' do
49
- expect(result).to eql value
49
+ expect(result.value).to eql value
50
50
  end
51
51
  end
52
52
  end
@@ -54,7 +54,7 @@ describe ActiveInteraction::StringFilter, :filter do
54
54
 
55
55
  describe '#database_column_type' do
56
56
  it 'returns :string' do
57
- expect(filter.database_column_type).to eql :string
57
+ expect(filter.database_column_type).to be :string
58
58
  end
59
59
  end
60
60
  end
@@ -4,14 +4,14 @@ describe ActiveInteraction::SymbolFilter, :filter do
4
4
  include_context 'filters'
5
5
  it_behaves_like 'a filter'
6
6
 
7
- describe '#cast' do
8
- let(:result) { filter.send(:cast, value, nil) }
7
+ describe '#process' do
8
+ let(:result) { filter.process(value, nil) }
9
9
 
10
10
  context 'with a Symbol' do
11
11
  let(:value) { SecureRandom.hex.to_sym }
12
12
 
13
13
  it 'returns the Symbol' do
14
- expect(result).to eql value
14
+ expect(result.value).to eql value
15
15
  end
16
16
  end
17
17
 
@@ -25,7 +25,7 @@ describe ActiveInteraction::SymbolFilter, :filter do
25
25
  end
26
26
 
27
27
  it 'returns a symbol' do
28
- expect(result).to eql value.to_sym
28
+ expect(result.value).to eql value.to_sym
29
29
  end
30
30
  end
31
31
 
@@ -33,14 +33,14 @@ describe ActiveInteraction::SymbolFilter, :filter do
33
33
  let(:value) { SecureRandom.hex }
34
34
 
35
35
  it 'returns a Symbol' do
36
- expect(result).to eql value.to_sym
36
+ expect(result.value).to eql value.to_sym
37
37
  end
38
38
  end
39
39
  end
40
40
 
41
41
  describe '#database_column_type' do
42
42
  it 'returns :string' do
43
- expect(filter.database_column_type).to eql :string
43
+ expect(filter.database_column_type).to be :string
44
44
  end
45
45
  end
46
46
  end
@@ -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