AbstractLayoutTest.php 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Tests\Component\Form;
  11. use Symfony\Component\Form\FormError;
  12. use Symfony\Component\Form\FormView;
  13. use Symfony\Component\Form\FormFactory;
  14. use Symfony\Component\Form\Extension\Core\CoreExtension;
  15. use Symfony\Component\Form\Extension\Csrf\CsrfExtension;
  16. use Symfony\Component\EventDispatcher\EventDispatcher;
  17. abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
  18. {
  19. protected $csrfProvider;
  20. protected $factory;
  21. protected function setUp()
  22. {
  23. \Locale::setDefault('en');
  24. $this->csrfProvider = $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface');
  25. $this->factory = new FormFactory(array(
  26. new CoreExtension(),
  27. new CsrfExtension($this->csrfProvider),
  28. ));
  29. }
  30. protected function tearDown()
  31. {
  32. $this->csrfProvider = null;
  33. $this->factory = null;
  34. }
  35. protected function assertXpathNodeValue(\DomElement $element, $expression, $nodeValue)
  36. {
  37. $xpath = new \DOMXPath($element->ownerDocument);
  38. $nodeList = $xpath->evaluate($expression);
  39. $this->assertEquals(1, $nodeList->length);
  40. $this->assertEquals($nodeValue, $nodeList->item(0)->nodeValue);
  41. }
  42. protected function assertMatchesXpath($html, $expression, $count = 1)
  43. {
  44. $dom = new \DomDocument('UTF-8');
  45. try {
  46. // Wrap in <root> node so we can load HTML with multiple tags at
  47. // the top level
  48. $dom->loadXml('<root>'.$html.'</root>');
  49. } catch (\Exception $e) {
  50. return $this->fail(sprintf(
  51. "Failed loading HTML:\n\n%s\n\nError: %s",
  52. $html,
  53. $e->getMessage()
  54. ));
  55. }
  56. $xpath = new \DOMXPath($dom);
  57. $nodeList = $xpath->evaluate('/root'.$expression);
  58. if ($nodeList->length != $count) {
  59. $dom->formatOutput = true;
  60. $this->fail(sprintf(
  61. "Failed asserting that \n\n%s\n\nmatches exactly %s. Matches %s in \n\n%s",
  62. $expression,
  63. $count == 1 ? 'once' : $count . ' times',
  64. $nodeList->length == 1 ? 'once' : $nodeList->length . ' times',
  65. // strip away <root> and </root>
  66. substr($dom->saveHTML(), 6, -8)
  67. ));
  68. }
  69. }
  70. protected function assertWidgetMatchesXpath(FormView $view, array $vars, $xpath)
  71. {
  72. // include ampersands everywhere to validate escaping
  73. $html = $this->renderWidget($view, array_merge(array(
  74. 'id' => 'my&id',
  75. 'attr' => array('class' => 'my&class'),
  76. ), $vars));
  77. $xpath = trim($xpath).'
  78. [@id="my&id"]
  79. [@class="my&class"]';
  80. $this->assertMatchesXpath($html, $xpath);
  81. }
  82. abstract protected function renderEnctype(FormView $view);
  83. abstract protected function renderLabel(FormView $view, $label = null, array $vars = array());
  84. abstract protected function renderErrors(FormView $view);
  85. abstract protected function renderWidget(FormView $view, array $vars = array());
  86. abstract protected function renderRow(FormView $view, array $vars = array());
  87. abstract protected function renderRest(FormView $view, array $vars = array());
  88. public function testEnctype()
  89. {
  90. $form = $this->factory->createNamedBuilder('form', 'na&me', null, array(
  91. 'property_path' => 'name',
  92. ))
  93. ->add('file', 'file')
  94. ->getForm();
  95. $this->assertEquals('enctype="multipart/form-data"', $this->renderEnctype($form->createView()));
  96. }
  97. public function testNoEnctype()
  98. {
  99. $form = $this->factory->createNamedBuilder('form', 'na&me', null, array(
  100. 'property_path' => 'name',
  101. ))
  102. ->add('text', 'text')
  103. ->getForm();
  104. $this->assertEquals('', $this->renderEnctype($form->createView()));
  105. }
  106. public function testLabel()
  107. {
  108. $form = $this->factory->createNamed('text', 'na&me', null, array(
  109. 'property_path' => 'name',
  110. ));
  111. $view = $form->createView();
  112. $this->renderWidget($view, array('label' => 'foo'));
  113. $html = $this->renderLabel($view);
  114. $this->assertMatchesXpath($html,
  115. '/label
  116. [@for="na&me"]
  117. [.="[trans]Na&me[/trans]"]
  118. '
  119. );
  120. }
  121. public function testLabelWithCustomTextPassedAsOption()
  122. {
  123. $form = $this->factory->createNamed('text', 'na&me', null, array(
  124. 'property_path' => 'name',
  125. 'label' => 'Custom label',
  126. ));
  127. $html = $this->renderLabel($form->createView());
  128. $this->assertMatchesXpath($html,
  129. '/label
  130. [@for="na&me"]
  131. [.="[trans]Custom label[/trans]"]
  132. '
  133. );
  134. }
  135. public function testLabelWithCustomTextPassedDirectly()
  136. {
  137. $form = $this->factory->createNamed('text', 'na&me', null, array(
  138. 'property_path' => 'name',
  139. ));
  140. $html = $this->renderLabel($form->createView(), 'Custom label');
  141. $this->assertMatchesXpath($html,
  142. '/label
  143. [@for="na&me"]
  144. [.="[trans]Custom label[/trans]"]
  145. '
  146. );
  147. }
  148. public function testLabelWithCustomTextPassedAsOptionAndDirectly()
  149. {
  150. $form = $this->factory->createNamed('text', 'na&me', null, array(
  151. 'property_path' => 'name',
  152. 'label' => 'Custom label',
  153. ));
  154. $html = $this->renderLabel($form->createView(), 'Overridden label');
  155. $this->assertMatchesXpath($html,
  156. '/label
  157. [@for="na&me"]
  158. [.="[trans]Overridden label[/trans]"]
  159. '
  160. );
  161. }
  162. public function testLabelWithCustomOptionsPassedDirectly()
  163. {
  164. $form = $this->factory->createNamed('text', 'na&me', null, array(
  165. 'property_path' => 'name',
  166. ));
  167. $html = $this->renderLabel($form->createView(), null, array(
  168. 'attr' => array(
  169. 'class' => 'my&class'
  170. ),
  171. ));
  172. $this->assertMatchesXpath($html,
  173. '/label
  174. [@for="na&me"]
  175. [@class="my&class"]
  176. '
  177. );
  178. }
  179. public function testLabelWithCustomTextAndCustomOptionsPassedDirectly()
  180. {
  181. $form = $this->factory->createNamed('text', 'na&me', null, array(
  182. 'property_path' => 'name',
  183. ));
  184. $html = $this->renderLabel($form->createView(), 'Custom label', array(
  185. 'attr' => array(
  186. 'class' => 'my&class'
  187. ),
  188. ));
  189. $this->assertMatchesXpath($html,
  190. '/label
  191. [@for="na&me"]
  192. [@class="my&class"]
  193. [.="[trans]Custom label[/trans]"]
  194. '
  195. );
  196. }
  197. public function testErrors()
  198. {
  199. $form = $this->factory->createNamed('text', 'na&me', null, array(
  200. 'property_path' => 'name',
  201. ));
  202. $form->addError(new FormError('Error 1'));
  203. $form->addError(new FormError('Error 2'));
  204. $view = $form->createView();
  205. $html = $this->renderErrors($view);
  206. $this->assertMatchesXpath($html,
  207. '/ul
  208. [
  209. ./li[.="[trans]Error 1[/trans]"]
  210. /following-sibling::li[.="[trans]Error 2[/trans]"]
  211. ]
  212. [count(./li)=2]
  213. '
  214. );
  215. }
  216. public function testWidgetById()
  217. {
  218. $form = $this->factory->createNamed('text', 'text_id');
  219. $html = $this->renderWidget($form->createView());
  220. $this->assertMatchesXpath($html,
  221. '/div
  222. [
  223. ./input
  224. [@type="text"]
  225. [@id="text_id"]
  226. ]
  227. [@id="container"]
  228. '
  229. );
  230. }
  231. public function testCheckedCheckbox()
  232. {
  233. $form = $this->factory->createNamed('checkbox', 'na&me', true, array(
  234. 'property_path' => 'name',
  235. ));
  236. $this->assertWidgetMatchesXpath($form->createView(), array(),
  237. '/input
  238. [@type="checkbox"]
  239. [@name="na&me"]
  240. [@checked="checked"]
  241. [@value="1"]
  242. '
  243. );
  244. }
  245. public function testCheckedCheckboxWithValue()
  246. {
  247. $form = $this->factory->createNamed('checkbox', 'na&me', true, array(
  248. 'property_path' => 'name',
  249. 'value' => 'foo&bar',
  250. ));
  251. $this->assertWidgetMatchesXpath($form->createView(), array(),
  252. '/input
  253. [@type="checkbox"]
  254. [@name="na&me"]
  255. [@checked="checked"]
  256. [@value="foo&bar"]
  257. '
  258. );
  259. }
  260. public function testUncheckedCheckbox()
  261. {
  262. $form = $this->factory->createNamed('checkbox', 'na&me', false, array(
  263. 'property_path' => 'name',
  264. ));
  265. $this->assertWidgetMatchesXpath($form->createView(), array(),
  266. '/input
  267. [@type="checkbox"]
  268. [@name="na&me"]
  269. [not(@checked)]
  270. '
  271. );
  272. }
  273. public function testSingleChoice()
  274. {
  275. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  276. 'property_path' => 'name',
  277. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  278. 'multiple' => false,
  279. 'expanded' => false,
  280. ));
  281. $this->assertWidgetMatchesXpath($form->createView(), array(),
  282. '/select
  283. [@name="na&me"]
  284. [@required="required"]
  285. [
  286. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  287. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  288. ]
  289. [count(./option)=2]
  290. '
  291. );
  292. }
  293. public function testSingleChoiceWithPreferred()
  294. {
  295. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  296. 'property_path' => 'name',
  297. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  298. 'preferred_choices' => array('&b'),
  299. 'multiple' => false,
  300. 'expanded' => false,
  301. ));
  302. $this->assertWidgetMatchesXpath($form->createView(), array('separator' => '-- sep --'),
  303. '/select
  304. [@name="na&me"]
  305. [@required="required"]
  306. [
  307. ./option[@value="&b"][not(@selected)][.="Choice&B"]
  308. /following-sibling::option[@disabled="disabled"][not(@selected)][.="-- sep --"]
  309. /following-sibling::option[@value="&a"][@selected="selected"][.="Choice&A"]
  310. ]
  311. [count(./option)=3]
  312. '
  313. );
  314. }
  315. public function testSingleChoiceNonRequired()
  316. {
  317. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  318. 'property_path' => 'name',
  319. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  320. 'required' => false,
  321. 'multiple' => false,
  322. 'expanded' => false,
  323. ));
  324. $this->assertWidgetMatchesXpath($form->createView(), array(),
  325. '/select
  326. [@name="na&me"]
  327. [not(@required)]
  328. [
  329. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  330. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  331. ]
  332. [count(./option)=2]
  333. '
  334. );
  335. }
  336. public function testSingleChoiceNonRequiredNoneSelected()
  337. {
  338. $form = $this->factory->createNamed('choice', 'na&me', null, array(
  339. 'property_path' => 'name',
  340. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  341. 'required' => false,
  342. 'multiple' => false,
  343. 'expanded' => false,
  344. ));
  345. $this->assertWidgetMatchesXpath($form->createView(), array(),
  346. '/select
  347. [@name="na&me"]
  348. [not(@required)]
  349. [
  350. ./option[@value="&a"][not(@selected)][.="Choice&A"]
  351. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  352. ]
  353. [count(./option)=2]
  354. '
  355. );
  356. }
  357. public function testSingleChoiceWithNonRequiredEmptyValue()
  358. {
  359. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  360. 'property_path' => 'name',
  361. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  362. 'multiple' => false,
  363. 'expanded' => false,
  364. 'required' => false,
  365. 'empty_value' => 'Select&Anything&Not&Me',
  366. ));
  367. $this->assertWidgetMatchesXpath($form->createView(), array(),
  368. '/select
  369. [@name="na&me"]
  370. [not(@required)]
  371. [
  372. ./option[@value=""][not(@selected)][.="[trans]Select&Anything&Not&Me[/trans]"]
  373. /following-sibling::option[@value="&a"][@selected="selected"][.="Choice&A"]
  374. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  375. ]
  376. [count(./option)=3]
  377. '
  378. );
  379. }
  380. public function testSingleChoiceRequiredWithEmptyValue()
  381. {
  382. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  383. 'property_path' => 'name',
  384. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  385. 'required' => true,
  386. 'multiple' => false,
  387. 'expanded' => false,
  388. 'empty_value' => 'Test&Me'
  389. ));
  390. $this->assertWidgetMatchesXpath($form->createView(), array(),
  391. '/select
  392. [@name="na&me"]
  393. [@required="required"]
  394. [
  395. ./option[@value=""][.="[trans]Test&Me[/trans]"]
  396. /following-sibling::option[@value="&a"][@selected="selected"][.="Choice&A"]
  397. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  398. ]
  399. [count(./option)=3]
  400. '
  401. );
  402. }
  403. public function testSingleChoiceRequiredWithEmptyValueViaView()
  404. {
  405. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  406. 'property_path' => 'name',
  407. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  408. 'required' => true,
  409. 'multiple' => false,
  410. 'expanded' => false,
  411. ));
  412. $this->assertWidgetMatchesXpath($form->createView(), array('empty_value' => ''),
  413. '/select
  414. [@name="na&me"]
  415. [@required="required"]
  416. [
  417. ./option[@value=""][.="[trans][/trans]"]
  418. /following-sibling::option[@value="&a"][@selected="selected"][.="Choice&A"]
  419. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  420. ]
  421. [count(./option)=3]
  422. '
  423. );
  424. }
  425. public function testSingleChoiceGrouped()
  426. {
  427. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  428. 'property_path' => 'name',
  429. 'choices' => array(
  430. 'Group&1' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  431. 'Group&2' => array('&c' => 'Choice&C'),
  432. ),
  433. 'multiple' => false,
  434. 'expanded' => false,
  435. ));
  436. $this->assertWidgetMatchesXpath($form->createView(), array(),
  437. '/select
  438. [@name="na&me"]
  439. [./optgroup[@label="Group&1"]
  440. [
  441. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  442. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  443. ]
  444. [count(./option)=2]
  445. ]
  446. [./optgroup[@label="Group&2"]
  447. [./option[@value="&c"][not(@selected)][.="Choice&C"]]
  448. [count(./option)=1]
  449. ]
  450. [count(./optgroup)=2]
  451. '
  452. );
  453. }
  454. public function testMultipleChoice()
  455. {
  456. $form = $this->factory->createNamed('choice', 'na&me', array('&a'), array(
  457. 'property_path' => 'name',
  458. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  459. 'multiple' => true,
  460. 'expanded' => false,
  461. ));
  462. $this->assertWidgetMatchesXpath($form->createView(), array(),
  463. '/select
  464. [@name="na&me[]"]
  465. [@multiple="multiple"]
  466. [
  467. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  468. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  469. ]
  470. [count(./option)=2]
  471. '
  472. );
  473. }
  474. public function testMultipleChoiceSkipEmptyValue()
  475. {
  476. $form = $this->factory->createNamed('choice', 'na&me', array('&a'), array(
  477. 'property_path' => 'name',
  478. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  479. 'multiple' => true,
  480. 'expanded' => false,
  481. 'empty_value' => 'Test&Me'
  482. ));
  483. $this->assertWidgetMatchesXpath($form->createView(), array(),
  484. '/select
  485. [@name="na&me[]"]
  486. [@multiple="multiple"]
  487. [
  488. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  489. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  490. ]
  491. [count(./option)=2]
  492. '
  493. );
  494. }
  495. public function testMultipleChoiceNonRequired()
  496. {
  497. $form = $this->factory->createNamed('choice', 'na&me', array('&a'), array(
  498. 'property_path' => 'name',
  499. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  500. 'required' => false,
  501. 'multiple' => true,
  502. 'expanded' => false,
  503. ));
  504. $this->assertWidgetMatchesXpath($form->createView(), array(),
  505. '/select
  506. [@name="na&me[]"]
  507. [@multiple="multiple"]
  508. [
  509. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  510. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  511. ]
  512. [count(./option)=2]
  513. '
  514. );
  515. }
  516. public function testSingleChoiceExpanded()
  517. {
  518. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  519. 'property_path' => 'name',
  520. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  521. 'multiple' => false,
  522. 'expanded' => true,
  523. ));
  524. $this->assertWidgetMatchesXpath($form->createView(), array(),
  525. '/div
  526. [
  527. ./input[@type="radio"][@name="na&me"][@id="na&me_&a"][@checked]
  528. /following-sibling::label[@for="na&me_&a"][.="[trans]Choice&A[/trans]"]
  529. /following-sibling::input[@type="radio"][@name="na&me"][@id="na&me_&b"][not(@checked)]
  530. /following-sibling::label[@for="na&me_&b"][.="[trans]Choice&B[/trans]"]
  531. ]
  532. [count(./input)=2]
  533. '
  534. );
  535. }
  536. public function testSingleChoiceExpandedSkipEmptyValue()
  537. {
  538. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  539. 'property_path' => 'name',
  540. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  541. 'multiple' => false,
  542. 'expanded' => true,
  543. 'empty_value' => 'Test&Me'
  544. ));
  545. $this->assertWidgetMatchesXpath($form->createView(), array(),
  546. '/div
  547. [
  548. ./input[@type="radio"][@name="na&me"][@id="na&me_&a"][@checked]
  549. /following-sibling::label[@for="na&me_&a"][.="[trans]Choice&A[/trans]"]
  550. /following-sibling::input[@type="radio"][@name="na&me"][@id="na&me_&b"][not(@checked)]
  551. /following-sibling::label[@for="na&me_&b"][.="[trans]Choice&B[/trans]"]
  552. ]
  553. [count(./input)=2]
  554. '
  555. );
  556. }
  557. public function testSingleChoiceExpandedWithBooleanValue()
  558. {
  559. $form = $this->factory->createNamed('choice', 'na&me', true, array(
  560. 'property_path' => 'name',
  561. 'choices' => array('1' => 'Choice&A', '0' => 'Choice&B'),
  562. 'multiple' => false,
  563. 'expanded' => true,
  564. ));
  565. $this->assertWidgetMatchesXpath($form->createView(), array(),
  566. '/div
  567. [
  568. ./input[@type="radio"][@name="na&me"][@id="na&me_1"][@checked]
  569. /following-sibling::label[@for="na&me_1"][.="[trans]Choice&A[/trans]"]
  570. /following-sibling::input[@type="radio"][@name="na&me"][@id="na&me_0"][not(@checked)]
  571. /following-sibling::label[@for="na&me_0"][.="[trans]Choice&B[/trans]"]
  572. ]
  573. [count(./input)=2]
  574. '
  575. );
  576. }
  577. public function testMultipleChoiceExpanded()
  578. {
  579. $form = $this->factory->createNamed('choice', 'na&me', array('&a', '&c'), array(
  580. 'property_path' => 'name',
  581. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B', '&c' => 'Choice&C'),
  582. 'multiple' => true,
  583. 'expanded' => true,
  584. 'required' => true,
  585. ));
  586. $this->assertWidgetMatchesXpath($form->createView(), array(),
  587. '/div
  588. [
  589. ./input[@type="checkbox"][@name="na&me[&a]"][@id="na&me_&a"][@checked][not(@required)]
  590. /following-sibling::label[@for="na&me_&a"][.="[trans]Choice&A[/trans]"]
  591. /following-sibling::input[@type="checkbox"][@name="na&me[&b]"][@id="na&me_&b"][not(@checked)][not(@required)]
  592. /following-sibling::label[@for="na&me_&b"][.="[trans]Choice&B[/trans]"]
  593. /following-sibling::input[@type="checkbox"][@name="na&me[&c]"][@id="na&me_&c"][@checked][not(@required)]
  594. /following-sibling::label[@for="na&me_&c"][.="[trans]Choice&C[/trans]"]
  595. ]
  596. [count(./input)=3]
  597. '
  598. );
  599. }
  600. public function testCountry()
  601. {
  602. $form = $this->factory->createNamed('country', 'na&me', 'AT', array(
  603. 'property_path' => 'name',
  604. ));
  605. $this->assertWidgetMatchesXpath($form->createView(), array(),
  606. '/select
  607. [@name="na&me"]
  608. [./option[@value="AT"][@selected="selected"][.="Austria"]]
  609. [count(./option)>200]
  610. '
  611. );
  612. }
  613. public function testCountryWithEmptyValue()
  614. {
  615. $form = $this->factory->createNamed('country', 'na&me', 'AT', array(
  616. 'property_path' => 'name',
  617. 'empty_value' => 'Select&Country',
  618. 'required' => false,
  619. ));
  620. $this->assertWidgetMatchesXpath($form->createView(), array(),
  621. '/select
  622. [@name="na&me"]
  623. [./option[@value=""][not(@selected)][.="[trans]Select&Country[/trans]"]]
  624. [./option[@value="AT"][@selected="selected"][.="Austria"]]
  625. [count(./option)>201]
  626. '
  627. );
  628. }
  629. public function testCsrf()
  630. {
  631. $this->csrfProvider->expects($this->any())
  632. ->method('generateCsrfToken')
  633. ->will($this->returnValue('foo&bar'));
  634. $form = $this->factory->createNamed('csrf', 'na&me', null, array(
  635. 'property_path' => 'name',
  636. ));
  637. $this->assertWidgetMatchesXpath($form->createView(), array(),
  638. '/input
  639. [@type="hidden"]
  640. [@value="foo&bar"]
  641. '
  642. );
  643. }
  644. public function testDateTime()
  645. {
  646. $form = $this->factory->createNamed('datetime', 'na&me', '2011-02-03 04:05:06', array(
  647. 'property_path' => 'name',
  648. 'input' => 'string',
  649. 'with_seconds' => false,
  650. ));
  651. $this->assertWidgetMatchesXpath($form->createView(), array(),
  652. '/div
  653. [
  654. ./div
  655. [@id="na&me_date"]
  656. [
  657. ./select
  658. [@id="na&me_date_month"]
  659. [./option[@value="2"][@selected="selected"]]
  660. /following-sibling::select
  661. [@id="na&me_date_day"]
  662. [./option[@value="3"][@selected="selected"]]
  663. /following-sibling::select
  664. [@id="na&me_date_year"]
  665. [./option[@value="2011"][@selected="selected"]]
  666. ]
  667. /following-sibling::div
  668. [@id="na&me_time"]
  669. [
  670. ./select
  671. [@id="na&me_time_hour"]
  672. [./option[@value="4"][@selected="selected"]]
  673. /following-sibling::select
  674. [@id="na&me_time_minute"]
  675. [./option[@value="5"][@selected="selected"]]
  676. ]
  677. ]
  678. [count(.//select)=5]
  679. '
  680. );
  681. }
  682. public function testDateTimeWithEmptyValueGlobal()
  683. {
  684. $form = $this->factory->createNamed('datetime', 'na&me', null, array(
  685. 'property_path' => 'name',
  686. 'input' => 'string',
  687. 'empty_value' => 'Change&Me',
  688. 'required' => false,
  689. ));
  690. $this->assertWidgetMatchesXpath($form->createView(), array(),
  691. '/div
  692. [
  693. ./div
  694. [@id="na&me_date"]
  695. [
  696. ./select
  697. [@id="na&me_date_month"]
  698. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  699. /following-sibling::select
  700. [@id="na&me_date_day"]
  701. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  702. /following-sibling::select
  703. [@id="na&me_date_year"]
  704. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  705. ]
  706. /following-sibling::div
  707. [@id="na&me_time"]
  708. [
  709. ./select
  710. [@id="na&me_time_hour"]
  711. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  712. /following-sibling::select
  713. [@id="na&me_time_minute"]
  714. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  715. ]
  716. ]
  717. [count(.//select)=5]
  718. '
  719. );
  720. }
  721. public function testDateTimeWithEmptyValueOnTime()
  722. {
  723. $form = $this->factory->createNamed('datetime', 'na&me', '2011-02-03', array(
  724. 'property_path' => 'name',
  725. 'input' => 'string',
  726. 'empty_value' => array('hour' => 'Change&Me', 'minute' => 'Change&Me'),
  727. 'required' => false,
  728. ));
  729. $this->assertWidgetMatchesXpath($form->createView(), array(),
  730. '/div
  731. [
  732. ./div
  733. [@id="na&me_date"]
  734. [
  735. ./select
  736. [@id="na&me_date_month"]
  737. [./option[@value="2"][@selected="selected"]]
  738. /following-sibling::select
  739. [@id="na&me_date_day"]
  740. [./option[@value="3"][@selected="selected"]]
  741. /following-sibling::select
  742. [@id="na&me_date_year"]
  743. [./option[@value="2011"][@selected="selected"]]
  744. ]
  745. /following-sibling::div
  746. [@id="na&me_time"]
  747. [
  748. ./select
  749. [@id="na&me_time_hour"]
  750. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  751. /following-sibling::select
  752. [@id="na&me_time_minute"]
  753. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  754. ]
  755. ]
  756. [count(.//select)=5]
  757. '
  758. );
  759. }
  760. public function testDateTimeWithSeconds()
  761. {
  762. $form = $this->factory->createNamed('datetime', 'na&me', '2011-02-03 04:05:06', array(
  763. 'property_path' => 'name',
  764. 'input' => 'string',
  765. 'with_seconds' => true,
  766. ));
  767. $this->assertWidgetMatchesXpath($form->createView(), array(),
  768. '/div
  769. [
  770. ./div
  771. [@id="na&me_date"]
  772. [
  773. ./select
  774. [@id="na&me_date_month"]
  775. [./option[@value="2"][@selected="selected"]]
  776. /following-sibling::select
  777. [@id="na&me_date_day"]
  778. [./option[@value="3"][@selected="selected"]]
  779. /following-sibling::select
  780. [@id="na&me_date_year"]
  781. [./option[@value="2011"][@selected="selected"]]
  782. ]
  783. /following-sibling::div
  784. [@id="na&me_time"]
  785. [
  786. ./select
  787. [@id="na&me_time_hour"]
  788. [./option[@value="4"][@selected="selected"]]
  789. /following-sibling::select
  790. [@id="na&me_time_minute"]
  791. [./option[@value="5"][@selected="selected"]]
  792. /following-sibling::select
  793. [@id="na&me_time_second"]
  794. [./option[@value="6"][@selected="selected"]]
  795. ]
  796. ]
  797. [count(.//select)=6]
  798. '
  799. );
  800. }
  801. public function testDateChoice()
  802. {
  803. $form = $this->factory->createNamed('date', 'na&me', '2011-02-03', array(
  804. 'property_path' => 'name',
  805. 'input' => 'string',
  806. 'widget' => 'choice',
  807. ));
  808. $this->assertWidgetMatchesXpath($form->createView(), array(),
  809. '/div
  810. [
  811. ./select
  812. [@id="na&me_month"]
  813. [./option[@value="2"][@selected="selected"]]
  814. /following-sibling::select
  815. [@id="na&me_day"]
  816. [./option[@value="3"][@selected="selected"]]
  817. /following-sibling::select
  818. [@id="na&me_year"]
  819. [./option[@value="2011"][@selected="selected"]]
  820. ]
  821. [count(./select)=3]
  822. '
  823. );
  824. }
  825. public function testDateChoiceWithEmptyValueGlobal()
  826. {
  827. $form = $this->factory->createNamed('date', 'na&me', null, array(
  828. 'property_path' => 'name',
  829. 'input' => 'string',
  830. 'widget' => 'choice',
  831. 'empty_value' => 'Change&Me',
  832. 'required' => false,
  833. ));
  834. $this->assertWidgetMatchesXpath($form->createView(), array(),
  835. '/div
  836. [
  837. ./select
  838. [@id="na&me_month"]
  839. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  840. /following-sibling::select
  841. [@id="na&me_day"]
  842. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  843. /following-sibling::select
  844. [@id="na&me_year"]
  845. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  846. ]
  847. [count(./select)=3]
  848. '
  849. );
  850. }
  851. public function testDateChoiceWithEmptyValueOnYear()
  852. {
  853. $form = $this->factory->createNamed('date', 'na&me', null, array(
  854. 'property_path' => 'name',
  855. 'input' => 'string',
  856. 'widget' => 'choice',
  857. 'required' => false,
  858. 'empty_value' => array('year' => 'Change&Me'),
  859. ));
  860. $this->assertWidgetMatchesXpath($form->createView(), array(),
  861. '/div
  862. [
  863. ./select
  864. [@id="na&me_month"]
  865. [./option[@value="1"]]
  866. /following-sibling::select
  867. [@id="na&me_day"]
  868. [./option[@value="1"]]
  869. /following-sibling::select
  870. [@id="na&me_year"]
  871. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  872. ]
  873. [count(./select)=3]
  874. '
  875. );
  876. }
  877. public function testDateText()
  878. {
  879. $form = $this->factory->createNamed('date', 'na&me', '2011-02-03', array(
  880. 'property_path' => 'name',
  881. 'input' => 'string',
  882. 'widget' => 'text',
  883. ));
  884. $this->assertWidgetMatchesXpath($form->createView(), array(),
  885. '/div
  886. [
  887. ./input
  888. [@id="na&me_month"]
  889. [@type="text"]
  890. [@value="2"]
  891. /following-sibling::input
  892. [@id="na&me_day"]
  893. [@type="text"]
  894. [@value="3"]
  895. /following-sibling::input
  896. [@id="na&me_year"]
  897. [@type="text"]
  898. [@value="2011"]
  899. ]
  900. [count(./input)=3]
  901. '
  902. );
  903. }
  904. public function testDateSingleText()
  905. {
  906. $form = $this->factory->createNamed('date', 'na&me', '2011-02-03', array(
  907. 'property_path' => 'name',
  908. 'input' => 'string',
  909. 'widget' => 'single_text',
  910. ));
  911. $this->assertWidgetMatchesXpath($form->createView(), array(),
  912. '/input
  913. [@type="text"]
  914. [@name="na&me"]
  915. [@value="Feb 3, 2011"]
  916. '
  917. );
  918. }
  919. public function testBirthDay()
  920. {
  921. $form = $this->factory->createNamed('birthday', 'na&me', '2000-02-03', array(
  922. 'property_path' => 'name',
  923. 'input' => 'string',
  924. ));
  925. $this->assertWidgetMatchesXpath($form->createView(), array(),
  926. '/div
  927. [
  928. ./select
  929. [@id="na&me_month"]
  930. [./option[@value="2"][@selected="selected"]]
  931. /following-sibling::select
  932. [@id="na&me_day"]
  933. [./option[@value="3"][@selected="selected"]]
  934. /following-sibling::select
  935. [@id="na&me_year"]
  936. [./option[@value="2000"][@selected="selected"]]
  937. ]
  938. [count(./select)=3]
  939. '
  940. );
  941. }
  942. public function testBirthDayWithEmptyValue()
  943. {
  944. $form = $this->factory->createNamed('birthday', 'na&me', '1950-01-01', array(
  945. 'property_path' => 'name',
  946. 'input' => 'string',
  947. 'empty_value' => '',
  948. 'required' => false,
  949. ));
  950. $this->assertWidgetMatchesXpath($form->createView(), array(),
  951. '/div
  952. [
  953. ./select
  954. [@id="na&me_month"]
  955. [./option[@value=""][.="[trans][/trans]"]]
  956. [./option[@value="1"][@selected="selected"]]
  957. /following-sibling::select
  958. [@id="na&me_day"]
  959. [./option[@value=""][.="[trans][/trans]"]]
  960. [./option[@value="1"][@selected="selected"]]
  961. /following-sibling::select
  962. [@id="na&me_year"]
  963. [./option[@value=""][.="[trans][/trans]"]]
  964. [./option[@value="1950"][@selected="selected"]]
  965. ]
  966. [count(./select)=3]
  967. '
  968. );
  969. }
  970. public function testEmail()
  971. {
  972. $form = $this->factory->createNamed('email', 'na&me', 'foo&bar', array(
  973. 'property_path' => 'name',
  974. ));
  975. $this->assertWidgetMatchesXpath($form->createView(), array(),
  976. '/input
  977. [@type="email"]
  978. [@name="na&me"]
  979. [@value="foo&bar"]
  980. [not(@maxlength)]
  981. '
  982. );
  983. }
  984. public function testEmailWithMaxLength()
  985. {
  986. $form = $this->factory->createNamed('email', 'na&me', 'foo&bar', array(
  987. 'property_path' => 'name',
  988. 'max_length' => 123,
  989. ));
  990. $this->assertWidgetMatchesXpath($form->createView(), array(),
  991. '/input
  992. [@type="email"]
  993. [@name="na&me"]
  994. [@value="foo&bar"]
  995. [@maxlength="123"]
  996. '
  997. );
  998. }
  999. public function testFile()
  1000. {
  1001. $form = $this->factory->createNamed('file', 'na&me', null, array(
  1002. 'property_path' => 'name',
  1003. ));
  1004. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1005. '/input
  1006. [@type="file"]
  1007. '
  1008. );
  1009. }
  1010. public function testHidden()
  1011. {
  1012. $form = $this->factory->createNamed('hidden', 'na&me', 'foo&bar', array(
  1013. 'property_path' => 'name',
  1014. ));
  1015. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1016. '/input
  1017. [@type="hidden"]
  1018. [@name="na&me"]
  1019. [@value="foo&bar"]
  1020. '
  1021. );
  1022. }
  1023. public function testInteger()
  1024. {
  1025. $form = $this->factory->createNamed('integer', 'na&me', 123, array(
  1026. 'property_path' => 'name',
  1027. ));
  1028. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1029. '/input
  1030. [@type="number"]
  1031. [@name="na&me"]
  1032. [@value="123"]
  1033. '
  1034. );
  1035. }
  1036. public function testLanguage()
  1037. {
  1038. $form = $this->factory->createNamed('language', 'na&me', 'de', array(
  1039. 'property_path' => 'name',
  1040. ));
  1041. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1042. '/select
  1043. [@name="na&me"]
  1044. [./option[@value="de"][@selected="selected"][.="German"]]
  1045. [count(./option)>200]
  1046. '
  1047. );
  1048. }
  1049. public function testLocale()
  1050. {
  1051. $form = $this->factory->createNamed('locale', 'na&me', 'de_AT', array(
  1052. 'property_path' => 'name',
  1053. ));
  1054. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1055. '/select
  1056. [@name="na&me"]
  1057. [./option[@value="de_AT"][@selected="selected"][.="German (Austria)"]]
  1058. [count(./option)>200]
  1059. '
  1060. );
  1061. }
  1062. public function testMoney()
  1063. {
  1064. $form = $this->factory->createNamed('money', 'na&me', 1234.56, array(
  1065. 'property_path' => 'name',
  1066. 'currency' => 'EUR',
  1067. ));
  1068. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1069. '/input
  1070. [@type="text"]
  1071. [@name="na&me"]
  1072. [@value="1234.56"]
  1073. [contains(.., "€")]
  1074. '
  1075. );
  1076. }
  1077. public function testNumber()
  1078. {
  1079. $form = $this->factory->createNamed('number', 'na&me', 1234.56, array(
  1080. 'property_path' => 'name',
  1081. ));
  1082. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1083. '/input
  1084. [@type="text"]
  1085. [@name="na&me"]
  1086. [@value="1234.56"]
  1087. '
  1088. );
  1089. }
  1090. public function testPassword()
  1091. {
  1092. $form = $this->factory->createNamed('password', 'na&me', 'foo&bar', array(
  1093. 'property_path' => 'name',
  1094. ));
  1095. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1096. '/input
  1097. [@type="password"]
  1098. [@name="na&me"]
  1099. [@value=""]
  1100. '
  1101. );
  1102. }
  1103. public function testPasswordBoundNotAlwaysEmpty()
  1104. {
  1105. $form = $this->factory->createNamed('password', 'na&me', null, array(
  1106. 'property_path' => 'name',
  1107. 'always_empty' => false,
  1108. ));
  1109. $form->bind('foo&bar');
  1110. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1111. '/input
  1112. [@type="password"]
  1113. [@name="na&me"]
  1114. [@value="foo&bar"]
  1115. '
  1116. );
  1117. }
  1118. public function testPasswordWithMaxLength()
  1119. {
  1120. $form = $this->factory->createNamed('password', 'na&me', 'foo&bar', array(
  1121. 'property_path' => 'name',
  1122. 'max_length' => 123,
  1123. ));
  1124. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1125. '/input
  1126. [@type="password"]
  1127. [@name="na&me"]
  1128. [@value=""]
  1129. [@maxlength="123"]
  1130. '
  1131. );
  1132. }
  1133. public function testPercent()
  1134. {
  1135. $form = $this->factory->createNamed('percent', 'na&me', 0.1, array(
  1136. 'property_path' => 'name',
  1137. ));
  1138. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1139. '/input
  1140. [@type="text"]
  1141. [@name="na&me"]
  1142. [@value="10"]
  1143. [contains(.., "%")]
  1144. '
  1145. );
  1146. }
  1147. public function testCheckedRadio()
  1148. {
  1149. $form = $this->factory->createNamed('radio', 'na&me', true, array(
  1150. 'property_path' => 'name',
  1151. ));
  1152. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1153. '/input
  1154. [@type="radio"]
  1155. [@name="na&me"]
  1156. [@checked="checked"]
  1157. [@value=""]
  1158. '
  1159. );
  1160. }
  1161. public function testCheckedRadioWithValue()
  1162. {
  1163. $form = $this->factory->createNamed('radio', 'na&me', true, array(
  1164. 'property_path' => 'name',
  1165. 'value' => 'foo&bar',
  1166. ));
  1167. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1168. '/input
  1169. [@type="radio"]
  1170. [@name="na&me"]
  1171. [@checked="checked"]
  1172. [@value="foo&bar"]
  1173. '
  1174. );
  1175. }
  1176. public function testUncheckedRadio()
  1177. {
  1178. $form = $this->factory->createNamed('radio', 'na&me', false, array(
  1179. 'property_path' => 'name',
  1180. ));
  1181. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1182. '/input
  1183. [@type="radio"]
  1184. [@name="na&me"]
  1185. [not(@checked)]
  1186. '
  1187. );
  1188. }
  1189. public function testTextarea()
  1190. {
  1191. $form = $this->factory->createNamed('textarea', 'na&me', 'foo&bar', array(
  1192. 'property_path' => 'name',
  1193. ));
  1194. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1195. '/textarea
  1196. [@name="na&me"]
  1197. [.="foo&bar"]
  1198. '
  1199. );
  1200. }
  1201. public function testText()
  1202. {
  1203. $form = $this->factory->createNamed('text', 'na&me', 'foo&bar', array(
  1204. 'property_path' => 'name',
  1205. ));
  1206. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1207. '/input
  1208. [@type="text"]
  1209. [@name="na&me"]
  1210. [@value="foo&bar"]
  1211. [not(@maxlength)]
  1212. '
  1213. );
  1214. }
  1215. public function testTextWithMaxLength()
  1216. {
  1217. $form = $this->factory->createNamed('text', 'na&me', 'foo&bar', array(
  1218. 'property_path' => 'name',
  1219. 'max_length' => 123,
  1220. ));
  1221. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1222. '/input
  1223. [@type="text"]
  1224. [@name="na&me"]
  1225. [@value="foo&bar"]
  1226. [@maxlength="123"]
  1227. '
  1228. );
  1229. }
  1230. public function testSearch()
  1231. {
  1232. $form = $this->factory->createNamed('search', 'na&me', 'foo&bar', array(
  1233. 'property_path' => 'name',
  1234. ));
  1235. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1236. '/input
  1237. [@type="search"]
  1238. [@name="na&me"]
  1239. [@value="foo&bar"]
  1240. [not(@maxlength)]
  1241. '
  1242. );
  1243. }
  1244. public function testTime()
  1245. {
  1246. $form = $this->factory->createNamed('time', 'na&me', '04:05:06', array(
  1247. 'property_path' => 'name',
  1248. 'input' => 'string',
  1249. 'with_seconds' => false,
  1250. ));
  1251. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1252. '/div
  1253. [
  1254. ./select
  1255. [@id="na&me_hour"]
  1256. [@size="1"]
  1257. [./option[@value="4"][@selected="selected"]]
  1258. /following-sibling::select
  1259. [@id="na&me_minute"]
  1260. [@size="1"]
  1261. [./option[@value="5"][@selected="selected"]]
  1262. ]
  1263. [count(./select)=2]
  1264. '
  1265. );
  1266. }
  1267. public function testTimeWithSeconds()
  1268. {
  1269. $form = $this->factory->createNamed('time', 'na&me', '04:05:06', array(
  1270. 'property_path' => 'name',
  1271. 'input' => 'string',
  1272. 'with_seconds' => true,
  1273. ));
  1274. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1275. '/div
  1276. [
  1277. ./select
  1278. [@id="na&me_hour"]
  1279. [@size="1"]
  1280. [./option[@value="4"][@selected="selected"]]
  1281. [count(./option)>23]
  1282. /following-sibling::select
  1283. [@id="na&me_minute"]
  1284. [@size="1"]
  1285. [./option[@value="5"][@selected="selected"]]
  1286. [count(./option)>59]
  1287. /following-sibling::select
  1288. [@id="na&me_second"]
  1289. [@size="1"]
  1290. [./option[@value="6"][@selected="selected"]]
  1291. [count(./option)>59]
  1292. ]
  1293. [count(./select)=3]
  1294. '
  1295. );
  1296. }
  1297. public function testTimeWithEmptyValueGlobal()
  1298. {
  1299. $form = $this->factory->createNamed('time', 'na&me', null, array(
  1300. 'property_path' => 'name',
  1301. 'input' => 'string',
  1302. 'empty_value' => 'Change&Me',
  1303. 'required' => false,
  1304. ));
  1305. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1306. '/div
  1307. [
  1308. ./select
  1309. [@id="na&me_hour"]
  1310. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  1311. [count(./option)>24]
  1312. /following-sibling::select
  1313. [@id="na&me_minute"]
  1314. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  1315. [count(./option)>60]
  1316. ]
  1317. [count(./select)=2]
  1318. '
  1319. );
  1320. }
  1321. public function testTimeWithEmptyValueOnYear()
  1322. {
  1323. $form = $this->factory->createNamed('time', 'na&me', null, array(
  1324. 'property_path' => 'name',
  1325. 'input' => 'string',
  1326. 'required' => false,
  1327. 'empty_value' => array('hour' => 'Change&Me'),
  1328. ));
  1329. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1330. '/div
  1331. [
  1332. ./select
  1333. [@id="na&me_hour"]
  1334. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  1335. [count(./option)>24]
  1336. /following-sibling::select
  1337. [@id="na&me_minute"]
  1338. [./option[@value="1"]]
  1339. [count(./option)>59]
  1340. ]
  1341. [count(./select)=2]
  1342. '
  1343. );
  1344. }
  1345. public function testTimezone()
  1346. {
  1347. $form = $this->factory->createNamed('timezone', 'na&me', 'Europe/Vienna', array(
  1348. 'property_path' => 'name',
  1349. ));
  1350. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1351. '/select
  1352. [@name="na&me"]
  1353. [@required="required"]
  1354. [./optgroup
  1355. [@label="Europe"]
  1356. [./option[@value="Europe/Vienna"][@selected="selected"][.="Vienna"]]
  1357. ]
  1358. [count(./optgroup)>10]
  1359. [count(.//option)>200]
  1360. '
  1361. );
  1362. }
  1363. public function testTimezoneWithEmptyValue()
  1364. {
  1365. $form = $this->factory->createNamed('timezone', 'na&me', null, array(
  1366. 'property_path' => 'name',
  1367. 'empty_value' => 'Select&Timezone',
  1368. 'required' => false,
  1369. ));
  1370. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1371. '/select
  1372. [./option[@value=""][.="[trans]Select&Timezone[/trans]"]]
  1373. [count(./optgroup)>10]
  1374. [count(.//option)>201]
  1375. '
  1376. );
  1377. }
  1378. public function testUrl()
  1379. {
  1380. $url = 'http://www.google.com?foo1=bar1&foo2=bar2';
  1381. $form = $this->factory->createNamed('url', 'na&me', $url, array(
  1382. 'property_path' => 'name',
  1383. ));
  1384. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1385. '/input
  1386. [@type="url"]
  1387. [@name="na&me"]
  1388. [@value="http://www.google.com?foo1=bar1&foo2=bar2"]
  1389. '
  1390. );
  1391. }
  1392. public function testCollectionPrototype()
  1393. {
  1394. $form = $this->factory->createNamedBuilder('form', 'na&me', array('items' => array('one', 'two', 'three')))
  1395. ->add('items', 'collection', array('allow_add' => true))
  1396. ->getForm()
  1397. ->createView();
  1398. $html = $this->renderWidget($form);
  1399. $this->assertMatchesXpath($html,
  1400. '//script
  1401. [@id="na&me_items_prototype"]
  1402. [@type="text/html"]
  1403. '
  1404. );
  1405. }
  1406. }