freeform 1.0.11 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,161 +3,131 @@ require 'freeform/form/property'
3
3
  require 'freeform/form/nested'
4
4
 
5
5
  describe FreeForm::Nested do
6
- describe "has_many", :has_many => true do
7
- let!(:nested_class) do
8
- klass = Class.new(Module) do
9
- include FreeForm::Property
10
- include FreeForm::Nested
6
+ let(:form_class) do
7
+ klass = Class.new(Module) do
8
+ include FreeForm::Model
9
+ include FreeForm::Property
10
+ include FreeForm::Nested
11
+
12
+ def initialize(h={})
13
+ h.each {|k,v| send("#{k}=",v)}
14
+ end
15
+
16
+ has_many :mailing_addresses, :default_initializer => :mailing_address_initializer do
11
17
  declared_model :address
12
-
13
18
  property :street, :on => :address
14
-
15
- def initialize(h={})
16
- h.each {|k,v| send("#{k}=",v)}
17
- end
18
19
  end
19
- # This wrapper just avoids CONST warnings
20
- v, $VERBOSE = $VERBOSE, nil
21
- Module.const_set("MailingAddressForm", klass)
22
- $VERBOSE = v
23
- klass
24
- end
25
20
 
26
- let!(:second_nested_class) do
27
- klass = Class.new(Module) do
28
- include FreeForm::Property
29
- include FreeForm::Nested
21
+ def mailing_address_initializer
22
+ { :address => OpenStruct.new(:id => Random.new.rand(1000000)) }
23
+ end
24
+
25
+ has_many :phone_numbers, :default_initializer => :phone_number_initializer do
30
26
  declared_model :phone
31
-
32
- property :number, :on => :phone
33
-
34
- def initialize(h={})
35
- h.each {|k,v| send("#{k}=",v)}
36
- end
27
+ property :number, :on => :phone
37
28
  end
38
- # This wrapper just avoids CONST warnings
39
- v, $VERBOSE = $VERBOSE, nil
40
- Module.const_set("PhoneNumberForm", klass)
41
- $VERBOSE = v
42
- klass
43
- end
44
29
 
45
- let(:form_class) do
46
- klass = Class.new(Module) do
47
- include FreeForm::Property
48
- include FreeForm::Nested
49
-
50
- def initialize(h={})
51
- h.each {|k,v| send("#{k}=",v)}
52
- end
53
-
54
- has_many :mailing_addresses, :class => Module::MailingAddressForm, :default_initializer => :mailing_address_initializer
55
- def mailing_address_initializer
56
- { :address => OpenStruct.new(:id => Random.new.rand(1000000)) }
57
- end
58
-
59
- has_many :phone_numbers, :class => Module::PhoneNumberForm, :default_initializer => :phone_number_initializer
60
- def phone_number_initializer
61
- { :phone => OpenStruct.new(:id => Random.new.rand(1000000)) }
62
- end
30
+ def phone_number_initializer
31
+ { :phone => OpenStruct.new(:id => Random.new.rand(1000000)) }
63
32
  end
64
- # This wrapper just avoids CONST warnings
65
- v, $VERBOSE = $VERBOSE, nil
66
- Module.const_set("DummyForm", klass)
67
- $VERBOSE = v
68
- klass
69
33
  end
34
+ # This wrapper just avoids CONST warnings
35
+ v, $VERBOSE = $VERBOSE, nil
36
+ Module.const_set("ParentForm", klass)
37
+ $VERBOSE = v
38
+ klass
39
+ end
70
40
 
71
- let(:form) do
72
- form_model = form_class.new
41
+ let(:form) do
42
+ form_model = form_class.new
43
+ end
44
+
45
+ describe "form class" do
46
+ it "has correct class" do
47
+ form.should be_a(Module::ParentForm)
73
48
  end
74
49
 
75
- describe "form class" do
76
- it "sets nested_form in models" do
77
- form_class.models.should eq([:mailing_addresses, :phone_numbers])
78
- end
50
+ it "has nested forms" do
51
+ form_class.nested_forms.should eq([Module::ParentForm::MailingAddress, Module::ParentForm::PhoneNumber])
79
52
  end
80
-
81
- describe "building nested models" do
82
- it "initializes with no nested models prebuilt" do
83
- form.mailing_addresses.should eq([])
84
- form.phone_numbers.should eq([])
53
+
54
+ describe "mailing address nested form class" do
55
+ let(:nested_form) { form_class.nested_forms.first.new }
56
+
57
+ it "should be a MailingAddress object" do
58
+ nested_form.should be_a(Module::ParentForm::MailingAddress)
85
59
  end
86
-
87
- context "with default initializer" do
88
- context "for mailing addresses" do
89
- it "allows nested_forms to be built" do
90
- form.build_mailing_addresses
91
- form.mailing_addresses.should be_an(Array)
92
- form.mailing_addresses.should_not be_empty
93
- form.mailing_addresses.first.should be_a(Module::MailingAddressForm)
94
- end
95
-
96
- it "does not add to other has_many array" do
97
- form.build_mailing_addresses
98
- form.phone_numbers.should eq([])
99
- end
100
-
101
- it "builds unique models" do
102
- form = form_class.new
103
- form.build_mailing_address
104
- form.build_mailing_address
105
- address_1 = form.mailing_addresses.first.address
106
- address_2 = form.mailing_addresses.last.address
107
- address_1.should_not eq(address_2)
108
- end
109
- end
110
-
111
- context "for phone numbers" do
112
- it "allows nested_forms to be built" do
113
- form.build_phone_number
114
- form.phone_numbers.should be_an(Array)
115
- form.phone_numbers.should_not be_empty
116
- form.phone_numbers.first.should be_a(Module::PhoneNumberForm)
117
- end
118
-
119
- it "does not add to other has_many array" do
120
- form.build_phone_numbers
121
- form.mailing_addresses.should eq([])
122
- end
123
-
124
- it "builds unique models" do
125
- form = form_class.new
126
- form.build_phone_number
127
- form.build_phone_number
128
- phone_1 = form.phone_numbers.first.phone
129
- phone_2 = form.phone_numbers.last.phone
130
- phone_1.should_not eq(phone_2)
131
- end
132
- end
60
+
61
+ it "should respond to property methods" do
62
+ nested_form.should respond_to(:street)
133
63
  end
134
-
135
- context "with custom initializer" do
136
- it "allows nested_forms to be built" do
137
- form.build_mailing_addresses(:address => OpenStruct.new)
138
- form.mailing_addresses.should be_an(Array)
139
- form.mailing_addresses.should_not be_empty
140
- form.mailing_addresses.first.should be_a(Module::MailingAddressForm)
141
- end
142
-
143
- it "allows nested_forms to be built with custom initializers" do
144
- form.build_mailing_address(:address => OpenStruct.new(:street => "1600 Pennsylvania Ave."))
145
- form.mailing_addresses.first.street.should eq("1600 Pennsylvania Ave.")
146
- end
64
+ end
65
+
66
+ describe "phone number nested form class" do
67
+ let(:nested_form) { form_class.nested_forms.last.new }
68
+
69
+ it "should be a PhoneNumber object" do
70
+ nested_form.should be_a(Module::ParentForm::PhoneNumber)
147
71
  end
72
+
73
+ it "should respond to property methods" do
74
+ nested_form.should respond_to(:number)
75
+ end
76
+ end
77
+ end
78
+
79
+ describe "building nested models" do
80
+ it "responds to mailing_addresses" do
81
+ form.should respond_to(:mailing_addresses)
82
+ end
83
+
84
+ it "responds to phone_numbers" do
85
+ form.should respond_to(:phone_numbers)
148
86
  end
149
-
150
- describe "setting attributes" do
151
- describe "nested attribute assignment" do
152
- let(:attributes) do
153
- { :mailing_addresses_attributes => { "0" => { :street => "123 Main St." } } }
154
- end
155
-
156
- it "assigns nested attributes" do
157
- form.fill(attributes)
158
- form.mailing_addresses.first.street.should eq("123 Main St.")
159
- end
87
+
88
+ it "initializes with no nested models prebuilt" do
89
+ form.mailing_addresses.should eq([])
90
+ form.phone_numbers.should eq([])
91
+ end
92
+
93
+ describe "building new nested models" do
94
+ it "can build new nested model" do
95
+ form.build_mailing_address
96
+ form.mailing_addresses.should_not be_empty
97
+ form.mailing_addresses.first.should be_a(Module::ParentForm::MailingAddress)
98
+ end
99
+
100
+ it "builds unique models" do
101
+ form.build_mailing_address
102
+ form.build_mailing_address
103
+ address_model_1 = form.mailing_addresses.first
104
+ address_model_2 = form.mailing_addresses.last
105
+ address_model_1.should_not eq(address_model_2)
106
+ address_model_1.address.should_not eq(address_model_2.address)
107
+ end
108
+
109
+ it "builds with correct default initializer" do
110
+ address_model = form.build_mailing_address
111
+ address_model.address.should be_a(OpenStruct)
112
+ end
113
+
114
+ it "builds with custom initializer" do
115
+ address_model = form.build_mailing_address({:address => Date.new})
116
+ address_model.address.should be_a(Date)
160
117
  end
161
- end
118
+ end
162
119
  end
120
+
121
+ describe "setting attributes" do
122
+ describe "nested attribute assignment" do
123
+ let(:attributes) do
124
+ { :mailing_addresses_attributes => { "0" => { :street => "123 Main St." } } }
125
+ end
126
+
127
+ it "assigns nested attributes" do
128
+ form.fill(attributes)
129
+ form.mailing_addresses.first.street.should eq("123 Main St.")
130
+ end
131
+ end
132
+ end
163
133
  end
@@ -0,0 +1,304 @@
1
+ require 'spec_helper'
2
+
3
+ describe FreeForm::Form do
4
+ let(:form_class) do
5
+ klass = Class.new(FreeForm::Form) do
6
+ form_input_key :task
7
+ form_models :task
8
+ validate_models
9
+ allow_destroy_on_save
10
+
11
+ property :name, :on => :task
12
+ property :start_date, :on => :task
13
+ property :end_date, :on => :task
14
+ validates :name, :presence => true
15
+
16
+ has_many :milestones do
17
+ form_input_key :milestone
18
+ form_model :milestone
19
+ validate_models
20
+ allow_destroy_on_save
21
+
22
+ property :name, :on => :milestone
23
+ end
24
+
25
+ def milestone_initializer
26
+ { :milestone => task.milestones.build }
27
+ end
28
+ end
29
+ # This wrapper just avoids CONST warnings
30
+ v, $VERBOSE = $VERBOSE, nil
31
+ Module.const_set("AcceptanceForm", klass)
32
+ $VERBOSE = v
33
+ klass
34
+ end
35
+
36
+ let(:company) { Company.create!(:name => "Demo Corporation") }
37
+ let(:project) { Project.create!(:owner => company, :name => "Widget", :due_date => Date.new(2014, 1, 1)) }
38
+ let(:task) { Task.new(:project => project) }
39
+
40
+ let(:form) do
41
+ form_class.new( :task => task ).tap do |f|
42
+ f.build_milestone
43
+ end
44
+ end
45
+
46
+ before(:each) { Milestone.destroy_all }
47
+
48
+ describe "form initialization", :initialization => true do
49
+ it "initializes with task model" do
50
+ form.task.should eq(task)
51
+ end
52
+
53
+ it "initializes with a milestone model" do
54
+ form.milestones.should_not be_empty
55
+ end
56
+ end
57
+
58
+ describe "saving", :saving => true do
59
+ context "with invalid attributes on primary form" do
60
+ let(:attributes) do {
61
+ :name => nil,
62
+ "start_date(1i)" => "2012",
63
+ "start_date(2i)" => "1",
64
+ "start_date(3i)" => "2",
65
+ "end_date(1i)" => "2011",
66
+ "end_date(2i)" => "12",
67
+ "end_date(3i)" => "15",
68
+ :milestones_attributes => {
69
+ "0" => {
70
+ :name => "milestone_1",
71
+ },
72
+ "1310201" => {
73
+ :name => "milestone_2",
74
+ }
75
+ } }
76
+ end
77
+
78
+ before(:each) do
79
+ form.fill(attributes)
80
+ end
81
+
82
+ it "should not be valid" do
83
+ form.should_not be_valid
84
+ end
85
+
86
+ describe "#save" do
87
+ it "should return false on 'save'" do
88
+ form.save.should be_false
89
+ end
90
+
91
+ it "should not persist task" do
92
+ form.save
93
+ task.should_not exist_in_database
94
+ end
95
+
96
+ it "should not save any Milestone objects" do
97
+ form.save
98
+ Milestone.all.size.should eq(0)
99
+ end
100
+ end
101
+
102
+ describe "#save!" do
103
+ it "should raise error on 'save!'" do
104
+ expect{ form.save! }.to raise_error(FreeForm::FormInvalid)
105
+ end
106
+ end
107
+ end
108
+
109
+ context "with invalid attributes on nested form" do
110
+ let(:attributes) do {
111
+ :name => "newtask",
112
+ "start_date(1i)" => "2012",
113
+ "start_date(2i)" => "1",
114
+ "start_date(3i)" => "2",
115
+ "end_date(1i)" => "2011",
116
+ "end_date(2i)" => "12",
117
+ "end_date(3i)" => "15",
118
+ :milestones_attributes => {
119
+ "0" => {
120
+ :name => "milestone_1",
121
+ },
122
+ "1310201" => {
123
+ :name => nil,
124
+ }
125
+ } }
126
+ end
127
+
128
+ before(:each) do
129
+ form.fill(attributes)
130
+ end
131
+
132
+ it "should not be valid" do
133
+ form.should_not be_valid
134
+ end
135
+
136
+ describe "#save" do
137
+ it "should return false on 'save'" do
138
+ form.save.should be_false
139
+ end
140
+
141
+ it "should not persist task" do
142
+ form.save
143
+ task.should_not exist_in_database
144
+ end
145
+
146
+ it "should not save any Milestone objects" do
147
+ form.save
148
+ Milestone.all.size.should eq(0)
149
+ end
150
+ end
151
+
152
+ describe "#save!" do
153
+ it "should raise error on 'save!'" do
154
+ expect{ form.save! }.to raise_error(FreeForm::FormInvalid)
155
+ end
156
+ end
157
+ end
158
+
159
+ context "with invalid attributes on destroyed nested form" do
160
+ let(:attributes) do {
161
+ :name => "newtask",
162
+ "start_date(1i)" => "2012",
163
+ "start_date(2i)" => "1",
164
+ "start_date(3i)" => "2",
165
+ "end_date(1i)" => "2011",
166
+ "end_date(2i)" => "12",
167
+ "end_date(3i)" => "15",
168
+ :milestones_attributes => {
169
+ "0" => {
170
+ :name => "milestone_1",
171
+ },
172
+ "1310201" => {
173
+ :name => nil,
174
+ :_destroy => "1",
175
+ }
176
+ } }
177
+ end
178
+
179
+ before(:each) do
180
+ form.fill(attributes)
181
+ end
182
+
183
+ it "should not be valid" do
184
+ form.should be_valid
185
+ end
186
+
187
+ describe "#save" do
188
+ it "should return true on 'save'" do
189
+ form.save.should be_true
190
+ end
191
+
192
+ it "should persist task" do
193
+ form.save
194
+ task.should exist_in_database
195
+ end
196
+
197
+ it "should save one Milestone object" do
198
+ form.save
199
+ Milestone.all.size.should eq(1)
200
+ end
201
+ end
202
+
203
+ describe "#save!" do
204
+ it "should not raise error on 'save!'" do
205
+ expect{ form.save! }.to_not raise_error
206
+ end
207
+ end
208
+ end
209
+
210
+ context "with valid attributes and multiple nested forms" do
211
+ let(:attributes) do {
212
+ :name => "newtask",
213
+ "start_date(1i)" => "2012",
214
+ "start_date(2i)" => "1",
215
+ "start_date(3i)" => "2",
216
+ "end_date(1i)" => "2011",
217
+ "end_date(2i)" => "12",
218
+ "end_date(3i)" => "15",
219
+ :milestones_attributes => {
220
+ "0" => {
221
+ :name => "milestone_1",
222
+ },
223
+ "1310201" => {
224
+ :name => "milestone_2",
225
+ },
226
+ "9837373" => {
227
+ :name => "milestone_3",
228
+ }
229
+ } }
230
+ end
231
+
232
+ before(:each) do
233
+ form.fill(attributes)
234
+ end
235
+
236
+ it "should not be valid" do
237
+ form.should be_valid
238
+ end
239
+
240
+ describe "#save" do
241
+ it "should return true on 'save'" do
242
+ form.save.should be_true
243
+ end
244
+
245
+ it "should persist task" do
246
+ form.save
247
+ task.should exist_in_database
248
+ end
249
+
250
+ it "should save three Milestone objects" do
251
+ form.save
252
+ Milestone.all.size.should eq(3)
253
+ end
254
+ end
255
+
256
+ describe "#save!" do
257
+ it "should not raise error on 'save!'" do
258
+ expect{ form.save! }.to_not raise_error
259
+ end
260
+ end
261
+ end
262
+ end
263
+
264
+ describe "destroying", :destroying => true do
265
+ context "without nested forms" do
266
+ let(:task) { Task.create!(:project => project, :name => "mytask", :start_date => Date.new(2011, 1, 1), :end_date => Date.new(2012, 1, 1)) }
267
+
268
+ let(:form) do
269
+ form_class.new( :task => task )
270
+ end
271
+
272
+ it "destroys all models in form" do
273
+ form.destroy
274
+ task.should_not exist_in_database
275
+ end
276
+ end
277
+
278
+ context "with nested forms" do
279
+ let(:task) { Task.create!(:project => project, :name => "mytask", :start_date => Date.new(2011, 1, 1), :end_date => Date.new(2012, 1, 1)) }
280
+ let(:milestone) do
281
+ task.milestones.build do |m|
282
+ m.name = "dummy_milestone"
283
+ m.save!
284
+ end
285
+ end
286
+
287
+ let(:form) do
288
+ form_class.new( :task => task ).tap do |f|
289
+ f.build_milestone(:milestone => milestone)
290
+ end
291
+ end
292
+
293
+ it "destroys all models in form" do
294
+ form.destroy
295
+ task.should_not exist_in_database
296
+ end
297
+
298
+ it "destroys all nested models" do
299
+ form.destroy
300
+ milestone.should_not exist_in_database
301
+ end
302
+ end
303
+ end
304
+ end