dry-validation 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +1 -0
- data/.travis.yml +3 -2
- data/CHANGELOG.md +42 -0
- data/Gemfile +8 -1
- data/README.md +13 -89
- data/config/errors.yml +35 -29
- data/dry-validation.gemspec +2 -2
- data/examples/basic.rb +3 -7
- data/examples/each.rb +3 -8
- data/examples/form.rb +3 -6
- data/examples/nested.rb +7 -15
- data/lib/dry/validation.rb +33 -5
- data/lib/dry/validation/error.rb +10 -26
- data/lib/dry/validation/error_compiler.rb +69 -99
- data/lib/dry/validation/error_compiler/input.rb +148 -0
- data/lib/dry/validation/hint_compiler.rb +83 -33
- data/lib/dry/validation/input_processor_compiler.rb +98 -0
- data/lib/dry/validation/input_processor_compiler/form.rb +46 -0
- data/lib/dry/validation/input_processor_compiler/sanitizer.rb +46 -0
- data/lib/dry/validation/messages/abstract.rb +30 -10
- data/lib/dry/validation/messages/i18n.rb +2 -1
- data/lib/dry/validation/messages/namespaced.rb +1 -0
- data/lib/dry/validation/messages/yaml.rb +8 -5
- data/lib/dry/validation/result.rb +33 -25
- data/lib/dry/validation/schema.rb +168 -61
- data/lib/dry/validation/schema/attr.rb +5 -27
- data/lib/dry/validation/schema/check.rb +24 -0
- data/lib/dry/validation/schema/dsl.rb +97 -0
- data/lib/dry/validation/schema/form.rb +2 -26
- data/lib/dry/validation/schema/key.rb +32 -28
- data/lib/dry/validation/schema/rule.rb +88 -32
- data/lib/dry/validation/schema/value.rb +77 -27
- data/lib/dry/validation/schema_compiler.rb +38 -0
- data/lib/dry/validation/version.rb +1 -1
- data/spec/fixtures/locales/pl.yml +1 -1
- data/spec/integration/attr_spec.rb +122 -0
- data/spec/integration/custom_error_messages_spec.rb +9 -11
- data/spec/integration/custom_predicates_spec.rb +68 -18
- data/spec/integration/error_compiler_spec.rb +259 -65
- data/spec/integration/hints_spec.rb +28 -9
- data/spec/integration/injecting_rules_spec.rb +11 -12
- data/spec/integration/localized_error_messages_spec.rb +16 -16
- data/spec/integration/messages/i18n_spec.rb +9 -5
- data/spec/integration/optional_keys_spec.rb +9 -11
- data/spec/integration/schema/array_schema_spec.rb +23 -0
- data/spec/integration/schema/check_rules_spec.rb +39 -31
- data/spec/integration/schema/check_with_nth_el_spec.rb +25 -0
- data/spec/integration/schema/each_with_set_spec.rb +23 -24
- data/spec/integration/schema/form_spec.rb +122 -0
- data/spec/integration/schema/inheriting_schema_spec.rb +31 -0
- data/spec/integration/schema/input_processor_spec.rb +46 -0
- data/spec/integration/schema/macros/confirmation_spec.rb +33 -0
- data/spec/integration/schema/macros/maybe_spec.rb +32 -0
- data/spec/integration/schema/macros/required_spec.rb +59 -0
- data/spec/integration/schema/macros/when_spec.rb +65 -0
- data/spec/integration/schema/nested_values_spec.rb +41 -0
- data/spec/integration/schema/not_spec.rb +14 -14
- data/spec/integration/schema/option_with_default_spec.rb +30 -0
- data/spec/integration/schema/reusing_schema_spec.rb +33 -0
- data/spec/integration/schema/using_types_spec.rb +29 -0
- data/spec/integration/schema/xor_spec.rb +17 -14
- data/spec/integration/schema_spec.rb +75 -245
- data/spec/shared/rule_compiler.rb +8 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/unit/hint_compiler_spec.rb +10 -10
- data/spec/unit/{input_type_compiler_spec.rb → input_processor_compiler/form_spec.rb} +88 -73
- data/spec/unit/schema/key_spec.rb +33 -0
- data/spec/unit/schema/rule_spec.rb +7 -6
- data/spec/unit/schema/value_spec.rb +187 -54
- metadata +53 -31
- data/.rubocop.yml +0 -16
- data/.rubocop_todo.yml +0 -7
- data/lib/dry/validation/input_type_compiler.rb +0 -83
- data/lib/dry/validation/schema/definition.rb +0 -74
- data/lib/dry/validation/schema/result.rb +0 -68
- data/rakelib/rubocop.rake +0 -18
- data/spec/integration/rule_groups_spec.rb +0 -94
- data/spec/integration/schema/attrs_spec.rb +0 -38
- data/spec/integration/schema/default_key_behavior_spec.rb +0 -23
- data/spec/integration/schema/grouped_rules_spec.rb +0 -57
- data/spec/integration/schema/nested_spec.rb +0 -31
- data/spec/integration/schema_form_spec.rb +0 -97
@@ -1,19 +1,23 @@
|
|
1
1
|
require 'dry/validation/messages/i18n'
|
2
2
|
|
3
3
|
RSpec.describe 'Validation hints' do
|
4
|
-
subject(:validation) { schema.new }
|
5
|
-
|
6
4
|
shared_context '#messages' do
|
7
5
|
it 'provides hints for additional rules that were not checked' do
|
8
|
-
expect(
|
9
|
-
age: [
|
6
|
+
expect(schema.(age: '17').messages).to eql(
|
7
|
+
age: ['must be an integer', 'must be greater than 18']
|
8
|
+
)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'skips type-check rules' do
|
12
|
+
expect(schema.(age: 17).messages).to eql(
|
13
|
+
age: ['must be greater than 18']
|
10
14
|
)
|
11
15
|
end
|
12
16
|
end
|
13
17
|
|
14
18
|
context 'with yaml messages' do
|
15
|
-
|
16
|
-
|
19
|
+
subject(:schema) do
|
20
|
+
Dry::Validation.Schema do
|
17
21
|
key(:age) do |age|
|
18
22
|
age.none? | (age.int? & age.gt?(18))
|
19
23
|
end
|
@@ -24,9 +28,9 @@ RSpec.describe 'Validation hints' do
|
|
24
28
|
end
|
25
29
|
|
26
30
|
context 'with i18n messages' do
|
27
|
-
|
28
|
-
|
29
|
-
configure { |c| c.messages = :i18n }
|
31
|
+
subject(:schema) do
|
32
|
+
Dry::Validation.Schema do
|
33
|
+
configure { configure { |c| c.messages = :i18n } }
|
30
34
|
|
31
35
|
key(:age) do |age|
|
32
36
|
age.none? | (age.int? & age.gt?(18))
|
@@ -36,4 +40,19 @@ RSpec.describe 'Validation hints' do
|
|
36
40
|
|
37
41
|
include_context '#messages'
|
38
42
|
end
|
43
|
+
|
44
|
+
context 'when type expectation is specified' do
|
45
|
+
subject(:schema) do
|
46
|
+
Dry::Validation.Schema do
|
47
|
+
key(:email).required
|
48
|
+
key(:name).required(:str?, size?: 5..25)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'infers message for specific type' do
|
53
|
+
expect(schema.(email: 'jane@doe', name: 'HN').messages).to eql(
|
54
|
+
name: ['length must be within 5 - 25']
|
55
|
+
)
|
56
|
+
end
|
57
|
+
end
|
39
58
|
end
|
@@ -1,23 +1,22 @@
|
|
1
1
|
RSpec.describe 'Schema / Injecting Rules' do
|
2
|
-
|
2
|
+
subject(:schema) do
|
3
|
+
Dry::Validation.Schema(rules: other.class.rules) do
|
4
|
+
key(:email).maybe
|
3
5
|
|
4
|
-
|
5
|
-
Class.new(Dry::Validation::Schema) do
|
6
|
-
key(:login) { |value| value.bool? }
|
6
|
+
rule(:email) { value(:login).true? > value(:email).filled? }
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
-
let(:
|
11
|
-
|
12
|
-
key(:
|
13
|
-
|
14
|
-
rule(email: :filled?) { value(:login).true? > value(:email).filled? }
|
10
|
+
let(:other) do
|
11
|
+
Dry::Validation.Schema do
|
12
|
+
key(:login) { |value| value.bool? }
|
15
13
|
end
|
16
14
|
end
|
17
15
|
|
18
16
|
it 'appends rules from another schema' do
|
19
|
-
expect(
|
20
|
-
expect(
|
21
|
-
expect(
|
17
|
+
expect(schema.(login: true, email: 'jane@doe')).to be_success
|
18
|
+
expect(schema.(login: false, email: nil)).to be_success
|
19
|
+
expect(schema.(login: true, email: nil)).to_not be_success
|
20
|
+
expect(schema.(login: nil, email: 'jane@doe')).to_not be_success
|
22
21
|
end
|
23
22
|
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
require 'dry/validation/messages/i18n'
|
2
2
|
|
3
3
|
RSpec.describe Dry::Validation, 'with localized messages' do
|
4
|
-
subject(:validation) { schema.new }
|
5
|
-
|
6
4
|
before do
|
7
5
|
I18n.config.available_locales_set << :pl
|
8
6
|
I18n.load_path.concat(%w(en pl).map { |l| SPEC_ROOT.join("fixtures/locales/#{l}.yml") })
|
@@ -11,9 +9,9 @@ RSpec.describe Dry::Validation, 'with localized messages' do
|
|
11
9
|
|
12
10
|
describe 'defining schema' do
|
13
11
|
context 'without a namespace' do
|
14
|
-
|
15
|
-
|
16
|
-
configure do
|
12
|
+
subject(:schema) do
|
13
|
+
Dry::Validation.Schema do
|
14
|
+
configure do
|
17
15
|
config.messages = :i18n
|
18
16
|
end
|
19
17
|
|
@@ -23,19 +21,21 @@ RSpec.describe Dry::Validation, 'with localized messages' do
|
|
23
21
|
|
24
22
|
describe '#messages' do
|
25
23
|
it 'returns localized error messages' do
|
26
|
-
expect(
|
27
|
-
|
28
|
-
|
24
|
+
expect(schema.(email: '').messages(locale: :pl)).to eql(
|
25
|
+
email: ['Proszę podać adres email']
|
26
|
+
)
|
29
27
|
end
|
30
28
|
end
|
31
29
|
end
|
32
30
|
|
33
31
|
context 'with a namespace' do
|
34
|
-
|
35
|
-
|
36
|
-
configure do
|
37
|
-
|
38
|
-
|
32
|
+
subject(:schema) do
|
33
|
+
Dry::Validation.Schema do
|
34
|
+
configure do
|
35
|
+
configure do |config|
|
36
|
+
config.messages = :i18n
|
37
|
+
config.namespace = :user
|
38
|
+
end
|
39
39
|
end
|
40
40
|
|
41
41
|
key(:email) { |email| email.filled? }
|
@@ -44,9 +44,9 @@ RSpec.describe Dry::Validation, 'with localized messages' do
|
|
44
44
|
|
45
45
|
describe '#messages' do
|
46
46
|
it 'returns localized error messages' do
|
47
|
-
expect(
|
48
|
-
|
49
|
-
|
47
|
+
expect(schema.(email: '').messages(locale: :pl)).to eql(
|
48
|
+
email: ['Hej user! Dawaj ten email no!']
|
49
|
+
)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|
@@ -11,10 +11,14 @@ RSpec.describe Messages::I18n do
|
|
11
11
|
|
12
12
|
describe '#[]' do
|
13
13
|
context 'with the default locale' do
|
14
|
+
it 'returns nil when message is not defined' do
|
15
|
+
expect(messages[:not_here, rule: :srsly]).to be(nil)
|
16
|
+
end
|
17
|
+
|
14
18
|
it 'returns a message for a predicate' do
|
15
19
|
message = messages[:filled?, rule: :name]
|
16
20
|
|
17
|
-
expect(message).to eql("
|
21
|
+
expect(message).to eql("must be filled")
|
18
22
|
end
|
19
23
|
|
20
24
|
it 'returns a message for a specific rule' do
|
@@ -26,19 +30,19 @@ RSpec.describe Messages::I18n do
|
|
26
30
|
it 'returns a message for a specific val type' do
|
27
31
|
message = messages[:size?, rule: :pages, val_type: String]
|
28
32
|
|
29
|
-
expect(message).to eql("
|
33
|
+
expect(message).to eql("length must be %{num}")
|
30
34
|
end
|
31
35
|
|
32
36
|
it 'returns a message for a specific rule and its default arg type' do
|
33
37
|
message = messages[:size?, rule: :pages]
|
34
38
|
|
35
|
-
expect(message).to eql("
|
39
|
+
expect(message).to eql("size must be %{num}")
|
36
40
|
end
|
37
41
|
|
38
42
|
it 'returns a message for a specific rule and its arg type' do
|
39
43
|
message = messages[:size?, rule: :pages, arg_type: Range]
|
40
44
|
|
41
|
-
expect(message).to eql("
|
45
|
+
expect(message).to eql("size must be within %{left} - %{right}")
|
42
46
|
end
|
43
47
|
end
|
44
48
|
|
@@ -46,7 +50,7 @@ RSpec.describe Messages::I18n do
|
|
46
50
|
it 'returns a message for a predicate' do
|
47
51
|
message = messages[:filled?, rule: :name, locale: :pl]
|
48
52
|
|
49
|
-
expect(message).to eql("
|
53
|
+
expect(message).to eql("nie może być pusty")
|
50
54
|
end
|
51
55
|
|
52
56
|
it 'returns a message for a specific rule' do
|
@@ -1,17 +1,15 @@
|
|
1
1
|
RSpec.describe Dry::Validation::Schema do
|
2
|
-
subject(:validation) { schema.new }
|
3
|
-
|
4
2
|
describe 'defining schema with optional keys' do
|
5
|
-
|
6
|
-
|
3
|
+
subject(:schema) do
|
4
|
+
Dry::Validation.Schema do
|
7
5
|
optional(:email) { |email| email.filled? }
|
8
6
|
|
9
|
-
key(:address) do
|
10
|
-
|
11
|
-
|
7
|
+
key(:address) do
|
8
|
+
key(:city, &:filled?)
|
9
|
+
key(:street, &:filled?)
|
12
10
|
|
13
|
-
|
14
|
-
|
11
|
+
optional(:phone_number) do
|
12
|
+
none? | str?
|
15
13
|
end
|
16
14
|
end
|
17
15
|
end
|
@@ -19,11 +17,11 @@ RSpec.describe Dry::Validation::Schema do
|
|
19
17
|
|
20
18
|
describe '#call' do
|
21
19
|
it 'skips rules when key is not present' do
|
22
|
-
expect(
|
20
|
+
expect(schema.(address: { city: 'NYC', street: 'Street 1/2' })).to be_success
|
23
21
|
end
|
24
22
|
|
25
23
|
it 'applies rules when key is present' do
|
26
|
-
expect(
|
24
|
+
expect(schema.(email: '')).to_not be_success
|
27
25
|
end
|
28
26
|
end
|
29
27
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
RSpec.describe Dry::Validation::Schema, 'for an array' do
|
2
|
+
subject(:schema) do
|
3
|
+
Dry::Validation.Schema do
|
4
|
+
each do
|
5
|
+
key(:prefix).required
|
6
|
+
key(:value).required
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'applies its rules to array input' do
|
12
|
+
result = schema.([{ prefix: 1, value: 123 }, { prefix: 2, value: 456 }])
|
13
|
+
|
14
|
+
expect(result).to be_success
|
15
|
+
|
16
|
+
result = schema.([{ prefix: 1, value: nil }, { prefix: nil, value: 456 }])
|
17
|
+
|
18
|
+
expect(result.messages).to eql(
|
19
|
+
0 => { value: ["must be filled"] },
|
20
|
+
1 => { prefix: ["must be filled"] }
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
@@ -1,49 +1,57 @@
|
|
1
1
|
RSpec.describe Schema, 'using high-level rules' do
|
2
|
-
subject(:validate) { schema.new }
|
3
|
-
|
4
2
|
context 'composing rules' do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
subject(:schema) do
|
4
|
+
Dry::Validation.Schema do
|
5
|
+
configure do
|
6
|
+
def self.messages
|
7
|
+
Messages.default.merge(
|
8
|
+
en: { errors: { destiny: 'you must select either red or blue' } }
|
9
|
+
)
|
10
|
+
end
|
11
11
|
end
|
12
12
|
|
13
|
-
optional(:red
|
14
|
-
optional(:blue
|
13
|
+
optional(:red).maybe
|
14
|
+
optional(:blue).maybe
|
15
15
|
|
16
|
-
rule(:
|
16
|
+
rule(destiny: [:red, :blue]) do |red, blue|
|
17
|
+
red.filled? | blue.filled?
|
18
|
+
end
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
20
22
|
it 'passes when only red is filled' do
|
21
|
-
expect(
|
23
|
+
expect(schema.(red: '1')).to be_success
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'fails when keys are missing' do
|
27
|
+
expect(schema.({})).to be_failure
|
22
28
|
end
|
23
29
|
|
24
30
|
it 'fails when red and blue are not filled ' do
|
25
|
-
expect(
|
26
|
-
[
|
31
|
+
expect(schema.(red: nil, blue: nil).messages[:destiny]).to eql(
|
32
|
+
['you must select either red or blue']
|
27
33
|
)
|
28
34
|
end
|
29
35
|
end
|
30
36
|
|
31
37
|
context 'composing specific predicates' do
|
32
38
|
let(:schema) do
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
39
|
+
Dry::Validation.Schema do
|
40
|
+
configure do
|
41
|
+
def self.messages
|
42
|
+
Messages.default.merge(
|
43
|
+
en: {
|
44
|
+
errors: {
|
45
|
+
email_presence: 'must be present when login is set to true',
|
46
|
+
email_absence: 'must not be present when login is set to false'
|
47
|
+
}
|
40
48
|
}
|
41
|
-
|
42
|
-
|
49
|
+
)
|
50
|
+
end
|
43
51
|
end
|
44
52
|
|
45
|
-
key(:login)
|
46
|
-
key(:email)
|
53
|
+
key(:login).required(:bool?)
|
54
|
+
key(:email).maybe
|
47
55
|
|
48
56
|
rule(:email_presence) { value(:login).true?.then(value(:email).filled?) }
|
49
57
|
|
@@ -52,22 +60,22 @@ RSpec.describe Schema, 'using high-level rules' do
|
|
52
60
|
end
|
53
61
|
|
54
62
|
it 'passes when login is false and email is nil' do
|
55
|
-
expect(
|
63
|
+
expect(schema.(login: false, email: nil)).to be_success
|
56
64
|
end
|
57
65
|
|
58
66
|
it 'fails when login is false and email is present' do
|
59
|
-
expect(
|
60
|
-
[
|
67
|
+
expect(schema.(login: false, email: 'jane@doe').messages).to eql(
|
68
|
+
email_absence: ['must not be present when login is set to false']
|
61
69
|
)
|
62
70
|
end
|
63
71
|
|
64
72
|
it 'passes when login is true and email is present' do
|
65
|
-
expect(
|
73
|
+
expect(schema.(login: true, email: 'jane@doe')).to be_success
|
66
74
|
end
|
67
75
|
|
68
76
|
it 'fails when login is true and email is not present' do
|
69
|
-
expect(
|
70
|
-
[
|
77
|
+
expect(schema.(login: true, email: nil).messages).to eql(
|
78
|
+
email_presence: ['must be present when login is set to true']
|
71
79
|
)
|
72
80
|
end
|
73
81
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
RSpec.describe 'Check depending on nth element in an array' do
|
2
|
+
subject(:schema) do
|
3
|
+
Dry::Validation.Schema do
|
4
|
+
key(:tags).each(:str?)
|
5
|
+
|
6
|
+
rule(red: [[:tags, 0]]) do |value|
|
7
|
+
value.eql?('red')
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'skips check when dependency failed' do
|
13
|
+
expect(schema.(tags: 'oops')).to be_failure
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'passes when check passes' do
|
17
|
+
expect(schema.(tags: %w(red green blue))).to be_success
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'fails when check fails' do
|
21
|
+
expect(schema.(tags: %w(blue green red)).messages).to eql(
|
22
|
+
tags: { 0 => ["must be equal to red"] }
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
@@ -1,20 +1,22 @@
|
|
1
1
|
RSpec.describe 'Schema with each and set rules' do
|
2
|
-
subject(:
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
payments.array? do
|
8
|
-
payments.each do |payment|
|
9
|
-
payment.key(:method, &:str?)
|
10
|
-
payment.key(:amount, &:float?)
|
11
|
-
end
|
12
|
-
end
|
2
|
+
subject(:schema) do
|
3
|
+
Dry::Validation.Schema do
|
4
|
+
key(:payments).each do
|
5
|
+
key(:method).required(:str?)
|
6
|
+
key(:amount).required(:float?)
|
13
7
|
end
|
14
8
|
end
|
15
9
|
end
|
16
10
|
|
17
11
|
describe '#messages' do
|
12
|
+
it 'validates using all rules' do
|
13
|
+
expect(schema.(payments: [{}]).messages).to eql(
|
14
|
+
{ payments: {
|
15
|
+
0 => { method: ['is missing'], amount: ['is missing'] }
|
16
|
+
}}
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
18
20
|
it 'validates each payment against its set of rules' do
|
19
21
|
input = {
|
20
22
|
payments: [
|
@@ -23,7 +25,7 @@ RSpec.describe 'Schema with each and set rules' do
|
|
23
25
|
]
|
24
26
|
}
|
25
27
|
|
26
|
-
expect(
|
28
|
+
expect(schema.(input).messages).to eql({})
|
27
29
|
end
|
28
30
|
|
29
31
|
it 'validates presence of the method key for each payment' do
|
@@ -34,10 +36,9 @@ RSpec.describe 'Schema with each and set rules' do
|
|
34
36
|
]
|
35
37
|
}
|
36
38
|
|
37
|
-
expect(
|
38
|
-
|
39
|
-
|
40
|
-
])
|
39
|
+
expect(schema.(input).messages).to eql(
|
40
|
+
payments: { 1 => { method: ['is missing'] } }
|
41
|
+
)
|
41
42
|
end
|
42
43
|
|
43
44
|
it 'validates type of the method value for each payment' do
|
@@ -48,10 +49,9 @@ RSpec.describe 'Schema with each and set rules' do
|
|
48
49
|
]
|
49
50
|
}
|
50
51
|
|
51
|
-
expect(
|
52
|
-
|
53
|
-
|
54
|
-
])
|
52
|
+
expect(schema.(input).messages).to eql(
|
53
|
+
payments: { 1 => { method: ['must be a string'] } }
|
54
|
+
)
|
55
55
|
end
|
56
56
|
|
57
57
|
it 'validates type of the amount value for each payment' do
|
@@ -62,10 +62,9 @@ RSpec.describe 'Schema with each and set rules' do
|
|
62
62
|
]
|
63
63
|
}
|
64
64
|
|
65
|
-
expect(
|
66
|
-
|
67
|
-
|
68
|
-
])
|
65
|
+
expect(schema.(input).messages).to eql(
|
66
|
+
payments: { 1 => { amount: ['must be a float'] } }
|
67
|
+
)
|
69
68
|
end
|
70
69
|
end
|
71
70
|
end
|