ess 0.9.1

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.
@@ -0,0 +1,796 @@
1
+ require 'time'
2
+ require 'spec_helper'
3
+ require 'ess/helpers'
4
+
5
+ module ESS
6
+ describe Element do
7
+
8
+ describe '#new' do
9
+ it 'should require a name and a DTD argument' do
10
+ expect { Element.new }.to raise_error
11
+ expect { Element.new :tag_name }.to raise_error
12
+ end
13
+
14
+ it 'should accept a hash with both :attributes and :tags keys' do
15
+ lambda {
16
+ Element.new(:tag_name, {:attributes => "", :tags => ""})
17
+ }.should_not raise_error
18
+ end
19
+ end
20
+
21
+ describe '#text!' do
22
+ let(:element) { Element.new(:tag_name, {:attributes => "", :tags => ""}) }
23
+
24
+ context 'when text was not preset' do
25
+ context 'without parameters' do
26
+ it 'should return an empty string' do
27
+ element.text!.should == ""
28
+ end
29
+ end
30
+ context 'with parameters' do
31
+ it 'should accept one parameter' do
32
+ lambda {
33
+ element.text!("Example text")
34
+ }.should_not raise_error
35
+ end
36
+
37
+ it 'should set the text value of the element to that parameter' do
38
+ element.text! "Example text"
39
+ element.text!.should == "Example text"
40
+ end
41
+ end
42
+ end
43
+
44
+ context 'when text was preset' do
45
+ before(:each) { element.text! "Example text" }
46
+
47
+ context 'without parameters' do
48
+ it 'should return that text' do
49
+ element.text!.should == "Example text"
50
+ end
51
+ end
52
+ context 'with parameters' do
53
+ it 'should accept one parameter' do
54
+ lambda {
55
+ element.text!("Example text")
56
+ }.should_not raise_error
57
+ end
58
+
59
+ it 'should set the text value of the element to that parameter' do
60
+ element.text! "Example text"
61
+ element.text!.should == "Example text"
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ context 'element with one tag' do
68
+ let(:element) { Element.new(:tags, DTD::TAGS) }
69
+
70
+ it 'should return an error when trying to set an invalid tag' do
71
+ expect { element.bad "Example text" }.to raise_error
72
+ expect { element.bad }.to raise_error
73
+ expect { element.add_bad "Example text" }.to raise_error
74
+ end
75
+
76
+ describe '#tag' do
77
+ context 'called for the first time without parameters' do
78
+ it 'should return an Element instance with a proper DTD and no text' do
79
+ element.tag.class.should == Element
80
+ element.tag.dtd.should == DTD::BASIC_ELEMENT
81
+ element.tag.text!.should == ""
82
+ end
83
+ end
84
+
85
+ context 'called a second time' do
86
+ it 'should return the same object' do
87
+ tag_tag = element.tag
88
+ tag_tag.object_id.should == element.tag.object_id
89
+ end
90
+ end
91
+
92
+ context 'called with a string' do
93
+ it 'should set the new elements text with that value' do
94
+ element.tag "Example text"
95
+ element.tag.text!.should == "Example text"
96
+ end
97
+ end
98
+
99
+ context 'called with a block' do
100
+ it 'should yield that block with the "tag" element as an argument' do
101
+ lambda {
102
+ element.tag { |tag| tag.text! "Example text" }
103
+ }.should_not raise_error
104
+ element.tag.text!.should == "Example text"
105
+ end
106
+ end
107
+ end
108
+
109
+ describe '#tag_list' do
110
+ context 'when no "tag" tags have been added' do
111
+ it 'should return an empty list' do
112
+ element.tag_list.should == []
113
+ end
114
+ end
115
+
116
+ context 'when one tag has been added with the #tag method' do
117
+ it 'should return a list with one element' do
118
+ element.tag "Example text"
119
+ element.tag_list.length.should == 1
120
+ element.tag_list[0].class.should == Element
121
+ end
122
+ end
123
+ end
124
+
125
+ describe '#add_tag' do
126
+ context 'when no tags preset' do
127
+ it 'should create that one tag' do
128
+ element.add_tag "Example text"
129
+ element.tag.text!.should == "Example text"
130
+ element.tag_list.length.should == 1
131
+ end
132
+ end
133
+
134
+ context 'when called a second time' do
135
+ before(:each) { element.add_tag "Example text 1" }
136
+ it 'should add another tag of the same type' do
137
+ element.add_tag "Example text 2"
138
+ element.tag_list.length.should == 2
139
+ element.tag_list[0].text!.should == "Example text 1"
140
+ element.tag_list[1].text!.should == "Example text 2"
141
+ end
142
+ end
143
+
144
+ context 'called with a block' do
145
+ it 'should yield that block with the new "tag" element as an argument' do
146
+ lambda {
147
+ element.add_tag { |tag| tag.text! "Example text" }
148
+ }.should_not raise_error
149
+ element.tag.text!.should == "Example text"
150
+ end
151
+ end
152
+ end
153
+ end
154
+
155
+ context 'with attributes, ESS tag for example' do
156
+ let(:element) { Element.new(:ess, DTD::ESS) }
157
+
158
+ describe '#xmlns_attr' do
159
+ it 'should return an empty string if it was not yet set' do
160
+ element.xmlns_attr.should == ""
161
+ end
162
+
163
+ it 'should return the preset value if the attribute was set' do
164
+ element.xmlns_attr "Example value"
165
+ element.xmlns_attr.should == "Example value"
166
+ end
167
+
168
+ it 'should allow redefining the value of the attribute' do
169
+ element.xmlns_attr "Example value"
170
+ element.xmlns_attr "Another example value"
171
+ element.xmlns_attr.should == "Another example value"
172
+ end
173
+ end
174
+
175
+ describe '#to_xml!' do
176
+ it 'should include the attribute value in xml' do
177
+ element.xmlns_attr "Example value"
178
+ element.to_xml!.should include('<ess xmlns="Example value"></ess>')
179
+ end
180
+
181
+ it 'should include values for multiple attributes in xml' do
182
+ element.xmlns_attr "xmlns value"
183
+ element.version_attr "Version value"
184
+ element.to_xml!.should include('xmlns="xmlns value"')
185
+ element.to_xml!.should include('version="Version value"')
186
+ end
187
+ end
188
+ end
189
+
190
+ context 'with a child tag with attributes, CATEGORIES tag for example' do
191
+ let(:element) { Element.new(:categories, DTD::CATEGORIES) }
192
+
193
+ describe '#item' do
194
+ it 'should accept setting of the attribute value in a hash argument' do
195
+ element.item :type => "competition"
196
+ element.item.type_attr.should == "competition"
197
+ end
198
+
199
+ it 'should accept setting both text and attributes at the same time' do
200
+ element.item "Example text", :type => "competition"
201
+ element.item.type_attr.should == "competition"
202
+ element.item.text!.should == "Example text"
203
+ end
204
+ end
205
+
206
+ describe '#add_item' do
207
+ it 'should accept setting both text and attributes in a hash argument at the same time' do
208
+ element.add_item "Example text", :type => "competition"
209
+ element.item.type_attr.should == "competition"
210
+ element.item.text!.should == "Example text"
211
+ end
212
+ end
213
+ end
214
+
215
+ describe '#to_xml!' do
216
+ let(:element) { Element.new(:channel, DTD::CHANNEL) }
217
+
218
+ it 'should return a string' do
219
+ element.to_xml!.class.should == String
220
+ end
221
+
222
+ context 'when the element is completely empty' do
223
+ it 'should return at least the starting and ending tags' do
224
+ element.to_xml!.should include("<channel></channel>")
225
+ end
226
+ end
227
+
228
+ context 'when the element has text preset' do
229
+ before(:each) { element.text! "Example text" }
230
+ it 'should return the starting and ending tags with the text between them' do
231
+ element.to_xml!.should include("<channel>Example text</channel>")
232
+ end
233
+ end
234
+
235
+ context 'when the element has child elements' do
236
+ before(:each) { element.generator "ruby" }
237
+ it 'should return the starting and ending tags, and the same for the child tag' do
238
+ element.to_xml!.should include("<channel><generator>ruby</generator></channel>")
239
+ end
240
+ end
241
+ end
242
+
243
+ context 'with attributes with restricted value, for example DATE_ITEM' do
244
+ let(:element) { Element.new(:item, DTD::DATE_ITEM) }
245
+
246
+ it 'should allow valid value for that attribute' do
247
+ lambda {
248
+ element.type_attr "standalone"
249
+ }.should_not raise_error
250
+ end
251
+
252
+ it 'should raise error if an invalid value was used for an attribute' do
253
+ expect { element.type_attr "bad_value" }.to raise_error
254
+ end
255
+
256
+ it 'should allow multiple comma separated valid values' do
257
+ lambda {
258
+ element.selected_day_attr "friday,saturday"
259
+ }.should_not raise_error
260
+ end
261
+
262
+ it 'should raise error if one value is valid and the other is not' do
263
+ expect {
264
+ element.selected_day_attr "friday,bad"
265
+ }.to raise_error
266
+ end
267
+ end
268
+
269
+ describe '#valid?' do
270
+ context 'called on an element with one mandatory tag with infinite number' do
271
+ let(:element) { Element.new :tags, DTD::TAGS }
272
+
273
+ it 'should return false if that mandatory tag was not defined' do
274
+ element.should_not be_valid
275
+ end
276
+
277
+ it 'should return true if there is one mandatory tag defined' do
278
+ element.tag "Example text"
279
+ element.should be_valid
280
+ end
281
+
282
+ it 'should return true if there are more then one instances of that tag' do
283
+ element.add_tag "Example text 1"
284
+ element.add_tag "Example text 2"
285
+ element.should be_valid
286
+ end
287
+ end
288
+
289
+ context 'called on an element with mandatory tags and counter restricted' do
290
+ let(:element) do
291
+ element = Element.new :tags, DTD::RELATION_ITEM
292
+ element.type_attr "related"
293
+ element
294
+ end
295
+
296
+ it 'should return true if all tags presents and within limits' do
297
+ element.name "Example name"
298
+ element.uri "Example uri"
299
+ element.id "Example id"
300
+ element.should be_valid
301
+ end
302
+ it 'should return false if at least one tag has too many elements' do
303
+ element.add_name "Example name 1"
304
+ element.add_name "Example name 2"
305
+ element.uri "Example uri"
306
+ element.id "Example id"
307
+ element.should_not be_valid
308
+ end
309
+ end
310
+
311
+ context 'when child elements need to be tested too' do
312
+ let(:element) do
313
+ element = Element.new :feed, DTD::FEED
314
+ element.title "A title"
315
+ element.id "An ID"
316
+ element.access "PUBLIC"
317
+ element.description "desc"
318
+ element.published Time.now.to_s
319
+ element.uri "http://example.com/"
320
+ element.categories.add_item :type => "award" do |item|
321
+ item.name "A name"
322
+ item.id "An ID"
323
+ end
324
+ element.dates.add_item :type => "standalone" do |item|
325
+ item.name "A name"
326
+ item.start Time.now.to_s
327
+ end
328
+ element.places.add_item :type => "fixed" do |item|
329
+ item.name "A name"
330
+ end
331
+ element
332
+ end
333
+
334
+ it 'should return true if a valid element was generated' do
335
+ element.should be_valid
336
+ end
337
+
338
+ it 'should return false if a child of the element is not valid' do
339
+ # Creating a places item without a name tag to make it invalid
340
+ element.places.add_item
341
+ element.should_not be_valid
342
+ end
343
+ end
344
+ end
345
+
346
+ describe 'tag valid values' do
347
+ let(:element) { Element.new :feed, DTD::FEED }
348
+
349
+ describe '#access' do
350
+ it 'should allow PUBLIC and PRIVATE values' do
351
+ lambda {
352
+ element.access "PUBLIC"
353
+ element.access "PRIVATE"
354
+ }.should_not raise_error
355
+ end
356
+
357
+ it 'should not allow other values' do
358
+ expect { element.access "bad" }.to raise_error
359
+ end
360
+ end
361
+ end
362
+
363
+ describe 'postprocessing' do
364
+ describe 'Feed element' do
365
+ let(:element) { Element.new(:feed, DTD::FEED) }
366
+
367
+ describe '#id' do
368
+ it 'should replace id with a regular event uuid when receiving regular text' do
369
+ element.id "Some text"
370
+ element.id.text!.should == Helpers::uuid("Some text", 'EVENTID:')
371
+ end
372
+ end
373
+
374
+ context 'when no id set' do
375
+ describe '#title' do
376
+ it 'should automatically set the feed id to a uuid(title)' do
377
+ a_title = "A title"
378
+ puts element.id.text!
379
+ element.title a_title
380
+ element.id.text!.should == Helpers::uuid(a_title, 'EVENTID:')
381
+ end
382
+ end
383
+
384
+ describe '#add_title' do
385
+ it 'should automatically set the feed id to a uuid(title)' do
386
+ a_title = "A title"
387
+ element.add_title a_title
388
+ element.id.text!.should == Helpers::uuid(a_title, 'EVENTID:')
389
+ end
390
+ end
391
+
392
+ describe '#uri' do
393
+ it 'should automatically set the feed id to a uuid(uri)' do
394
+ an_uri = "http://event/uri/"
395
+ element.uri an_uri
396
+ element.id.text!.should == Helpers::uuid(an_uri, 'EVENTID:')
397
+ end
398
+ end
399
+
400
+ describe '#add_uri' do
401
+ it 'should automatically set the feed id to a uuid(uri)' do
402
+ an_uri = "http://event/uri/"
403
+ element.add_uri an_uri
404
+ element.id.text!.should == Helpers::uuid(an_uri, 'EVENTID:')
405
+ end
406
+ end
407
+ end
408
+
409
+ context 'when id was set' do
410
+ let(:an_id) { Helpers::uuid("Some text", 'EVENTID:') }
411
+ before(:each) { element.id an_id }
412
+
413
+ describe '#title' do
414
+ it 'should not automatically set the feed id to a uuid(title)' do
415
+ a_title = "A title"
416
+ element.title a_title
417
+ element.id.text!.should == an_id
418
+ end
419
+ end
420
+
421
+ describe '#add_title' do
422
+ it 'should not automatically set the feed id to a uuid(title)' do
423
+ a_title = "A title"
424
+ element.add_title a_title
425
+ element.id.text!.should == an_id
426
+ end
427
+ end
428
+
429
+ describe '#uri' do
430
+ it 'should not automatically set the feed id to a uuid(uri)' do
431
+ an_uri = "http://event/uri/"
432
+ element.uri an_uri
433
+ element.id.text!.should == an_id
434
+ end
435
+ end
436
+
437
+ describe '#add_uri' do
438
+ it 'should not automatically set the feed id to a uuid(uri)' do
439
+ an_uri = "http://event/uri/"
440
+ element.add_uri an_uri
441
+ element.id.text!.should == an_id
442
+ end
443
+ end
444
+ end
445
+
446
+ describe '#published' do
447
+ it 'should accept Time objects and return a string in ISO8601 format' do
448
+ current_time = Time.now
449
+ element.published current_time
450
+ element.published.text!.should == current_time.iso8601
451
+ end
452
+
453
+ it 'should accept string in ISO8601 format and keep them the same' do
454
+ current_time = Time.now.iso8601
455
+ element.published current_time
456
+ element.published.text!.should == current_time
457
+ end
458
+ end
459
+ end
460
+
461
+ describe 'Description element' do
462
+ let(:element) { Element.new :description, DTD::DESCRIPTION }
463
+ it 'should strip unwanted tags from the description' do
464
+ desc = "<p> About this feed... </p> <script src=\"test.js\"></script>"
465
+ element.text! desc
466
+ element.text!.should == "<p> About this feed... </p>"
467
+ end
468
+ end
469
+
470
+ describe 'Channel element' do
471
+ let(:element) { Element.new(:channel, DTD::CHANNEL) }
472
+
473
+ context 'when no id set' do
474
+ describe '#title' do
475
+ it 'should automatically set the channel id to a uuid(title)' do
476
+ a_title = "A title"
477
+ element.title a_title
478
+ element.id.text!.should == Helpers::uuid(a_title, 'ESSID:')
479
+ end
480
+ end
481
+
482
+ describe '#add_title' do
483
+ it 'should automatically set the channel id to a uuid(title)' do
484
+ a_title = "A title"
485
+ element.add_title a_title
486
+ element.id.text!.should == Helpers::uuid(a_title, 'ESSID:')
487
+ end
488
+ end
489
+ end
490
+
491
+ context 'when id was set' do
492
+ let(:an_id) { Helpers::uuid("Some text", 'ESSID:') }
493
+
494
+ describe '#title' do
495
+ it 'should not automatically set the channel id to a uuid(title)' do
496
+ element.id an_id
497
+ a_title = "A title"
498
+ element.title a_title
499
+ element.id.text!.should == an_id
500
+ end
501
+ end
502
+
503
+ describe '#add_title' do
504
+ it 'should not automatically set the channel id to a uuid(title)' do
505
+ element.id an_id
506
+ a_title = "A title"
507
+ element.add_title a_title
508
+ element.id.text!.should == an_id
509
+ end
510
+ end
511
+ end
512
+ end
513
+ end
514
+
515
+ describe 'Validation' do
516
+ context 'an empty element which should not be empty' do
517
+ let(:element) do
518
+ element = Element.new :description, DTD::BASIC_ELEMENT
519
+ element.text! " "
520
+ element
521
+ end
522
+
523
+ it 'should be invalid' do
524
+ element.should_not be_valid
525
+ end
526
+
527
+ it 'should be valid if fixed' do
528
+ element.text! "Sample text"
529
+ element.should be_valid
530
+ end
531
+ end
532
+
533
+ context 'an URL element' do
534
+ let(:element) { Element.new :logo, DTD::URL_ELEMENT }
535
+
536
+ it 'should be invalid if a bad URL is set' do
537
+ element.text! "bad url"
538
+ element.should_not be_valid
539
+ end
540
+
541
+ it 'should be valid if valid URL is set' do
542
+ element.text! "http://Example.com:8000/"
543
+ element.should be_valid
544
+ end
545
+
546
+ it 'should be valid if valid IP address is set' do
547
+ element.text! "192.168.0.1"
548
+ element.should be_valid
549
+ end
550
+ end
551
+
552
+ context 'an latitude element' do
553
+ let(:element) { Element.new :latitude, DTD::LATITUDE }
554
+
555
+ it 'should be invalid if not a floating point number' do
556
+ element.text! "bad"
557
+ element.should_not be_valid
558
+ end
559
+
560
+ it 'should be invalid if above limits' do
561
+ element.text! "1000.000"
562
+ element.should_not be_valid
563
+ end
564
+
565
+ it 'should be valid if within limit' do
566
+ element.text! "70.31"
567
+ element.should be_valid
568
+ end
569
+ end
570
+
571
+ context 'an longitude element' do
572
+ let(:element) { Element.new :longitude, DTD::LONGITUDE }
573
+
574
+ it 'should be invalid if not a floating point number' do
575
+ element.text! "bad"
576
+ element.should_not be_valid
577
+ end
578
+
579
+ it 'should be invalid if above limits' do
580
+ element.text! "1000.000"
581
+ element.should_not be_valid
582
+ end
583
+
584
+ it 'should be valid if within limit' do
585
+ element.text! "90.31"
586
+ element.should be_valid
587
+ end
588
+ end
589
+
590
+ context 'a country code element' do
591
+ let(:element) { Element.new :country_code, DTD::COUNTRY_CODE }
592
+
593
+ it 'should be invalid if not a valid country code' do
594
+ element.text! "bad"
595
+ element.should_not be_valid
596
+ end
597
+
598
+ it 'should be valid if valid country code' do
599
+ element.text! "US"
600
+ element.should be_valid
601
+ end
602
+
603
+ it 'should be valid if valid country code but lower case is used' do
604
+ element.text! "us"
605
+ element.should be_valid
606
+ end
607
+ end
608
+
609
+ context 'a currency element' do
610
+ let(:element) { Element.new :currency, DTD::CURRENCY }
611
+
612
+ it 'should be invalid if not a valid currency' do
613
+ element.text! "bad"
614
+ element.should_not be_valid
615
+ end
616
+
617
+ it 'should be valid if valid currency' do
618
+ element.text! "USD"
619
+ element.should be_valid
620
+ end
621
+
622
+ it 'should be valid if valid currency but lower case is used' do
623
+ element.text! "usd"
624
+ element.should be_valid
625
+ end
626
+ end
627
+
628
+ context 'a price item with a value tag, but without a currency tag' do
629
+ let(:element) do
630
+ element = Element.new :item, DTD::PRICE_ITEM
631
+ element.type_attr "standalone"
632
+ element.mode_attr "fixed"
633
+ element.name "Example name"
634
+ element
635
+ end
636
+
637
+ context 'when value is 0' do
638
+ before(:each) { element.value 0 }
639
+
640
+ it 'should not raise error' do
641
+ lambda {
642
+ element.validate
643
+ }.should_not raise_error
644
+ end
645
+ end
646
+
647
+ context 'when value is not 0' do
648
+ before(:each) { element.value 5 }
649
+
650
+ it 'should raise an error' do
651
+ lambda {
652
+ element.validate
653
+ }.should raise_error
654
+ end
655
+ end
656
+ end
657
+
658
+ context 'attributes' do
659
+ describe 'an element with a mandatory attribute' do
660
+ let(:element) do
661
+ element = Element.new :item, DTD::PRICE_ITEM
662
+ element.name "Example name"
663
+ element.value 0
664
+ element
665
+ end
666
+
667
+ context 'when the mandatory attribute is missing' do
668
+ it 'should be invalid' do
669
+ element.should_not be_valid
670
+ end
671
+ end
672
+
673
+ context 'when the mandatory attribute is set' do
674
+ it 'should be valid' do
675
+ element.type_attr "standalone"
676
+ element.mode_attr "fixed"
677
+ element.should be_valid
678
+ end
679
+ end
680
+ end
681
+
682
+ describe 'an element with an attribute with one value limit' do
683
+ let(:element) do
684
+ element = Element.new :item, DTD::PRICE_ITEM
685
+ element.mode_attr "fixed"
686
+ element.name "Example name"
687
+ element.value 0
688
+ element
689
+ end
690
+
691
+ context 'when single value is set' do
692
+ before(:each) { element.type_attr "standalone" }
693
+
694
+ it 'should be valid' do
695
+ element.should be_valid
696
+ end
697
+ end
698
+
699
+ context 'when a multiple value is set' do
700
+ before(:each) { element.type_attr "standalone,recurrent" }
701
+
702
+ it 'should not be valid' do
703
+ element.should_not be_valid
704
+ end
705
+ end
706
+ end
707
+
708
+ describe 'lang attribute in ESS tag' do
709
+ let(:element) { Examples.ring_cycle }
710
+
711
+ context 'when attribute has a valid value' do
712
+ it 'should be valid' do
713
+ element.lang_attr "zu"
714
+ element.should be_valid
715
+ end
716
+ end
717
+
718
+ context 'when attribute has an invalid value' do
719
+ it 'should not be valid' do
720
+ element.lang_attr "bad"
721
+ element.should_not be_valid
722
+ end
723
+ end
724
+ end
725
+ end
726
+
727
+ context "a date item" do
728
+ let(:element) do
729
+ element = Element.new(:item, DTD::DATE_ITEM)
730
+ element.name "An example date"
731
+ element.start Time.now
732
+ element
733
+ end
734
+
735
+ context 'type is recurrent' do
736
+ before(:each) { element.type_attr "recurrent" }
737
+ context 'unit type is defined' do
738
+ it 'should be valid' do
739
+ element.unit_attr "month"
740
+ element.should be_valid
741
+ end
742
+ end
743
+ context 'unit type is not defined' do
744
+ it 'should not be valid' do
745
+ element.should_not be_valid
746
+ end
747
+ end
748
+ end
749
+
750
+ context 'type is standalone' do
751
+ before(:each) { element.type_attr "standalone" }
752
+
753
+ it 'should be valid without unit attr' do
754
+ element.should be_valid
755
+ end
756
+ end
757
+ end
758
+
759
+ context "a price item" do
760
+ let(:element) do
761
+ element = Element.new(:item, DTD::PRICE_ITEM)
762
+ element.mode_attr "fixed"
763
+ element.name "An example price"
764
+ element.value 10
765
+ element.currency "USD"
766
+ element.start Time.now
767
+ element
768
+ end
769
+
770
+ context 'type is recurrent' do
771
+ before(:each) { element.type_attr "recurrent" }
772
+ context 'unit type is defined' do
773
+ it 'should be valid' do
774
+ element.unit_attr "month"
775
+ element.should be_valid
776
+ end
777
+ end
778
+ context 'unit type is not defined' do
779
+ it 'should not be valid' do
780
+ element.should_not be_valid
781
+ end
782
+ end
783
+ end
784
+
785
+ context 'type is standalone' do
786
+ before(:each) { element.type_attr "standalone" }
787
+
788
+ it 'should be valid without unit attr' do
789
+ element.should be_valid
790
+ end
791
+ end
792
+ end
793
+ end
794
+ end
795
+ end
796
+