reform 2.2.4 → 2.6.2
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.
- checksums.yaml +5 -5
- data/.github/workflows/ci.yml +17 -0
- data/.gitignore +5 -1
- data/CHANGES.md +80 -4
- data/CONTRIBUTING.md +31 -0
- data/Gemfile +2 -16
- data/ISSUE_TEMPLATE.md +25 -0
- data/LICENSE.txt +1 -1
- data/README.md +10 -12
- data/Rakefile +6 -10
- data/lib/reform/contract/custom_error.rb +41 -0
- data/lib/reform/contract/validate.rb +53 -23
- data/lib/reform/contract.rb +7 -17
- data/lib/reform/errors.rb +61 -0
- data/lib/reform/form/call.rb +1 -1
- data/lib/reform/form/composition.rb +2 -2
- data/lib/reform/form/dry/input_hash.rb +37 -0
- data/lib/reform/form/dry.rb +25 -35
- data/lib/reform/form/populator.rb +20 -26
- data/lib/reform/form/prepopulate.rb +5 -4
- data/lib/reform/form/validate.rb +29 -14
- data/lib/reform/form.rb +36 -10
- data/lib/reform/result.rb +90 -0
- data/lib/reform/validation/groups.rb +12 -28
- data/lib/reform/validation.rb +19 -11
- data/lib/reform/version.rb +1 -1
- data/lib/reform.rb +1 -0
- data/reform.gemspec +13 -13
- data/test/benchmarking.rb +39 -6
- data/test/call_test.rb +9 -9
- data/test/changed_test.rb +14 -14
- data/test/coercion_test.rb +57 -25
- data/test/composition_test.rb +85 -49
- data/test/contract/custom_error_test.rb +55 -0
- data/test/contract_test.rb +20 -20
- data/test/default_test.rb +4 -4
- data/test/deserialize_test.rb +17 -20
- data/test/docs/validation_test.rb +134 -0
- data/test/errors_test.rb +142 -82
- data/test/feature_test.rb +10 -12
- data/test/fixtures/dry_error_messages.yml +83 -23
- data/test/form_option_test.rb +5 -5
- data/test/form_test.rb +8 -8
- data/test/from_test.rb +18 -22
- data/test/inherit_test.rb +54 -68
- data/test/module_test.rb +27 -32
- data/test/parse_option_test.rb +40 -0
- data/test/parse_pipeline_test.rb +4 -4
- data/test/populate_test.rb +217 -100
- data/test/populator_skip_test.rb +11 -11
- data/test/prepopulator_test.rb +24 -25
- data/test/read_only_test.rb +12 -1
- data/test/readable_test.rb +9 -9
- data/test/reform_test.rb +47 -66
- data/test/save_test.rb +35 -23
- data/test/setup_test.rb +17 -17
- data/test/skip_if_test.rb +33 -22
- data/test/skip_setter_and_getter_test.rb +9 -10
- data/test/test_helper.rb +23 -14
- data/test/validate_test.rb +165 -145
- data/test/validation/dry_validation_test.rb +630 -146
- data/test/validation/result_test.rb +77 -0
- data/test/validation_library_provided_test.rb +16 -0
- data/test/virtual_test.rb +47 -7
- data/test/writeable_test.rb +38 -9
- metadata +46 -38
- data/.travis.yml +0 -11
- data/gemfiles/Gemfile.disposable-0.3 +0 -6
- data/lib/reform/contract/errors.rb +0 -43
- data/lib/reform/form/mongoid.rb +0 -37
- data/lib/reform/form/orm.rb +0 -26
- data/lib/reform/mongoid.rb +0 -4
- data/test/deprecation_test.rb +0 -27
- data/test/readonly_test.rb +0 -14
- data/test/validation/dry_test.rb +0 -60
- data/test/validation/errors.yml +0 -4
data/test/deserialize_test.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "test_helper"
|
|
2
2
|
require "representable/json"
|
|
3
3
|
|
|
4
4
|
class DeserializeTest < MiniTest::Spec
|
|
@@ -6,11 +6,11 @@ class DeserializeTest < MiniTest::Spec
|
|
|
6
6
|
Album = Struct.new(:title, :artist)
|
|
7
7
|
Artist = Struct.new(:name, :callname)
|
|
8
8
|
|
|
9
|
-
class JsonAlbumForm <
|
|
9
|
+
class JsonAlbumForm < TestForm
|
|
10
10
|
module Json
|
|
11
11
|
def deserialize(params)
|
|
12
12
|
deserializer.new(self).
|
|
13
|
-
|
|
13
|
+
# extend(Representable::Debug).
|
|
14
14
|
from_json(params)
|
|
15
15
|
end
|
|
16
16
|
|
|
@@ -18,7 +18,7 @@ class DeserializeTest < MiniTest::Spec
|
|
|
18
18
|
Disposable::Rescheme.from(self.class,
|
|
19
19
|
include: [Representable::JSON],
|
|
20
20
|
superclass: Representable::Decorator,
|
|
21
|
-
definitions_from:
|
|
21
|
+
definitions_from: ->(inline) { inline.definitions },
|
|
22
22
|
options_from: :deserializer,
|
|
23
23
|
exclude_options: [:populator]
|
|
24
24
|
)
|
|
@@ -26,15 +26,13 @@ class DeserializeTest < MiniTest::Spec
|
|
|
26
26
|
end
|
|
27
27
|
include Json
|
|
28
28
|
|
|
29
|
-
|
|
30
29
|
property :title
|
|
31
30
|
property :artist, populate_if_empty: Artist do
|
|
32
31
|
property :name
|
|
33
32
|
end
|
|
34
33
|
end
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
let (:artist) { Artist.new("A-ha") }
|
|
35
|
+
let(:artist) { Artist.new("A-ha") }
|
|
38
36
|
it do
|
|
39
37
|
artist_id = artist.object_id
|
|
40
38
|
|
|
@@ -43,13 +41,13 @@ class DeserializeTest < MiniTest::Spec
|
|
|
43
41
|
|
|
44
42
|
form.validate(json)
|
|
45
43
|
|
|
46
|
-
form.title
|
|
47
|
-
form.artist.name
|
|
48
|
-
form.artist.model.object_id
|
|
44
|
+
assert_equal form.title, "Apocalypse Soon"
|
|
45
|
+
assert_equal form.artist.name, "Mute"
|
|
46
|
+
assert_equal form.artist.model.object_id, artist_id
|
|
49
47
|
end
|
|
50
48
|
|
|
51
49
|
describe "infering the deserializer from another form should NOT copy its populators" do
|
|
52
|
-
class CompilationForm <
|
|
50
|
+
class CompilationForm < TestForm
|
|
53
51
|
property :artist, populator: ->(options) { self.artist = Artist.new(nil, options[:fragment].to_s) } do
|
|
54
52
|
property :name
|
|
55
53
|
end
|
|
@@ -62,20 +60,19 @@ class DeserializeTest < MiniTest::Spec
|
|
|
62
60
|
# also tests the Form#deserializer API. # FIXME.
|
|
63
61
|
it "uses deserializer inferred from JsonAlbumForm but deserializes/populates to CompilationForm" do
|
|
64
62
|
form = CompilationForm.new(Album.new)
|
|
65
|
-
form.validate("artist"=> {"name" => "Horowitz"}) # the deserializer doesn't know symbols.
|
|
63
|
+
form.validate("artist" => {"name" => "Horowitz"}) # the deserializer doesn't know symbols.
|
|
66
64
|
form.sync
|
|
67
|
-
form.artist.model
|
|
65
|
+
assert_equal form.artist.model, Artist.new("Horowitz", %{{"name"=>"Horowitz"}})
|
|
68
66
|
end
|
|
69
67
|
end
|
|
70
68
|
end
|
|
71
69
|
|
|
72
|
-
|
|
73
70
|
class ValidateWithBlockTest < MiniTest::Spec
|
|
74
71
|
Song = Struct.new(:title, :album, :composer)
|
|
75
72
|
Album = Struct.new(:title, :artist)
|
|
76
73
|
Artist = Struct.new(:name)
|
|
77
74
|
|
|
78
|
-
class AlbumForm <
|
|
75
|
+
class AlbumForm < TestForm
|
|
79
76
|
property :title
|
|
80
77
|
property :artist, populate_if_empty: Artist do
|
|
81
78
|
property :name
|
|
@@ -90,15 +87,15 @@ class ValidateWithBlockTest < MiniTest::Spec
|
|
|
90
87
|
deserializer = Disposable::Rescheme.from(AlbumForm,
|
|
91
88
|
include: [Representable::JSON],
|
|
92
89
|
superclass: Representable::Decorator,
|
|
93
|
-
definitions_from:
|
|
90
|
+
definitions_from: ->(inline) { inline.definitions },
|
|
94
91
|
options_from: :deserializer
|
|
95
92
|
)
|
|
96
93
|
|
|
97
|
-
form.validate(json)
|
|
94
|
+
assert form.validate(json) { |params|
|
|
98
95
|
deserializer.new(form).from_json(params)
|
|
99
|
-
|
|
96
|
+
} # with block must return result, too.
|
|
100
97
|
|
|
101
|
-
form.title
|
|
102
|
-
form.artist.name
|
|
98
|
+
assert_equal form.title, "Apocalypse Soon"
|
|
99
|
+
assert_equal form.artist.name, "Mute"
|
|
103
100
|
end
|
|
104
101
|
end
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
require 'test_helper'
|
|
2
|
+
require 'reform/form/dry'
|
|
3
|
+
|
|
4
|
+
class DocsDryVTest < Minitest::Spec
|
|
5
|
+
#:basic
|
|
6
|
+
class AlbumForm < Reform::Form
|
|
7
|
+
feature Reform::Form::Dry
|
|
8
|
+
|
|
9
|
+
property :name
|
|
10
|
+
|
|
11
|
+
validation do
|
|
12
|
+
params do
|
|
13
|
+
required(:name).filled
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
#:basic end
|
|
18
|
+
|
|
19
|
+
it 'validates correctly' do
|
|
20
|
+
form = DocsDryVTest::AlbumForm.new(Album.new(nil, nil, nil))
|
|
21
|
+
result = form.call(name: nil)
|
|
22
|
+
|
|
23
|
+
refute result.success?
|
|
24
|
+
assert_equal({ name: ['must be filled'] }, form.errors.messages)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class DocsDryVWithRulesTest < Minitest::Spec
|
|
29
|
+
#:basic_with_rules
|
|
30
|
+
class AlbumForm < Reform::Form
|
|
31
|
+
feature Reform::Form::Dry
|
|
32
|
+
|
|
33
|
+
property :name
|
|
34
|
+
|
|
35
|
+
validation name: :default do
|
|
36
|
+
option :form
|
|
37
|
+
|
|
38
|
+
params do
|
|
39
|
+
required(:name).filled
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
rule(:name) do
|
|
43
|
+
key.failure('must be unique') if Album.where.not(id: form.model.id).where(name: value).exists?
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
#:basic_with_rules end
|
|
48
|
+
|
|
49
|
+
it 'validates correctly' do
|
|
50
|
+
Album = Struct.new(:name, :songs, :artist, :user)
|
|
51
|
+
form = DocsDryVWithRulesTest::AlbumForm.new(Album.new(nil, nil, nil, nil))
|
|
52
|
+
result = form.call(name: nil)
|
|
53
|
+
|
|
54
|
+
refute result.success?
|
|
55
|
+
assert_equal({ name: ['must be filled'] }, form.errors.messages)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
class DryVWithNestedTest < Minitest::Spec
|
|
60
|
+
#:nested
|
|
61
|
+
class AlbumForm < Reform::Form
|
|
62
|
+
feature Reform::Form::Dry
|
|
63
|
+
|
|
64
|
+
property :name
|
|
65
|
+
|
|
66
|
+
validation do
|
|
67
|
+
params { required(:name).filled }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
property :artist do
|
|
71
|
+
property :name
|
|
72
|
+
|
|
73
|
+
validation do
|
|
74
|
+
params { required(:name).filled }
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
#:nested end
|
|
79
|
+
|
|
80
|
+
it 'validates correctly' do
|
|
81
|
+
form = DryVWithNestedTest::AlbumForm.new(Album.new(nil, nil, Artist.new(nil)))
|
|
82
|
+
result = form.call(name: nil, artist: { name: '' })
|
|
83
|
+
|
|
84
|
+
refute result.success?
|
|
85
|
+
assert_equal({ name: ['must be filled'], 'artist.name': ['must be filled'] }, form.errors.messages)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
class DryVValGroupTest < Minitest::Spec
|
|
90
|
+
class AlbumForm < Reform::Form
|
|
91
|
+
feature Reform::Form::Dry
|
|
92
|
+
|
|
93
|
+
property :name
|
|
94
|
+
property :artist
|
|
95
|
+
#:validation_groups
|
|
96
|
+
validation name: :default do
|
|
97
|
+
params { required(:name).filled }
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
validation name: :artist, if: :default do
|
|
101
|
+
params { required(:artist).filled }
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
validation name: :famous, after: :default do
|
|
105
|
+
params { optional(:artist) }
|
|
106
|
+
|
|
107
|
+
rule(:artist) do
|
|
108
|
+
if value
|
|
109
|
+
key.failure('only famous artist') unless value =~ /famous/
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
#:validation_groups end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
it 'validates correctly' do
|
|
117
|
+
form = DryVValGroupTest::AlbumForm.new(Album.new(nil, nil, nil))
|
|
118
|
+
result = form.call(name: nil)
|
|
119
|
+
|
|
120
|
+
refute result.success?
|
|
121
|
+
assert_equal({ name: ['must be filled'] }, result.errors.messages)
|
|
122
|
+
|
|
123
|
+
result = form.call(name: 'Title')
|
|
124
|
+
refute result.success?
|
|
125
|
+
assert_equal({ artist: ['must be filled'] }, result.errors.messages)
|
|
126
|
+
|
|
127
|
+
result = form.call(name: 'Title', artist: 'Artist')
|
|
128
|
+
refute result.success?
|
|
129
|
+
assert_equal({ artist: ['only famous artist'] }, result.errors.messages)
|
|
130
|
+
|
|
131
|
+
result = form.call(name: 'Title', artist: 'Artist famous')
|
|
132
|
+
assert result.success?
|
|
133
|
+
end
|
|
134
|
+
end
|
data/test/errors_test.rb
CHANGED
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
require "test_helper"
|
|
2
2
|
|
|
3
3
|
class ErrorsTest < MiniTest::Spec
|
|
4
|
-
class AlbumForm <
|
|
4
|
+
class AlbumForm < TestForm
|
|
5
5
|
property :title
|
|
6
|
+
validation do
|
|
7
|
+
params { required(:title).filled }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
property :artists, default: []
|
|
11
|
+
property :producer do
|
|
12
|
+
property :name
|
|
13
|
+
end
|
|
6
14
|
|
|
7
15
|
property :hit do
|
|
8
16
|
property :title
|
|
9
17
|
validation do
|
|
10
|
-
required(:title).filled
|
|
18
|
+
params { required(:title).filled }
|
|
11
19
|
end
|
|
12
20
|
end
|
|
13
21
|
|
|
14
22
|
collection :songs do
|
|
15
23
|
property :title
|
|
16
24
|
validation do
|
|
17
|
-
required(:title).filled
|
|
25
|
+
params { required(:title).filled }
|
|
18
26
|
end
|
|
19
27
|
end
|
|
20
28
|
|
|
@@ -23,143 +31,195 @@ class ErrorsTest < MiniTest::Spec
|
|
|
23
31
|
property :label do
|
|
24
32
|
property :name
|
|
25
33
|
validation do
|
|
26
|
-
required(:name).filled
|
|
34
|
+
params { required(:name).filled }
|
|
27
35
|
end
|
|
28
36
|
end
|
|
29
37
|
# TODO: make band a required object.
|
|
30
38
|
|
|
31
39
|
validation do
|
|
32
|
-
|
|
40
|
+
config.messages.load_paths << "test/fixtures/dry_error_messages.yml"
|
|
33
41
|
|
|
34
|
-
|
|
35
|
-
config.messages_file = "test/validation/errors.yml"
|
|
42
|
+
params { required(:name).filled }
|
|
36
43
|
|
|
37
|
-
|
|
38
|
-
value != "Nickelback"
|
|
39
|
-
# errors.add(:base, "You are a bad person") if name == "Nickelback"
|
|
40
|
-
end
|
|
41
|
-
end
|
|
44
|
+
rule(:name) { key.failure(:good_musical_taste?) if value == "Nickelback" }
|
|
42
45
|
end
|
|
43
|
-
# validate :music_taste_ok?
|
|
44
|
-
|
|
45
|
-
# private
|
|
46
|
-
# def music_taste_ok?
|
|
47
|
-
# errors.add(:base, "You are a bad person") if name == "Nickelback"
|
|
48
|
-
# end
|
|
49
46
|
end
|
|
50
47
|
|
|
51
48
|
validation do
|
|
52
|
-
|
|
49
|
+
params do
|
|
50
|
+
required(:title).filled
|
|
51
|
+
required(:artists).each(:str?)
|
|
52
|
+
required(:producer).hash do
|
|
53
|
+
required(:name).filled
|
|
54
|
+
end
|
|
55
|
+
end
|
|
53
56
|
end
|
|
54
57
|
end
|
|
55
58
|
|
|
56
|
-
let
|
|
59
|
+
let(:album_title) { "Blackhawks Over Los Angeles" }
|
|
60
|
+
let(:album) do
|
|
57
61
|
OpenStruct.new(
|
|
58
|
-
:
|
|
59
|
-
:
|
|
60
|
-
:
|
|
61
|
-
|
|
62
|
-
:
|
|
62
|
+
title: album_title,
|
|
63
|
+
hit: song,
|
|
64
|
+
songs: songs, # TODO: document this requirement,
|
|
65
|
+
band: Struct.new(:name, :label).new("Epitaph", OpenStruct.new),
|
|
66
|
+
producer: Struct.new(:name).new("Sun Records")
|
|
63
67
|
)
|
|
64
68
|
end
|
|
65
|
-
let
|
|
66
|
-
let
|
|
67
|
-
let
|
|
68
|
-
|
|
69
|
+
let(:song) { OpenStruct.new(title: "Downtown") }
|
|
70
|
+
let(:songs) { [song = OpenStruct.new(title: "Calling"), song] }
|
|
71
|
+
let(:form) { AlbumForm.new(album) }
|
|
69
72
|
|
|
70
|
-
describe "
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
describe "#validate with invalid array property" do
|
|
74
|
+
it do
|
|
75
|
+
refute form.validate(
|
|
76
|
+
title: "Swimming Pool - EP",
|
|
77
|
+
band: {
|
|
78
|
+
name: "Marie Madeleine",
|
|
79
|
+
label: {name: "Ekler'o'shocK"}
|
|
80
|
+
},
|
|
81
|
+
artists: [42, "Good Charlotte", 43]
|
|
82
|
+
)
|
|
83
|
+
assert_equal form.errors.messages, artists: {0 => ["must be a string"], 2 => ["must be a string"]}
|
|
84
|
+
assert_equal form.errors.size, 1
|
|
85
|
+
end
|
|
86
|
+
end
|
|
75
87
|
|
|
88
|
+
describe "#errors without #validate" do
|
|
76
89
|
it do
|
|
77
|
-
form.errors.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
90
|
+
assert_equal form.errors.size, 0
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
describe "blank everywhere" do
|
|
95
|
+
before do
|
|
96
|
+
form.validate(
|
|
97
|
+
"hit" => {"title" => ""},
|
|
98
|
+
"title" => "",
|
|
99
|
+
"songs" => [{"title" => ""}, {"title" => ""}],
|
|
100
|
+
"producer" => {"name" => ""}
|
|
101
|
+
)
|
|
83
102
|
end
|
|
84
103
|
|
|
85
104
|
it do
|
|
86
|
-
|
|
87
|
-
|
|
105
|
+
assert_equal form.errors.messages,{
|
|
106
|
+
title: ["must be filled"],
|
|
107
|
+
"hit.title": ["must be filled"],
|
|
108
|
+
"songs.title": ["must be filled"],
|
|
109
|
+
"band.label.name": ["must be filled"],
|
|
110
|
+
"producer.name": ["must be filled"]
|
|
111
|
+
}
|
|
88
112
|
end
|
|
89
113
|
|
|
114
|
+
# it do
|
|
115
|
+
# form.errors.must_equal({:title => ["must be filled"]})
|
|
116
|
+
# TODO: this should only contain local errors?
|
|
117
|
+
# end
|
|
118
|
+
|
|
90
119
|
# nested forms keep their own Errors:
|
|
91
|
-
it { form.
|
|
92
|
-
it { form.
|
|
120
|
+
it { assert_equal form.producer.errors.messages, name: ["must be filled"] }
|
|
121
|
+
it { assert_equal form.hit.errors.messages, title: ["must be filled"] }
|
|
122
|
+
it { assert_equal form.songs[0].errors.messages, title: ["must be filled"] }
|
|
93
123
|
|
|
94
124
|
it do
|
|
95
|
-
form.errors.messages
|
|
96
|
-
:
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
125
|
+
assert_equal form.errors.messages, {
|
|
126
|
+
title: ["must be filled"],
|
|
127
|
+
"hit.title": ["must be filled"],
|
|
128
|
+
"songs.title": ["must be filled"],
|
|
129
|
+
"band.label.name": ["must be filled"],
|
|
130
|
+
"producer.name": ["must be filled"]
|
|
131
|
+
}
|
|
132
|
+
assert_equal form.errors.size, 5
|
|
101
133
|
end
|
|
102
134
|
end
|
|
103
135
|
|
|
104
|
-
|
|
105
136
|
describe "#validate with main form invalid" do
|
|
106
137
|
it do
|
|
107
|
-
form.validate("title"=>"", "band"=>{"label"=>{:
|
|
108
|
-
form.errors.messages
|
|
138
|
+
refute form.validate("title" => "", "band" => {"label" => {name: "Fat Wreck"}}, "producer" => nil)
|
|
139
|
+
assert_equal form.errors.messages, title: ["must be filled"], producer: ["must be a hash"]
|
|
140
|
+
assert_equal form.errors.size, 2
|
|
109
141
|
end
|
|
110
142
|
end
|
|
111
143
|
|
|
112
|
-
|
|
113
144
|
describe "#validate with middle nested form invalid" do
|
|
114
|
-
before { @result = form.validate("hit"=>{"title" => ""}, "band"=>{"label"=>{:
|
|
145
|
+
before { @result = form.validate("hit" => {"title" => ""}, "band" => {"label" => {name: "Fat Wreck"}}) }
|
|
115
146
|
|
|
116
|
-
it { @result
|
|
117
|
-
it { form.errors.messages
|
|
147
|
+
it { refute @result }
|
|
148
|
+
it { assert_equal form.errors.messages, "hit.title": ["must be filled"] }
|
|
149
|
+
it { assert_equal form.errors.size, 1 }
|
|
118
150
|
end
|
|
119
151
|
|
|
120
|
-
|
|
121
152
|
describe "#validate with collection form invalid" do
|
|
122
|
-
before { @result = form.validate("songs"=>[{"title" => ""}], "band"=>{"label"=>{:
|
|
153
|
+
before { @result = form.validate("songs" => [{"title" => ""}], "band" => {"label" => {name: "Fat Wreck"}}) }
|
|
123
154
|
|
|
124
|
-
it { @result
|
|
125
|
-
it { form.errors.messages
|
|
155
|
+
it { refute @result }
|
|
156
|
+
it { assert_equal form.errors.messages, "songs.title": ["must be filled"] }
|
|
157
|
+
it { assert_equal form.errors.size, 1 }
|
|
126
158
|
end
|
|
127
159
|
|
|
128
|
-
|
|
129
160
|
describe "#validate with collection and 2-level-nested invalid" do
|
|
130
|
-
before { @result = form.validate("songs"=>[{"title" => ""}], "band" => {"label" => {}}) }
|
|
161
|
+
before { @result = form.validate("songs" => [{"title" => ""}], "band" => {"label" => {}}) }
|
|
131
162
|
|
|
132
|
-
it { @result
|
|
133
|
-
it { form.errors.messages
|
|
163
|
+
it { refute @result }
|
|
164
|
+
it { assert_equal form.errors.messages, "songs.title": ["must be filled"], "band.label.name": ["must be filled"] }
|
|
165
|
+
it { assert_equal form.errors.size, 2 }
|
|
134
166
|
end
|
|
135
167
|
|
|
136
168
|
describe "#validate with nested form using :base invalid" do
|
|
137
169
|
it do
|
|
138
|
-
result = form.validate("songs"=>[{"title" => "Someday"}], "band" => {"name" => "Nickelback", "label" => {"name" => "Roadrunner Records"}})
|
|
139
|
-
result
|
|
140
|
-
form.errors.messages
|
|
170
|
+
result = form.validate("songs" => [{"title" => "Someday"}], "band" => {"name" => "Nickelback", "label" => {"name" => "Roadrunner Records"}})
|
|
171
|
+
refute result
|
|
172
|
+
assert_equal form.errors.messages, "band.name": ["you're a bad person"]
|
|
173
|
+
assert_equal form.errors.size, 1
|
|
141
174
|
end
|
|
142
175
|
end
|
|
143
176
|
|
|
144
|
-
describe "
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
"title" => "
|
|
148
|
-
|
|
149
|
-
"
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
177
|
+
describe "#add" do
|
|
178
|
+
let(:album_title) { nil }
|
|
179
|
+
it do
|
|
180
|
+
result = form.validate("songs" => [{"title" => "Someday"}], "band" => {"name" => "Nickelback", "label" => {"name" => "Roadrunner Records"}})
|
|
181
|
+
refute result
|
|
182
|
+
assert_equal form.errors.messages, title: ["must be filled"], "band.name": ["you're a bad person"]
|
|
183
|
+
# add a new custom error
|
|
184
|
+
form.errors.add(:policy, "error_text")
|
|
185
|
+
assert_equal form.errors.messages, title: ["must be filled"], "band.name": ["you're a bad person"], policy: ["error_text"]
|
|
186
|
+
# does not duplicate errors
|
|
187
|
+
form.errors.add(:title, "must be filled")
|
|
188
|
+
assert_equal form.errors.messages, title: ["must be filled"], "band.name": ["you're a bad person"], policy: ["error_text"]
|
|
189
|
+
# merge existing errors
|
|
190
|
+
form.errors.add(:policy, "another error")
|
|
191
|
+
assert_equal form.errors.messages, title: ["must be filled"], "band.name": ["you're a bad person"], policy: ["error_text", "another error"]
|
|
192
|
+
end
|
|
156
193
|
end
|
|
157
194
|
|
|
195
|
+
describe "correct #validate" do
|
|
196
|
+
before do
|
|
197
|
+
@result = form.validate(
|
|
198
|
+
"hit" => {"title" => "Sacrifice"},
|
|
199
|
+
"title" => "Second Heat",
|
|
200
|
+
"songs" => [{"title" => "Heart Of A Lion"}],
|
|
201
|
+
"band" => {"label" => {name: "Fat Wreck"}}
|
|
202
|
+
)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
it { assert @result }
|
|
206
|
+
it { assert_equal form.hit.title, "Sacrifice" }
|
|
207
|
+
it { assert_equal form.title, "Second Heat" }
|
|
208
|
+
it { assert_equal form.songs.first.title, "Heart Of A Lion" }
|
|
209
|
+
it do
|
|
210
|
+
skip "WE DON'T NEED COUNT AND EMPTY? ON THE CORE ERRORS OBJECT"
|
|
211
|
+
assert_equal form.errors.size, 0
|
|
212
|
+
assert form.errors.empty
|
|
213
|
+
end
|
|
214
|
+
end
|
|
158
215
|
|
|
159
216
|
describe "Errors#to_s" do
|
|
160
|
-
before { form.validate("songs"=>[{"title" => ""}], "band" => {"label" => {}}) }
|
|
217
|
+
before { form.validate("songs" => [{"title" => ""}], "band" => {"label" => {}}) }
|
|
161
218
|
|
|
162
219
|
# to_s is aliased to messages
|
|
163
|
-
it {
|
|
220
|
+
it {
|
|
221
|
+
skip "why do we need Errors#to_s ?"
|
|
222
|
+
assert_equal form.errors.to_s, "{:\"songs.title\"=>[\"must be filled\"], :\"band.label.name\"=>[\"must be filled\"]}"
|
|
223
|
+
}
|
|
164
224
|
end
|
|
165
225
|
end
|
data/test/feature_test.rb
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require 'test_helper'
|
|
2
|
-
|
|
3
1
|
class FeatureInheritanceTest < BaseTest
|
|
4
2
|
Song = Struct.new(:title, :album, :composer)
|
|
5
3
|
Album = Struct.new(:name, :songs, :artist)
|
|
@@ -21,7 +19,7 @@ class FeatureInheritanceTest < BaseTest
|
|
|
21
19
|
# end
|
|
22
20
|
# end
|
|
23
21
|
|
|
24
|
-
class AlbumForm <
|
|
22
|
+
class AlbumForm < TestForm
|
|
25
23
|
feature Date # feature.
|
|
26
24
|
property :name
|
|
27
25
|
|
|
@@ -38,17 +36,17 @@ class FeatureInheritanceTest < BaseTest
|
|
|
38
36
|
end
|
|
39
37
|
end
|
|
40
38
|
|
|
41
|
-
let
|
|
42
|
-
let
|
|
43
|
-
let
|
|
44
|
-
let
|
|
45
|
-
let
|
|
39
|
+
let(:song) { Song.new("Broken") }
|
|
40
|
+
let(:song_with_composer) { Song.new("Resist Stance", nil, composer) }
|
|
41
|
+
let(:composer) { Artist.new("Greg Graffin") }
|
|
42
|
+
let(:artist) { Artist.new("Bad Religion") }
|
|
43
|
+
let(:album) { Album.new("The Dissent Of Man", [song, song_with_composer], artist) }
|
|
46
44
|
|
|
47
|
-
let
|
|
45
|
+
let(:form) { AlbumForm.new(album) }
|
|
48
46
|
|
|
49
47
|
it do
|
|
50
|
-
form.date
|
|
51
|
-
form.songs[0].date
|
|
48
|
+
assert_equal form.date, "May 16"
|
|
49
|
+
assert_equal form.songs[0].date, "May 16"
|
|
52
50
|
end
|
|
53
51
|
|
|
54
52
|
# it { subject.class.include?(Reform::Form::ActiveModel) }
|
|
@@ -62,4 +60,4 @@ class FeatureInheritanceTest < BaseTest
|
|
|
62
60
|
# it { subject.band.label.is_a?(Reform::Form::ActiveModel) }
|
|
63
61
|
# it { subject.band.label.is_a?(Reform::Form::Coercion) }
|
|
64
62
|
# it { subject.band.label.is_a?(Reform::Form::MultiParameterAttributes) }
|
|
65
|
-
end
|
|
63
|
+
end
|