]> git.immae.eu Git - github/wallabag/wallabag.git/blob - vendor/symfony/form/Symfony/Component/Form/Tests/AbstractLayoutTest.php
twig implementation
[github/wallabag/wallabag.git] / vendor / symfony / form / Symfony / Component / Form / Tests / AbstractLayoutTest.php
1 <?php
2
3 /*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12 namespace Symfony\Component\Form\Tests;
13
14 use Symfony\Component\Form\FormError;
15 use Symfony\Component\Form\FormView;
16 use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
17
18 abstract class AbstractLayoutTest extends \Symfony\Component\Form\Test\FormIntegrationTestCase
19 {
20 protected $csrfProvider;
21
22 protected function setUp()
23 {
24 if (!extension_loaded('intl')) {
25 $this->markTestSkipped('The "intl" extension is not available');
26 }
27
28 \Locale::setDefault('en');
29
30 $this->csrfProvider = $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface');
31
32 parent::setUp();
33 }
34
35 protected function getExtensions()
36 {
37 return array(
38 new CsrfExtension($this->csrfProvider),
39 );
40 }
41
42 protected function tearDown()
43 {
44 $this->csrfProvider = null;
45
46 parent::tearDown();
47 }
48
49 protected function assertXpathNodeValue(\DomElement $element, $expression, $nodeValue)
50 {
51 $xpath = new \DOMXPath($element->ownerDocument);
52 $nodeList = $xpath->evaluate($expression);
53 $this->assertEquals(1, $nodeList->length);
54 $this->assertEquals($nodeValue, $nodeList->item(0)->nodeValue);
55 }
56
57 protected function assertMatchesXpath($html, $expression, $count = 1)
58 {
59 $dom = new \DomDocument('UTF-8');
60 try {
61 // Wrap in <root> node so we can load HTML with multiple tags at
62 // the top level
63 $dom->loadXml('<root>'.$html.'</root>');
64 } catch (\Exception $e) {
65 $this->fail(sprintf(
66 "Failed loading HTML:\n\n%s\n\nError: %s",
67 $html,
68 $e->getMessage()
69 ));
70 }
71 $xpath = new \DOMXPath($dom);
72 $nodeList = $xpath->evaluate('/root'.$expression);
73
74 if ($nodeList->length != $count) {
75 $dom->formatOutput = true;
76 $this->fail(sprintf(
77 "Failed asserting that \n\n%s\n\nmatches exactly %s. Matches %s in \n\n%s",
78 $expression,
79 $count == 1 ? 'once' : $count.' times',
80 $nodeList->length == 1 ? 'once' : $nodeList->length.' times',
81 // strip away <root> and </root>
82 substr($dom->saveHTML(), 6, -8)
83 ));
84 }
85 }
86
87 protected function assertWidgetMatchesXpath(FormView $view, array $vars, $xpath)
88 {
89 // include ampersands everywhere to validate escaping
90 $html = $this->renderWidget($view, array_merge(array(
91 'id' => 'my&id',
92 'attr' => array('class' => 'my&class'),
93 ), $vars));
94
95 $xpath = trim($xpath).'
96 [@id="my&id"]
97 [@class="my&class"]';
98
99 $this->assertMatchesXpath($html, $xpath);
100 }
101
102 abstract protected function renderForm(FormView $view, array $vars = array());
103
104 abstract protected function renderEnctype(FormView $view);
105
106 abstract protected function renderLabel(FormView $view, $label = null, array $vars = array());
107
108 abstract protected function renderErrors(FormView $view);
109
110 abstract protected function renderWidget(FormView $view, array $vars = array());
111
112 abstract protected function renderRow(FormView $view, array $vars = array());
113
114 abstract protected function renderRest(FormView $view, array $vars = array());
115
116 abstract protected function renderStart(FormView $view, array $vars = array());
117
118 abstract protected function renderEnd(FormView $view, array $vars = array());
119
120 abstract protected function setTheme(FormView $view, array $themes);
121
122 public function testEnctype()
123 {
124 $form = $this->factory->createNamedBuilder('name', 'form')
125 ->add('file', 'file')
126 ->getForm();
127
128 $this->assertEquals('enctype="multipart/form-data"', $this->renderEnctype($form->createView()));
129 }
130
131 public function testNoEnctype()
132 {
133 $form = $this->factory->createNamedBuilder('name', 'form')
134 ->add('text', 'text')
135 ->getForm();
136
137 $this->assertEquals('', $this->renderEnctype($form->createView()));
138 }
139
140 public function testLabel()
141 {
142 $form = $this->factory->createNamed('name', 'text');
143 $view = $form->createView();
144 $this->renderWidget($view, array('label' => 'foo'));
145 $html = $this->renderLabel($view);
146
147 $this->assertMatchesXpath($html,
148 '/label
149 [@for="name"]
150 [.="[trans]Name[/trans]"]
151 '
152 );
153 }
154
155 public function testLabelOnForm()
156 {
157 $form = $this->factory->createNamed('name', 'date');
158 $view = $form->createView();
159 $this->renderWidget($view, array('label' => 'foo'));
160 $html = $this->renderLabel($view);
161
162 $this->assertMatchesXpath($html,
163 '/label
164 [@class="required"]
165 [.="[trans]Name[/trans]"]
166 '
167 );
168 }
169
170 public function testLabelWithCustomTextPassedAsOption()
171 {
172 $form = $this->factory->createNamed('name', 'text', null, array(
173 'label' => 'Custom label',
174 ));
175 $html = $this->renderLabel($form->createView());
176
177 $this->assertMatchesXpath($html,
178 '/label
179 [@for="name"]
180 [.="[trans]Custom label[/trans]"]
181 '
182 );
183 }
184
185 public function testLabelWithCustomTextPassedDirectly()
186 {
187 $form = $this->factory->createNamed('name', 'text');
188 $html = $this->renderLabel($form->createView(), 'Custom label');
189
190 $this->assertMatchesXpath($html,
191 '/label
192 [@for="name"]
193 [.="[trans]Custom label[/trans]"]
194 '
195 );
196 }
197
198 public function testLabelWithCustomTextPassedAsOptionAndDirectly()
199 {
200 $form = $this->factory->createNamed('name', 'text', null, array(
201 'label' => 'Custom label',
202 ));
203 $html = $this->renderLabel($form->createView(), 'Overridden label');
204
205 $this->assertMatchesXpath($html,
206 '/label
207 [@for="name"]
208 [.="[trans]Overridden label[/trans]"]
209 '
210 );
211 }
212
213 public function testLabelDoesNotRenderFieldAttributes()
214 {
215 $form = $this->factory->createNamed('name', 'text');
216 $html = $this->renderLabel($form->createView(), null, array(
217 'attr' => array(
218 'class' => 'my&class'
219 ),
220 ));
221
222 $this->assertMatchesXpath($html,
223 '/label
224 [@for="name"]
225 [@class="required"]
226 '
227 );
228 }
229
230 public function testLabelWithCustomAttributesPassedDirectly()
231 {
232 $form = $this->factory->createNamed('name', 'text');
233 $html = $this->renderLabel($form->createView(), null, array(
234 'label_attr' => array(
235 'class' => 'my&class'
236 ),
237 ));
238
239 $this->assertMatchesXpath($html,
240 '/label
241 [@for="name"]
242 [@class="my&class required"]
243 '
244 );
245 }
246
247 public function testLabelWithCustomTextAndCustomAttributesPassedDirectly()
248 {
249 $form = $this->factory->createNamed('name', 'text');
250 $html = $this->renderLabel($form->createView(), 'Custom label', array(
251 'label_attr' => array(
252 'class' => 'my&class'
253 ),
254 ));
255
256 $this->assertMatchesXpath($html,
257 '/label
258 [@for="name"]
259 [@class="my&class required"]
260 [.="[trans]Custom label[/trans]"]
261 '
262 );
263 }
264
265 // https://github.com/symfony/symfony/issues/5029
266 public function testLabelWithCustomTextAsOptionAndCustomAttributesPassedDirectly()
267 {
268 $form = $this->factory->createNamed('name', 'text', null, array(
269 'label' => 'Custom label',
270 ));
271 $html = $this->renderLabel($form->createView(), null, array(
272 'label_attr' => array(
273 'class' => 'my&class'
274 ),
275 ));
276
277 $this->assertMatchesXpath($html,
278 '/label
279 [@for="name"]
280 [@class="my&class required"]
281 [.="[trans]Custom label[/trans]"]
282 '
283 );
284 }
285
286 public function testErrors()
287 {
288 $form = $this->factory->createNamed('name', 'text');
289 $form->addError(new FormError('[trans]Error 1[/trans]'));
290 $form->addError(new FormError('[trans]Error 2[/trans]'));
291 $view = $form->createView();
292 $html = $this->renderErrors($view);
293
294 $this->assertMatchesXpath($html,
295 '/ul
296 [
297 ./li[.="[trans]Error 1[/trans]"]
298 /following-sibling::li[.="[trans]Error 2[/trans]"]
299 ]
300 [count(./li)=2]
301 '
302 );
303 }
304
305 public function testWidgetById()
306 {
307 $form = $this->factory->createNamed('text_id', 'text');
308 $html = $this->renderWidget($form->createView());
309
310 $this->assertMatchesXpath($html,
311 '/div
312 [
313 ./input
314 [@type="text"]
315 [@id="text_id"]
316 ]
317 [@id="container"]
318 '
319 );
320 }
321
322 public function testCheckedCheckbox()
323 {
324 $form = $this->factory->createNamed('name', 'checkbox', true);
325
326 $this->assertWidgetMatchesXpath($form->createView(), array(),
327 '/input
328 [@type="checkbox"]
329 [@name="name"]
330 [@checked="checked"]
331 [@value="1"]
332 '
333 );
334 }
335
336 public function testUncheckedCheckbox()
337 {
338 $form = $this->factory->createNamed('name', 'checkbox', false);
339
340 $this->assertWidgetMatchesXpath($form->createView(), array(),
341 '/input
342 [@type="checkbox"]
343 [@name="name"]
344 [not(@checked)]
345 '
346 );
347 }
348
349 public function testCheckboxWithValue()
350 {
351 $form = $this->factory->createNamed('name', 'checkbox', false, array(
352 'value' => 'foo&bar',
353 ));
354
355 $this->assertWidgetMatchesXpath($form->createView(), array(),
356 '/input
357 [@type="checkbox"]
358 [@name="name"]
359 [@value="foo&bar"]
360 '
361 );
362 }
363
364 public function testSingleChoice()
365 {
366 $form = $this->factory->createNamed('name', 'choice', '&a', array(
367 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
368 'multiple' => false,
369 'expanded' => false,
370 ));
371
372 $this->assertWidgetMatchesXpath($form->createView(), array(),
373 '/select
374 [@name="name"]
375 [@required="required"]
376 [
377 ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
378 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
379 ]
380 [count(./option)=2]
381 '
382 );
383 }
384
385 public function testSingleChoiceWithPreferred()
386 {
387 $form = $this->factory->createNamed('name', 'choice', '&a', array(
388 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
389 'preferred_choices' => array('&b'),
390 'multiple' => false,
391 'expanded' => false,
392 ));
393
394 $this->assertWidgetMatchesXpath($form->createView(), array('separator' => '-- sep --'),
395 '/select
396 [@name="name"]
397 [@required="required"]
398 [
399 ./option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
400 /following-sibling::option[@disabled="disabled"][not(@selected)][.="-- sep --"]
401 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
402 ]
403 [count(./option)=3]
404 '
405 );
406 }
407
408 public function testSingleChoiceWithPreferredAndNoSeparator()
409 {
410 $form = $this->factory->createNamed('name', 'choice', '&a', array(
411 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
412 'preferred_choices' => array('&b'),
413 'multiple' => false,
414 'expanded' => false,
415 ));
416
417 $this->assertWidgetMatchesXpath($form->createView(), array('separator' => null),
418 '/select
419 [@name="name"]
420 [@required="required"]
421 [
422 ./option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
423 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
424 ]
425 [count(./option)=2]
426 '
427 );
428 }
429
430 public function testSingleChoiceWithPreferredAndBlankSeparator()
431 {
432 $form = $this->factory->createNamed('name', 'choice', '&a', array(
433 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
434 'preferred_choices' => array('&b'),
435 'multiple' => false,
436 'expanded' => false,
437 ));
438
439 $this->assertWidgetMatchesXpath($form->createView(), array('separator' => ''),
440 '/select
441 [@name="name"]
442 [@required="required"]
443 [
444 ./option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
445 /following-sibling::option[@disabled="disabled"][not(@selected)][.=""]
446 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
447 ]
448 [count(./option)=3]
449 '
450 );
451 }
452
453 public function testChoiceWithOnlyPreferred()
454 {
455 $form = $this->factory->createNamed('name', 'choice', '&a', array(
456 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
457 'preferred_choices' => array('&a', '&b'),
458 'multiple' => false,
459 'expanded' => false,
460 ));
461
462 $this->assertWidgetMatchesXpath($form->createView(), array(),
463 '/select
464 [count(./option)=2]
465 '
466 );
467 }
468
469 public function testSingleChoiceNonRequired()
470 {
471 $form = $this->factory->createNamed('name', 'choice', '&a', array(
472 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
473 'required' => false,
474 'multiple' => false,
475 'expanded' => false,
476 ));
477
478 $this->assertWidgetMatchesXpath($form->createView(), array(),
479 '/select
480 [@name="name"]
481 [not(@required)]
482 [
483 ./option[@value=""][.="[trans][/trans]"]
484 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
485 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
486 ]
487 [count(./option)=3]
488 '
489 );
490 }
491
492 public function testSingleChoiceNonRequiredNoneSelected()
493 {
494 $form = $this->factory->createNamed('name', 'choice', null, array(
495 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
496 'required' => false,
497 'multiple' => false,
498 'expanded' => false,
499 ));
500
501 $this->assertWidgetMatchesXpath($form->createView(), array(),
502 '/select
503 [@name="name"]
504 [not(@required)]
505 [
506 ./option[@value=""][.="[trans][/trans]"]
507 /following-sibling::option[@value="&a"][not(@selected)][.="[trans]Choice&A[/trans]"]
508 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
509 ]
510 [count(./option)=3]
511 '
512 );
513 }
514
515 public function testSingleChoiceWithNonRequiredEmptyValue()
516 {
517 $form = $this->factory->createNamed('name', 'choice', '&a', array(
518 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
519 'multiple' => false,
520 'expanded' => false,
521 'required' => false,
522 'empty_value' => 'Select&Anything&Not&Me',
523 ));
524
525 $this->assertWidgetMatchesXpath($form->createView(), array(),
526 '/select
527 [@name="name"]
528 [not(@required)]
529 [
530 ./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Select&Anything&Not&Me[/trans]"]
531 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
532 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
533 ]
534 [count(./option)=3]
535 '
536 );
537 }
538
539 public function testSingleChoiceRequiredWithEmptyValue()
540 {
541 $form = $this->factory->createNamed('name', 'choice', '&a', array(
542 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
543 'required' => true,
544 'multiple' => false,
545 'expanded' => false,
546 'empty_value' => 'Test&Me'
547 ));
548
549 $this->assertWidgetMatchesXpath($form->createView(), array(),
550 '/select
551 [@name="name"]
552 [@required="required"]
553 [
554 ./option[not(@value)][not(@selected)][@disabled][.="[trans]Test&Me[/trans]"]
555 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
556 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
557 ]
558 [count(./option)=3]
559 '
560 );
561 }
562
563 public function testSingleChoiceRequiredWithEmptyValueViaView()
564 {
565 $form = $this->factory->createNamed('name', 'choice', '&a', array(
566 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
567 'required' => true,
568 'multiple' => false,
569 'expanded' => false,
570 ));
571
572 $this->assertWidgetMatchesXpath($form->createView(), array('empty_value' => ''),
573 '/select
574 [@name="name"]
575 [@required="required"]
576 [
577 ./option[not(@value)][not(@selected)][@disabled][.="[trans][/trans]"]
578 /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
579 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
580 ]
581 [count(./option)=3]
582 '
583 );
584 }
585
586 public function testSingleChoiceGrouped()
587 {
588 $form = $this->factory->createNamed('name', 'choice', '&a', array(
589 'choices' => array(
590 'Group&1' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
591 'Group&2' => array('&c' => 'Choice&C'),
592 ),
593 'multiple' => false,
594 'expanded' => false,
595 ));
596
597 $this->assertWidgetMatchesXpath($form->createView(), array(),
598 '/select
599 [@name="name"]
600 [./optgroup[@label="[trans]Group&1[/trans]"]
601 [
602 ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
603 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
604 ]
605 [count(./option)=2]
606 ]
607 [./optgroup[@label="[trans]Group&2[/trans]"]
608 [./option[@value="&c"][not(@selected)][.="[trans]Choice&C[/trans]"]]
609 [count(./option)=1]
610 ]
611 [count(./optgroup)=2]
612 '
613 );
614 }
615
616 public function testMultipleChoice()
617 {
618 $form = $this->factory->createNamed('name', 'choice', array('&a'), array(
619 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
620 'multiple' => true,
621 'expanded' => false,
622 ));
623
624 $this->assertWidgetMatchesXpath($form->createView(), array(),
625 '/select
626 [@name="name[]"]
627 [@multiple="multiple"]
628 [
629 ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
630 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
631 ]
632 [count(./option)=2]
633 '
634 );
635 }
636
637 public function testMultipleChoiceSkipsEmptyValue()
638 {
639 $form = $this->factory->createNamed('name', 'choice', array('&a'), array(
640 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
641 'multiple' => true,
642 'expanded' => false,
643 'empty_value' => 'Test&Me'
644 ));
645
646 $this->assertWidgetMatchesXpath($form->createView(), array(),
647 '/select
648 [@name="name[]"]
649 [@multiple="multiple"]
650 [
651 ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
652 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
653 ]
654 [count(./option)=2]
655 '
656 );
657 }
658
659 public function testMultipleChoiceNonRequired()
660 {
661 $form = $this->factory->createNamed('name', 'choice', array('&a'), array(
662 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
663 'required' => false,
664 'multiple' => true,
665 'expanded' => false,
666 ));
667
668 $this->assertWidgetMatchesXpath($form->createView(), array(),
669 '/select
670 [@name="name[]"]
671 [@multiple="multiple"]
672 [
673 ./option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"]
674 /following-sibling::option[@value="&b"][not(@selected)][.="[trans]Choice&B[/trans]"]
675 ]
676 [count(./option)=2]
677 '
678 );
679 }
680
681 public function testSingleChoiceExpanded()
682 {
683 $form = $this->factory->createNamed('name', 'choice', '&a', array(
684 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
685 'multiple' => false,
686 'expanded' => true,
687 ));
688
689 $this->assertWidgetMatchesXpath($form->createView(), array(),
690 '/div
691 [
692 ./input[@type="radio"][@name="name"][@id="name_0"][@value="&a"][@checked]
693 /following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
694 /following-sibling::input[@type="radio"][@name="name"][@id="name_1"][@value="&b"][not(@checked)]
695 /following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
696 /following-sibling::input[@type="hidden"][@id="name__token"]
697 ]
698 [count(./input)=3]
699 '
700 );
701 }
702
703 public function testSingleChoiceExpandedWithEmptyValue()
704 {
705 $form = $this->factory->createNamed('name', 'choice', '&a', array(
706 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
707 'multiple' => false,
708 'expanded' => true,
709 'empty_value' => 'Test&Me'
710 ));
711
712 $this->assertWidgetMatchesXpath($form->createView(), array(),
713 '/div
714 [
715 ./input[@type="radio"][@name="name"][@id="name_placeholder"][not(@checked)]
716 /following-sibling::label[@for="name_placeholder"][.="[trans]Test&Me[/trans]"]
717 /following-sibling::input[@type="radio"][@name="name"][@id="name_0"][@checked]
718 /following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
719 /following-sibling::input[@type="radio"][@name="name"][@id="name_1"][not(@checked)]
720 /following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
721 /following-sibling::input[@type="hidden"][@id="name__token"]
722 ]
723 [count(./input)=4]
724 '
725 );
726 }
727
728 public function testSingleChoiceExpandedWithBooleanValue()
729 {
730 $form = $this->factory->createNamed('name', 'choice', true, array(
731 'choices' => array('1' => 'Choice&A', '0' => 'Choice&B'),
732 'multiple' => false,
733 'expanded' => true,
734 ));
735
736 $this->assertWidgetMatchesXpath($form->createView(), array(),
737 '/div
738 [
739 ./input[@type="radio"][@name="name"][@id="name_0"][@checked]
740 /following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
741 /following-sibling::input[@type="radio"][@name="name"][@id="name_1"][not(@checked)]
742 /following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
743 /following-sibling::input[@type="hidden"][@id="name__token"]
744 ]
745 [count(./input)=3]
746 '
747 );
748 }
749
750 public function testMultipleChoiceExpanded()
751 {
752 $form = $this->factory->createNamed('name', 'choice', array('&a', '&c'), array(
753 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B', '&c' => 'Choice&C'),
754 'multiple' => true,
755 'expanded' => true,
756 'required' => true,
757 ));
758
759 $this->assertWidgetMatchesXpath($form->createView(), array(),
760 '/div
761 [
762 ./input[@type="checkbox"][@name="name[]"][@id="name_0"][@checked][not(@required)]
763 /following-sibling::label[@for="name_0"][.="[trans]Choice&A[/trans]"]
764 /following-sibling::input[@type="checkbox"][@name="name[]"][@id="name_1"][not(@checked)][not(@required)]
765 /following-sibling::label[@for="name_1"][.="[trans]Choice&B[/trans]"]
766 /following-sibling::input[@type="checkbox"][@name="name[]"][@id="name_2"][@checked][not(@required)]
767 /following-sibling::label[@for="name_2"][.="[trans]Choice&C[/trans]"]
768 /following-sibling::input[@type="hidden"][@id="name__token"]
769 ]
770 [count(./input)=4]
771 '
772 );
773 }
774
775 public function testCountry()
776 {
777 $form = $this->factory->createNamed('name', 'country', 'AT');
778
779 $this->assertWidgetMatchesXpath($form->createView(), array(),
780 '/select
781 [@name="name"]
782 [./option[@value="AT"][@selected="selected"][.="[trans]Austria[/trans]"]]
783 [count(./option)>200]
784 '
785 );
786 }
787
788 public function testCountryWithEmptyValue()
789 {
790 $form = $this->factory->createNamed('name', 'country', 'AT', array(
791 'empty_value' => 'Select&Country',
792 'required' => false,
793 ));
794
795 $this->assertWidgetMatchesXpath($form->createView(), array(),
796 '/select
797 [@name="name"]
798 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Select&Country[/trans]"]]
799 [./option[@value="AT"][@selected="selected"][.="[trans]Austria[/trans]"]]
800 [count(./option)>201]
801 '
802 );
803 }
804
805 public function testDateTime()
806 {
807 $form = $this->factory->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
808 'input' => 'string',
809 'with_seconds' => false,
810 ));
811
812 $this->assertWidgetMatchesXpath($form->createView(), array(),
813 '/div
814 [
815 ./div
816 [@id="name_date"]
817 [
818 ./select
819 [@id="name_date_month"]
820 [./option[@value="2"][@selected="selected"]]
821 /following-sibling::select
822 [@id="name_date_day"]
823 [./option[@value="3"][@selected="selected"]]
824 /following-sibling::select
825 [@id="name_date_year"]
826 [./option[@value="2011"][@selected="selected"]]
827 ]
828 /following-sibling::div
829 [@id="name_time"]
830 [
831 ./select
832 [@id="name_time_hour"]
833 [./option[@value="4"][@selected="selected"]]
834 /following-sibling::select
835 [@id="name_time_minute"]
836 [./option[@value="5"][@selected="selected"]]
837 ]
838 ]
839 [count(.//select)=5]
840 '
841 );
842 }
843
844 public function testDateTimeWithEmptyValueGlobal()
845 {
846 $form = $this->factory->createNamed('name', 'datetime', null, array(
847 'input' => 'string',
848 'empty_value' => 'Change&Me',
849 'required' => false,
850 ));
851
852 $this->assertWidgetMatchesXpath($form->createView(), array(),
853 '/div
854 [
855 ./div
856 [@id="name_date"]
857 [
858 ./select
859 [@id="name_date_month"]
860 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
861 /following-sibling::select
862 [@id="name_date_day"]
863 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
864 /following-sibling::select
865 [@id="name_date_year"]
866 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
867 ]
868 /following-sibling::div
869 [@id="name_time"]
870 [
871 ./select
872 [@id="name_time_hour"]
873 [./option[@value=""][.="[trans]Change&Me[/trans]"]]
874 /following-sibling::select
875 [@id="name_time_minute"]
876 [./option[@value=""][.="[trans]Change&Me[/trans]"]]
877 ]
878 ]
879 [count(.//select)=5]
880 '
881 );
882 }
883
884 public function testDateTimeWithEmptyValueOnTime()
885 {
886 $data = array('year' => '2011', 'month' => '2', 'day' => '3', 'hour' => '', 'minute' => '');
887
888 $form = $this->factory->createNamed('name', 'datetime', $data, array(
889 'input' => 'array',
890 'empty_value' => array('hour' => 'Change&Me', 'minute' => 'Change&Me'),
891 'required' => false,
892 ));
893
894 $this->assertWidgetMatchesXpath($form->createView(), array(),
895 '/div
896 [
897 ./div
898 [@id="name_date"]
899 [
900 ./select
901 [@id="name_date_month"]
902 [./option[@value="2"][@selected="selected"]]
903 /following-sibling::select
904 [@id="name_date_day"]
905 [./option[@value="3"][@selected="selected"]]
906 /following-sibling::select
907 [@id="name_date_year"]
908 [./option[@value="2011"][@selected="selected"]]
909 ]
910 /following-sibling::div
911 [@id="name_time"]
912 [
913 ./select
914 [@id="name_time_hour"]
915 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
916 /following-sibling::select
917 [@id="name_time_minute"]
918 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
919 ]
920 ]
921 [count(.//select)=5]
922 '
923 );
924 }
925
926 public function testDateTimeWithSeconds()
927 {
928 $form = $this->factory->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
929 'input' => 'string',
930 'with_seconds' => true,
931 ));
932
933 $this->assertWidgetMatchesXpath($form->createView(), array(),
934 '/div
935 [
936 ./div
937 [@id="name_date"]
938 [
939 ./select
940 [@id="name_date_month"]
941 [./option[@value="2"][@selected="selected"]]
942 /following-sibling::select
943 [@id="name_date_day"]
944 [./option[@value="3"][@selected="selected"]]
945 /following-sibling::select
946 [@id="name_date_year"]
947 [./option[@value="2011"][@selected="selected"]]
948 ]
949 /following-sibling::div
950 [@id="name_time"]
951 [
952 ./select
953 [@id="name_time_hour"]
954 [./option[@value="4"][@selected="selected"]]
955 /following-sibling::select
956 [@id="name_time_minute"]
957 [./option[@value="5"][@selected="selected"]]
958 /following-sibling::select
959 [@id="name_time_second"]
960 [./option[@value="6"][@selected="selected"]]
961 ]
962 ]
963 [count(.//select)=6]
964 '
965 );
966 }
967
968 public function testDateTimeSingleText()
969 {
970 $form = $this->factory->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
971 'input' => 'string',
972 'date_widget' => 'single_text',
973 'time_widget' => 'single_text',
974 ));
975
976 $this->assertWidgetMatchesXpath($form->createView(), array(),
977 '/div
978 [
979 ./input
980 [@type="date"]
981 [@id="name_date"]
982 [@name="name[date]"]
983 [@value="2011-02-03"]
984 /following-sibling::input
985 [@type="time"]
986 [@id="name_time"]
987 [@name="name[time]"]
988 [@value="04:05"]
989 ]
990 '
991 );
992 }
993
994 public function testDateTimeWithWidgetSingleText()
995 {
996 $form = $this->factory->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
997 'input' => 'string',
998 'widget' => 'single_text',
999 'model_timezone' => 'UTC',
1000 'view_timezone' => 'UTC',
1001 ));
1002
1003 $this->assertWidgetMatchesXpath($form->createView(), array(),
1004 '/input
1005 [@type="datetime"]
1006 [@name="name"]
1007 [@value="2011-02-03T04:05:06Z"]
1008 '
1009 );
1010 }
1011
1012 public function testDateTimeWithWidgetSingleTextIgnoreDateAndTimeWidgets()
1013 {
1014 $form = $this->factory->createNamed('name', 'datetime', '2011-02-03 04:05:06', array(
1015 'input' => 'string',
1016 'date_widget' => 'choice',
1017 'time_widget' => 'choice',
1018 'widget' => 'single_text',
1019 'model_timezone' => 'UTC',
1020 'view_timezone' => 'UTC',
1021 ));
1022
1023 $this->assertWidgetMatchesXpath($form->createView(), array(),
1024 '/input
1025 [@type="datetime"]
1026 [@name="name"]
1027 [@value="2011-02-03T04:05:06Z"]
1028 '
1029 );
1030 }
1031
1032 public function testDateChoice()
1033 {
1034 $form = $this->factory->createNamed('name', 'date', '2011-02-03', array(
1035 'input' => 'string',
1036 'widget' => 'choice',
1037 ));
1038
1039 $this->assertWidgetMatchesXpath($form->createView(), array(),
1040 '/div
1041 [
1042 ./select
1043 [@id="name_month"]
1044 [./option[@value="2"][@selected="selected"]]
1045 /following-sibling::select
1046 [@id="name_day"]
1047 [./option[@value="3"][@selected="selected"]]
1048 /following-sibling::select
1049 [@id="name_year"]
1050 [./option[@value="2011"][@selected="selected"]]
1051 ]
1052 [count(./select)=3]
1053 '
1054 );
1055 }
1056
1057 public function testDateChoiceWithEmptyValueGlobal()
1058 {
1059 $form = $this->factory->createNamed('name', 'date', null, array(
1060 'input' => 'string',
1061 'widget' => 'choice',
1062 'empty_value' => 'Change&Me',
1063 'required' => false,
1064 ));
1065
1066 $this->assertWidgetMatchesXpath($form->createView(), array(),
1067 '/div
1068 [
1069 ./select
1070 [@id="name_month"]
1071 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1072 /following-sibling::select
1073 [@id="name_day"]
1074 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1075 /following-sibling::select
1076 [@id="name_year"]
1077 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1078 ]
1079 [count(./select)=3]
1080 '
1081 );
1082 }
1083
1084 public function testDateChoiceWithEmptyValueOnYear()
1085 {
1086 $form = $this->factory->createNamed('name', 'date', null, array(
1087 'input' => 'string',
1088 'widget' => 'choice',
1089 'required' => false,
1090 'empty_value' => array('year' => 'Change&Me'),
1091 ));
1092
1093 $this->assertWidgetMatchesXpath($form->createView(), array(),
1094 '/div
1095 [
1096 ./select
1097 [@id="name_month"]
1098 [./option[@value="1"]]
1099 /following-sibling::select
1100 [@id="name_day"]
1101 [./option[@value="1"]]
1102 /following-sibling::select
1103 [@id="name_year"]
1104 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1105 ]
1106 [count(./select)=3]
1107 '
1108 );
1109 }
1110
1111 public function testDateText()
1112 {
1113 $form = $this->factory->createNamed('name', 'date', '2011-02-03', array(
1114 'input' => 'string',
1115 'widget' => 'text',
1116 ));
1117
1118 $this->assertWidgetMatchesXpath($form->createView(), array(),
1119 '/div
1120 [
1121 ./input
1122 [@id="name_month"]
1123 [@type="text"]
1124 [@value="2"]
1125 /following-sibling::input
1126 [@id="name_day"]
1127 [@type="text"]
1128 [@value="3"]
1129 /following-sibling::input
1130 [@id="name_year"]
1131 [@type="text"]
1132 [@value="2011"]
1133 ]
1134 [count(./input)=3]
1135 '
1136 );
1137 }
1138
1139 public function testDateSingleText()
1140 {
1141 $form = $this->factory->createNamed('name', 'date', '2011-02-03', array(
1142 'input' => 'string',
1143 'widget' => 'single_text',
1144 ));
1145
1146 $this->assertWidgetMatchesXpath($form->createView(), array(),
1147 '/input
1148 [@type="date"]
1149 [@name="name"]
1150 [@value="2011-02-03"]
1151 '
1152 );
1153 }
1154
1155 public function testDateErrorBubbling()
1156 {
1157 $form = $this->factory->createNamedBuilder('form', 'form')
1158 ->add('date', 'date')
1159 ->getForm();
1160 $form->get('date')->addError(new FormError('[trans]Error![/trans]'));
1161 $view = $form->createView();
1162
1163 $this->assertEmpty($this->renderErrors($view));
1164 $this->assertNotEmpty($this->renderErrors($view['date']));
1165 }
1166
1167 public function testBirthDay()
1168 {
1169 $form = $this->factory->createNamed('name', 'birthday', '2000-02-03', array(
1170 'input' => 'string',
1171 ));
1172
1173 $this->assertWidgetMatchesXpath($form->createView(), array(),
1174 '/div
1175 [
1176 ./select
1177 [@id="name_month"]
1178 [./option[@value="2"][@selected="selected"]]
1179 /following-sibling::select
1180 [@id="name_day"]
1181 [./option[@value="3"][@selected="selected"]]
1182 /following-sibling::select
1183 [@id="name_year"]
1184 [./option[@value="2000"][@selected="selected"]]
1185 ]
1186 [count(./select)=3]
1187 '
1188 );
1189 }
1190
1191 public function testBirthDayWithEmptyValue()
1192 {
1193 $form = $this->factory->createNamed('name', 'birthday', '1950-01-01', array(
1194 'input' => 'string',
1195 'empty_value' => '',
1196 'required' => false,
1197 ));
1198
1199 $this->assertWidgetMatchesXpath($form->createView(), array(),
1200 '/div
1201 [
1202 ./select
1203 [@id="name_month"]
1204 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans][/trans]"]]
1205 [./option[@value="1"][@selected="selected"]]
1206 /following-sibling::select
1207 [@id="name_day"]
1208 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans][/trans]"]]
1209 [./option[@value="1"][@selected="selected"]]
1210 /following-sibling::select
1211 [@id="name_year"]
1212 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans][/trans]"]]
1213 [./option[@value="1950"][@selected="selected"]]
1214 ]
1215 [count(./select)=3]
1216 '
1217 );
1218 }
1219
1220 public function testEmail()
1221 {
1222 $form = $this->factory->createNamed('name', 'email', 'foo&bar');
1223
1224 $this->assertWidgetMatchesXpath($form->createView(), array(),
1225 '/input
1226 [@type="email"]
1227 [@name="name"]
1228 [@value="foo&bar"]
1229 [not(@maxlength)]
1230 '
1231 );
1232 }
1233
1234 public function testEmailWithMaxLength()
1235 {
1236 $form = $this->factory->createNamed('name', 'email', 'foo&bar', array(
1237 'max_length' => 123,
1238 ));
1239
1240 $this->assertWidgetMatchesXpath($form->createView(), array(),
1241 '/input
1242 [@type="email"]
1243 [@name="name"]
1244 [@value="foo&bar"]
1245 [@maxlength="123"]
1246 '
1247 );
1248 }
1249
1250 public function testFile()
1251 {
1252 $form = $this->factory->createNamed('name', 'file');
1253
1254 $this->assertWidgetMatchesXpath($form->createView(), array(),
1255 '/input
1256 [@type="file"]
1257 '
1258 );
1259 }
1260
1261 public function testHidden()
1262 {
1263 $form = $this->factory->createNamed('name', 'hidden', 'foo&bar');
1264
1265 $this->assertWidgetMatchesXpath($form->createView(), array(),
1266 '/input
1267 [@type="hidden"]
1268 [@name="name"]
1269 [@value="foo&bar"]
1270 '
1271 );
1272 }
1273
1274 public function testReadOnly()
1275 {
1276 $form = $this->factory->createNamed('name', 'text', null, array(
1277 'read_only' => true,
1278 ));
1279
1280 $this->assertWidgetMatchesXpath($form->createView(), array(),
1281 '/input
1282 [@type="text"]
1283 [@name="name"]
1284 [@readonly="readonly"]
1285 '
1286 );
1287 }
1288
1289 public function testDisabled()
1290 {
1291 $form = $this->factory->createNamed('name', 'text', null, array(
1292 'disabled' => true,
1293 ));
1294
1295 $this->assertWidgetMatchesXpath($form->createView(), array(),
1296 '/input
1297 [@type="text"]
1298 [@name="name"]
1299 [@disabled="disabled"]
1300 '
1301 );
1302 }
1303
1304 public function testInteger()
1305 {
1306 $form = $this->factory->createNamed('name', 'integer', 123);
1307
1308 $this->assertWidgetMatchesXpath($form->createView(), array(),
1309 '/input
1310 [@type="number"]
1311 [@name="name"]
1312 [@value="123"]
1313 '
1314 );
1315 }
1316
1317 public function testLanguage()
1318 {
1319 $form = $this->factory->createNamed('name', 'language', 'de');
1320
1321 $this->assertWidgetMatchesXpath($form->createView(), array(),
1322 '/select
1323 [@name="name"]
1324 [./option[@value="de"][@selected="selected"][.="[trans]German[/trans]"]]
1325 [count(./option)>200]
1326 '
1327 );
1328 }
1329
1330 public function testLocale()
1331 {
1332 $form = $this->factory->createNamed('name', 'locale', 'de_AT');
1333
1334 $this->assertWidgetMatchesXpath($form->createView(), array(),
1335 '/select
1336 [@name="name"]
1337 [./option[@value="de_AT"][@selected="selected"][.="[trans]German (Austria)[/trans]"]]
1338 [count(./option)>200]
1339 '
1340 );
1341 }
1342
1343 public function testMoney()
1344 {
1345 $form = $this->factory->createNamed('name', 'money', 1234.56, array(
1346 'currency' => 'EUR',
1347 ));
1348
1349 $this->assertWidgetMatchesXpath($form->createView(), array(),
1350 '/input
1351 [@type="text"]
1352 [@name="name"]
1353 [@value="1234.56"]
1354 [contains(.., "€")]
1355 '
1356 );
1357 }
1358
1359 public function testNumber()
1360 {
1361 $form = $this->factory->createNamed('name', 'number', 1234.56);
1362
1363 $this->assertWidgetMatchesXpath($form->createView(), array(),
1364 '/input
1365 [@type="text"]
1366 [@name="name"]
1367 [@value="1234.56"]
1368 '
1369 );
1370 }
1371
1372 public function testPassword()
1373 {
1374 $form = $this->factory->createNamed('name', 'password', 'foo&bar');
1375
1376 $this->assertWidgetMatchesXpath($form->createView(), array(),
1377 '/input
1378 [@type="password"]
1379 [@name="name"]
1380 '
1381 );
1382 }
1383
1384 public function testPasswordSubmittedWithNotAlwaysEmpty()
1385 {
1386 $form = $this->factory->createNamed('name', 'password', null, array(
1387 'always_empty' => false,
1388 ));
1389 $form->submit('foo&bar');
1390
1391 $this->assertWidgetMatchesXpath($form->createView(), array(),
1392 '/input
1393 [@type="password"]
1394 [@name="name"]
1395 [@value="foo&bar"]
1396 '
1397 );
1398 }
1399
1400 public function testPasswordWithMaxLength()
1401 {
1402 $form = $this->factory->createNamed('name', 'password', 'foo&bar', array(
1403 'max_length' => 123,
1404 ));
1405
1406 $this->assertWidgetMatchesXpath($form->createView(), array(),
1407 '/input
1408 [@type="password"]
1409 [@name="name"]
1410 [@maxlength="123"]
1411 '
1412 );
1413 }
1414
1415 public function testPercent()
1416 {
1417 $form = $this->factory->createNamed('name', 'percent', 0.1);
1418
1419 $this->assertWidgetMatchesXpath($form->createView(), array(),
1420 '/input
1421 [@type="text"]
1422 [@name="name"]
1423 [@value="10"]
1424 [contains(.., "%")]
1425 '
1426 );
1427 }
1428
1429 public function testCheckedRadio()
1430 {
1431 $form = $this->factory->createNamed('name', 'radio', true);
1432
1433 $this->assertWidgetMatchesXpath($form->createView(), array(),
1434 '/input
1435 [@type="radio"]
1436 [@name="name"]
1437 [@checked="checked"]
1438 [@value="1"]
1439 '
1440 );
1441 }
1442
1443 public function testUncheckedRadio()
1444 {
1445 $form = $this->factory->createNamed('name', 'radio', false);
1446
1447 $this->assertWidgetMatchesXpath($form->createView(), array(),
1448 '/input
1449 [@type="radio"]
1450 [@name="name"]
1451 [not(@checked)]
1452 '
1453 );
1454 }
1455
1456 public function testRadioWithValue()
1457 {
1458 $form = $this->factory->createNamed('name', 'radio', false, array(
1459 'value' => 'foo&bar',
1460 ));
1461
1462 $this->assertWidgetMatchesXpath($form->createView(), array(),
1463 '/input
1464 [@type="radio"]
1465 [@name="name"]
1466 [@value="foo&bar"]
1467 '
1468 );
1469 }
1470
1471 public function testTextarea()
1472 {
1473 $form = $this->factory->createNamed('name', 'textarea', 'foo&bar', array(
1474 'pattern' => 'foo',
1475 ));
1476
1477 $this->assertWidgetMatchesXpath($form->createView(), array(),
1478 '/textarea
1479 [@name="name"]
1480 [not(@pattern)]
1481 [.="foo&bar"]
1482 '
1483 );
1484 }
1485
1486 public function testText()
1487 {
1488 $form = $this->factory->createNamed('name', 'text', 'foo&bar');
1489
1490 $this->assertWidgetMatchesXpath($form->createView(), array(),
1491 '/input
1492 [@type="text"]
1493 [@name="name"]
1494 [@value="foo&bar"]
1495 [not(@maxlength)]
1496 '
1497 );
1498 }
1499
1500 public function testTextWithMaxLength()
1501 {
1502 $form = $this->factory->createNamed('name', 'text', 'foo&bar', array(
1503 'max_length' => 123,
1504 ));
1505
1506 $this->assertWidgetMatchesXpath($form->createView(), array(),
1507 '/input
1508 [@type="text"]
1509 [@name="name"]
1510 [@value="foo&bar"]
1511 [@maxlength="123"]
1512 '
1513 );
1514 }
1515
1516 public function testSearch()
1517 {
1518 $form = $this->factory->createNamed('name', 'search', 'foo&bar');
1519
1520 $this->assertWidgetMatchesXpath($form->createView(), array(),
1521 '/input
1522 [@type="search"]
1523 [@name="name"]
1524 [@value="foo&bar"]
1525 [not(@maxlength)]
1526 '
1527 );
1528 }
1529
1530 public function testTime()
1531 {
1532 $form = $this->factory->createNamed('name', 'time', '04:05:06', array(
1533 'input' => 'string',
1534 'with_seconds' => false,
1535 ));
1536
1537 $this->assertWidgetMatchesXpath($form->createView(), array(),
1538 '/div
1539 [
1540 ./select
1541 [@id="name_hour"]
1542 [not(@size)]
1543 [./option[@value="4"][@selected="selected"]]
1544 /following-sibling::select
1545 [@id="name_minute"]
1546 [not(@size)]
1547 [./option[@value="5"][@selected="selected"]]
1548 ]
1549 [count(./select)=2]
1550 '
1551 );
1552 }
1553
1554 public function testTimeWithSeconds()
1555 {
1556 $form = $this->factory->createNamed('name', 'time', '04:05:06', array(
1557 'input' => 'string',
1558 'with_seconds' => true,
1559 ));
1560
1561 $this->assertWidgetMatchesXpath($form->createView(), array(),
1562 '/div
1563 [
1564 ./select
1565 [@id="name_hour"]
1566 [not(@size)]
1567 [./option[@value="4"][@selected="selected"]]
1568 [count(./option)>23]
1569 /following-sibling::select
1570 [@id="name_minute"]
1571 [not(@size)]
1572 [./option[@value="5"][@selected="selected"]]
1573 [count(./option)>59]
1574 /following-sibling::select
1575 [@id="name_second"]
1576 [not(@size)]
1577 [./option[@value="6"][@selected="selected"]]
1578 [count(./option)>59]
1579 ]
1580 [count(./select)=3]
1581 '
1582 );
1583 }
1584
1585 public function testTimeText()
1586 {
1587 $form = $this->factory->createNamed('name', 'time', '04:05:06', array(
1588 'input' => 'string',
1589 'widget' => 'text',
1590 ));
1591
1592 $this->assertWidgetMatchesXpath($form->createView(), array(),
1593 '/div
1594 [
1595 ./input
1596 [@type="text"]
1597 [@id="name_hour"]
1598 [@name="name[hour]"]
1599 [@value="04"]
1600 [@size="1"]
1601 [@required="required"]
1602 /following-sibling::input
1603 [@type="text"]
1604 [@id="name_minute"]
1605 [@name="name[minute]"]
1606 [@value="05"]
1607 [@size="1"]
1608 [@required="required"]
1609 ]
1610 [count(./input)=2]
1611 '
1612 );
1613 }
1614
1615 public function testTimeSingleText()
1616 {
1617 $form = $this->factory->createNamed('name', 'time', '04:05:06', array(
1618 'input' => 'string',
1619 'widget' => 'single_text',
1620 ));
1621
1622 $this->assertWidgetMatchesXpath($form->createView(), array(),
1623 '/input
1624 [@type="time"]
1625 [@name="name"]
1626 [@value="04:05"]
1627 [not(@size)]
1628 '
1629 );
1630 }
1631
1632 public function testTimeWithEmptyValueGlobal()
1633 {
1634 $form = $this->factory->createNamed('name', 'time', null, array(
1635 'input' => 'string',
1636 'empty_value' => 'Change&Me',
1637 'required' => false,
1638 ));
1639
1640 $this->assertWidgetMatchesXpath($form->createView(), array(),
1641 '/div
1642 [
1643 ./select
1644 [@id="name_hour"]
1645 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1646 [count(./option)>24]
1647 /following-sibling::select
1648 [@id="name_minute"]
1649 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1650 [count(./option)>60]
1651 ]
1652 [count(./select)=2]
1653 '
1654 );
1655 }
1656
1657 public function testTimeWithEmptyValueOnYear()
1658 {
1659 $form = $this->factory->createNamed('name', 'time', null, array(
1660 'input' => 'string',
1661 'required' => false,
1662 'empty_value' => array('hour' => 'Change&Me'),
1663 ));
1664
1665 $this->assertWidgetMatchesXpath($form->createView(), array(),
1666 '/div
1667 [
1668 ./select
1669 [@id="name_hour"]
1670 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Change&Me[/trans]"]]
1671 [count(./option)>24]
1672 /following-sibling::select
1673 [@id="name_minute"]
1674 [./option[@value="1"]]
1675 [count(./option)>59]
1676 ]
1677 [count(./select)=2]
1678 '
1679 );
1680 }
1681
1682 public function testTimeErrorBubbling()
1683 {
1684 $form = $this->factory->createNamedBuilder('form', 'form')
1685 ->add('time', 'time')
1686 ->getForm();
1687 $form->get('time')->addError(new FormError('[trans]Error![/trans]'));
1688 $view = $form->createView();
1689
1690 $this->assertEmpty($this->renderErrors($view));
1691 $this->assertNotEmpty($this->renderErrors($view['time']));
1692 }
1693
1694 public function testTimezone()
1695 {
1696 $form = $this->factory->createNamed('name', 'timezone', 'Europe/Vienna');
1697
1698 $this->assertWidgetMatchesXpath($form->createView(), array(),
1699 '/select
1700 [@name="name"]
1701 [@required="required"]
1702 [./optgroup
1703 [@label="[trans]Europe[/trans]"]
1704 [./option[@value="Europe/Vienna"][@selected="selected"][.="[trans]Vienna[/trans]"]]
1705 ]
1706 [count(./optgroup)>10]
1707 [count(.//option)>200]
1708 '
1709 );
1710 }
1711
1712 public function testTimezoneWithEmptyValue()
1713 {
1714 $form = $this->factory->createNamed('name', 'timezone', null, array(
1715 'empty_value' => 'Select&Timezone',
1716 'required' => false,
1717 ));
1718
1719 $this->assertWidgetMatchesXpath($form->createView(), array(),
1720 '/select
1721 [./option[@value=""][not(@selected)][not(@disabled)][.="[trans]Select&Timezone[/trans]"]]
1722 [count(./optgroup)>10]
1723 [count(.//option)>201]
1724 '
1725 );
1726 }
1727
1728 public function testUrl()
1729 {
1730 $url = 'http://www.google.com?foo1=bar1&foo2=bar2';
1731 $form = $this->factory->createNamed('name', 'url', $url);
1732
1733 $this->assertWidgetMatchesXpath($form->createView(), array(),
1734 '/input
1735 [@type="url"]
1736 [@name="name"]
1737 [@value="http://www.google.com?foo1=bar1&foo2=bar2"]
1738 '
1739 );
1740 }
1741
1742 public function testCollectionPrototype()
1743 {
1744 $form = $this->factory->createNamedBuilder('name', 'form', array('items' => array('one', 'two', 'three')))
1745 ->add('items', 'collection', array('allow_add' => true))
1746 ->getForm()
1747 ->createView();
1748
1749 $html = $this->renderWidget($form);
1750
1751 $this->assertMatchesXpath($html,
1752 '//div[@id="name_items"][@data-prototype]
1753 |
1754 //table[@id="name_items"][@data-prototype]'
1755 );
1756 }
1757
1758 public function testEmptyRootFormName()
1759 {
1760 $form = $this->factory->createNamedBuilder('', 'form')
1761 ->add('child', 'text')
1762 ->getForm();
1763
1764 $this->assertMatchesXpath($this->renderWidget($form->createView()),
1765 '//input[@type="hidden"][@id="_token"][@name="_token"]
1766 |
1767 //input[@type="text"][@id="child"][@name="child"]'
1768 , 2);
1769 }
1770
1771 public function testButton()
1772 {
1773 $form = $this->factory->createNamed('name', 'button');
1774
1775 $this->assertWidgetMatchesXpath($form->createView(), array(),
1776 '/button[@type="button"][@name="name"][.="[trans]Name[/trans]"]'
1777 );
1778 }
1779
1780 public function testButtonLabelIsEmpty()
1781 {
1782 $form = $this->factory->createNamed('name', 'button');
1783
1784 $this->assertSame('', $this->renderLabel($form->createView()));
1785 }
1786
1787 public function testSubmit()
1788 {
1789 $form = $this->factory->createNamed('name', 'submit');
1790
1791 $this->assertWidgetMatchesXpath($form->createView(), array(),
1792 '/button[@type="submit"][@name="name"]'
1793 );
1794 }
1795
1796 public function testReset()
1797 {
1798 $form = $this->factory->createNamed('name', 'reset');
1799
1800 $this->assertWidgetMatchesXpath($form->createView(), array(),
1801 '/button[@type="reset"][@name="name"]'
1802 );
1803 }
1804
1805 public function testStartTag()
1806 {
1807 $form = $this->factory->create('form', null, array(
1808 'method' => 'get',
1809 'action' => 'http://example.com/directory'
1810 ));
1811
1812 $html = $this->renderStart($form->createView());
1813
1814 $this->assertSame('<form method="get" action="http://example.com/directory">', $html);
1815 }
1816
1817 public function testStartTagForPutRequest()
1818 {
1819 $form = $this->factory->create('form', null, array(
1820 'method' => 'put',
1821 'action' => 'http://example.com/directory'
1822 ));
1823
1824 $html = $this->renderStart($form->createView());
1825
1826 $this->assertMatchesXpath($html . '</form>',
1827 '/form
1828 [./input[@type="hidden"][@name="_method"][@value="PUT"]]
1829 [@method="post"]
1830 [@action="http://example.com/directory"]'
1831 );
1832 }
1833
1834 public function testStartTagWithOverriddenVars()
1835 {
1836 $form = $this->factory->create('form', null, array(
1837 'method' => 'put',
1838 'action' => 'http://example.com/directory',
1839 ));
1840
1841 $html = $this->renderStart($form->createView(), array(
1842 'method' => 'post',
1843 'action' => 'http://foo.com/directory'
1844 ));
1845
1846 $this->assertSame('<form method="post" action="http://foo.com/directory">', $html);
1847 }
1848
1849 public function testStartTagForMultipartForm()
1850 {
1851 $form = $this->factory->createBuilder('form', null, array(
1852 'method' => 'get',
1853 'action' => 'http://example.com/directory'
1854 ))
1855 ->add('file', 'file')
1856 ->getForm();
1857
1858 $html = $this->renderStart($form->createView());
1859
1860 $this->assertSame('<form method="get" action="http://example.com/directory" enctype="multipart/form-data">', $html);
1861 }
1862
1863 public function testStartTagWithExtraAttributes()
1864 {
1865 $form = $this->factory->create('form', null, array(
1866 'method' => 'get',
1867 'action' => 'http://example.com/directory'
1868 ));
1869
1870 $html = $this->renderStart($form->createView(), array(
1871 'attr' => array('class' => 'foobar'),
1872 ));
1873
1874 $this->assertSame('<form method="get" action="http://example.com/directory" class="foobar">', $html);
1875 }
1876 }