AbstractLayoutTest.php 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469
  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. [
  285. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  286. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  287. ]
  288. [count(./option)=2]
  289. '
  290. );
  291. }
  292. public function testSingleChoiceWithPreferred()
  293. {
  294. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  295. 'property_path' => 'name',
  296. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  297. 'preferred_choices' => array('&b'),
  298. 'multiple' => false,
  299. 'expanded' => false,
  300. ));
  301. $this->assertWidgetMatchesXpath($form->createView(), array('separator' => '-- sep --'),
  302. '/select
  303. [@name="na&me"]
  304. [@required="required"]
  305. [
  306. ./option[@value="&b"][not(@selected)][.="Choice&B"]
  307. /following-sibling::option[@disabled="disabled"][not(@selected)][.="-- sep --"]
  308. /following-sibling::option[@value="&a"][@selected="selected"][.="Choice&A"]
  309. ]
  310. [count(./option)=3]
  311. '
  312. );
  313. }
  314. public function testSingleChoiceNonRequired()
  315. {
  316. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  317. 'property_path' => 'name',
  318. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  319. 'required' => false,
  320. 'multiple' => false,
  321. 'expanded' => false,
  322. ));
  323. $this->assertWidgetMatchesXpath($form->createView(), array(),
  324. '/select
  325. [@name="na&me"]
  326. [not(@required)]
  327. [
  328. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  329. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  330. ]
  331. [count(./option)=2]
  332. '
  333. );
  334. }
  335. public function testSingleChoiceNonRequiredNoneSelected()
  336. {
  337. $form = $this->factory->createNamed('choice', 'na&me', null, array(
  338. 'property_path' => 'name',
  339. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  340. 'required' => false,
  341. 'multiple' => false,
  342. 'expanded' => false,
  343. ));
  344. $this->assertWidgetMatchesXpath($form->createView(), array(),
  345. '/select
  346. [@name="na&me"]
  347. [not(@required)]
  348. [
  349. ./option[@value="&a"][not(@selected)][.="Choice&A"]
  350. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  351. ]
  352. [count(./option)=2]
  353. '
  354. );
  355. }
  356. public function testSingleChoiceWithNonRequiredEmptyValue()
  357. {
  358. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  359. 'property_path' => 'name',
  360. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  361. 'multiple' => false,
  362. 'expanded' => false,
  363. 'required' => false,
  364. 'empty_value' => 'Select&Anything&Not&Me',
  365. ));
  366. $this->assertWidgetMatchesXpath($form->createView(), array(),
  367. '/select
  368. [@name="na&me"]
  369. [not(@required)]
  370. [
  371. ./option[@value=""][not(@selected)][.="[trans]Select&Anything&Not&Me[/trans]"]
  372. /following-sibling::option[@value="&a"][@selected="selected"][.="Choice&A"]
  373. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  374. ]
  375. [count(./option)=3]
  376. '
  377. );
  378. }
  379. public function testSingleChoiceRequiredWithEmptyValue()
  380. {
  381. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  382. 'property_path' => 'name',
  383. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  384. 'required' => true,
  385. 'multiple' => false,
  386. 'expanded' => false,
  387. 'empty_value' => 'Test&Me'
  388. ));
  389. $this->assertWidgetMatchesXpath($form->createView(), array(),
  390. '/select
  391. [@name="na&me"]
  392. [@required="required"]
  393. [
  394. ./option[@value=""][.="[trans]Test&Me[/trans]"]
  395. /following-sibling::option[@value="&a"][@selected="selected"][.="Choice&A"]
  396. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  397. ]
  398. [count(./option)=3]
  399. '
  400. );
  401. }
  402. public function testSingleChoiceRequiredWithEmptyValueViaView()
  403. {
  404. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  405. 'property_path' => 'name',
  406. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  407. 'required' => true,
  408. 'multiple' => false,
  409. 'expanded' => false,
  410. ));
  411. $this->assertWidgetMatchesXpath($form->createView(), array('empty_value' => ''),
  412. '/select
  413. [@name="na&me"]
  414. [@required="required"]
  415. [
  416. ./option[@value=""][.="[trans][/trans]"]
  417. /following-sibling::option[@value="&a"][@selected="selected"][.="Choice&A"]
  418. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  419. ]
  420. [count(./option)=3]
  421. '
  422. );
  423. }
  424. public function testSingleChoiceGrouped()
  425. {
  426. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  427. 'property_path' => 'name',
  428. 'choices' => array(
  429. 'Group&1' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  430. 'Group&2' => array('&c' => 'Choice&C'),
  431. ),
  432. 'multiple' => false,
  433. 'expanded' => false,
  434. ));
  435. $this->assertWidgetMatchesXpath($form->createView(), array(),
  436. '/select
  437. [@name="na&me"]
  438. [./optgroup[@label="Group&1"]
  439. [
  440. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  441. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  442. ]
  443. [count(./option)=2]
  444. ]
  445. [./optgroup[@label="Group&2"]
  446. [./option[@value="&c"][not(@selected)][.="Choice&C"]]
  447. [count(./option)=1]
  448. ]
  449. [count(./optgroup)=2]
  450. '
  451. );
  452. }
  453. public function testMultipleChoice()
  454. {
  455. $form = $this->factory->createNamed('choice', 'na&me', array('&a'), array(
  456. 'property_path' => 'name',
  457. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  458. 'multiple' => true,
  459. 'expanded' => false,
  460. ));
  461. $this->assertWidgetMatchesXpath($form->createView(), array(),
  462. '/select
  463. [@name="na&me[]"]
  464. [@multiple="multiple"]
  465. [
  466. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  467. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  468. ]
  469. [count(./option)=2]
  470. '
  471. );
  472. }
  473. public function testMultipleChoiceSkipEmptyValue()
  474. {
  475. $form = $this->factory->createNamed('choice', 'na&me', array('&a'), array(
  476. 'property_path' => 'name',
  477. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  478. 'multiple' => true,
  479. 'expanded' => false,
  480. 'empty_value' => 'Test&Me'
  481. ));
  482. $this->assertWidgetMatchesXpath($form->createView(), array(),
  483. '/select
  484. [@name="na&me[]"]
  485. [@multiple="multiple"]
  486. [
  487. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  488. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  489. ]
  490. [count(./option)=2]
  491. '
  492. );
  493. }
  494. public function testMultipleChoiceNonRequired()
  495. {
  496. $form = $this->factory->createNamed('choice', 'na&me', array('&a'), array(
  497. 'property_path' => 'name',
  498. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  499. 'required' => false,
  500. 'multiple' => true,
  501. 'expanded' => false,
  502. ));
  503. $this->assertWidgetMatchesXpath($form->createView(), array(),
  504. '/select
  505. [@name="na&me[]"]
  506. [@multiple="multiple"]
  507. [
  508. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  509. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  510. ]
  511. [count(./option)=2]
  512. '
  513. );
  514. }
  515. public function testSingleChoiceExpanded()
  516. {
  517. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  518. 'property_path' => 'name',
  519. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  520. 'multiple' => false,
  521. 'expanded' => true,
  522. ));
  523. $this->assertWidgetMatchesXpath($form->createView(), array(),
  524. '/div
  525. [
  526. ./input[@type="radio"][@name="na&me"][@id="na&me_&a"][@checked]
  527. /following-sibling::label[@for="na&me_&a"][.="[trans]Choice&A[/trans]"]
  528. /following-sibling::input[@type="radio"][@name="na&me"][@id="na&me_&b"][not(@checked)]
  529. /following-sibling::label[@for="na&me_&b"][.="[trans]Choice&B[/trans]"]
  530. ]
  531. [count(./input)=2]
  532. '
  533. );
  534. }
  535. public function testSingleChoiceExpandedSkipEmptyValue()
  536. {
  537. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  538. 'property_path' => 'name',
  539. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  540. 'multiple' => false,
  541. 'expanded' => true,
  542. 'empty_value' => 'Test&Me'
  543. ));
  544. $this->assertWidgetMatchesXpath($form->createView(), array(),
  545. '/div
  546. [
  547. ./input[@type="radio"][@name="na&me"][@id="na&me_&a"][@checked]
  548. /following-sibling::label[@for="na&me_&a"][.="[trans]Choice&A[/trans]"]
  549. /following-sibling::input[@type="radio"][@name="na&me"][@id="na&me_&b"][not(@checked)]
  550. /following-sibling::label[@for="na&me_&b"][.="[trans]Choice&B[/trans]"]
  551. ]
  552. [count(./input)=2]
  553. '
  554. );
  555. }
  556. public function testSingleChoiceExpandedWithBooleanValue()
  557. {
  558. $form = $this->factory->createNamed('choice', 'na&me', true, array(
  559. 'property_path' => 'name',
  560. 'choices' => array('1' => 'Choice&A', '0' => 'Choice&B'),
  561. 'multiple' => false,
  562. 'expanded' => true,
  563. ));
  564. $this->assertWidgetMatchesXpath($form->createView(), array(),
  565. '/div
  566. [
  567. ./input[@type="radio"][@name="na&me"][@id="na&me_1"][@checked]
  568. /following-sibling::label[@for="na&me_1"][.="[trans]Choice&A[/trans]"]
  569. /following-sibling::input[@type="radio"][@name="na&me"][@id="na&me_0"][not(@checked)]
  570. /following-sibling::label[@for="na&me_0"][.="[trans]Choice&B[/trans]"]
  571. ]
  572. [count(./input)=2]
  573. '
  574. );
  575. }
  576. public function testMultipleChoiceExpanded()
  577. {
  578. $form = $this->factory->createNamed('choice', 'na&me', array('&a', '&c'), array(
  579. 'property_path' => 'name',
  580. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B', '&c' => 'Choice&C'),
  581. 'multiple' => true,
  582. 'expanded' => true,
  583. 'required' => true,
  584. ));
  585. $this->assertWidgetMatchesXpath($form->createView(), array(),
  586. '/div
  587. [
  588. ./input[@type="checkbox"][@name="na&me[&a]"][@id="na&me_&a"][@checked][not(@required)]
  589. /following-sibling::label[@for="na&me_&a"][.="[trans]Choice&A[/trans]"]
  590. /following-sibling::input[@type="checkbox"][@name="na&me[&b]"][@id="na&me_&b"][not(@checked)][not(@required)]
  591. /following-sibling::label[@for="na&me_&b"][.="[trans]Choice&B[/trans]"]
  592. /following-sibling::input[@type="checkbox"][@name="na&me[&c]"][@id="na&me_&c"][@checked][not(@required)]
  593. /following-sibling::label[@for="na&me_&c"][.="[trans]Choice&C[/trans]"]
  594. ]
  595. [count(./input)=3]
  596. '
  597. );
  598. }
  599. public function testCountry()
  600. {
  601. $form = $this->factory->createNamed('country', 'na&me', 'AT', array(
  602. 'property_path' => 'name',
  603. ));
  604. $this->assertWidgetMatchesXpath($form->createView(), array(),
  605. '/select
  606. [@name="na&me"]
  607. [./option[@value="AT"][@selected="selected"][.="Austria"]]
  608. [count(./option)>200]
  609. '
  610. );
  611. }
  612. public function testCsrf()
  613. {
  614. $this->csrfProvider->expects($this->any())
  615. ->method('generateCsrfToken')
  616. ->will($this->returnValue('foo&bar'));
  617. $form = $this->factory->createNamed('csrf', 'na&me', null, array(
  618. 'property_path' => 'name',
  619. ));
  620. $this->assertWidgetMatchesXpath($form->createView(), array(),
  621. '/input
  622. [@type="hidden"]
  623. [@value="foo&bar"]
  624. '
  625. );
  626. }
  627. public function testDateTime()
  628. {
  629. $form = $this->factory->createNamed('datetime', 'na&me', '2011-02-03 04:05:06', array(
  630. 'property_path' => 'name',
  631. 'input' => 'string',
  632. 'with_seconds' => false,
  633. ));
  634. $this->assertWidgetMatchesXpath($form->createView(), array(),
  635. '/div
  636. [
  637. ./div
  638. [@id="na&me_date"]
  639. [
  640. ./select
  641. [@id="na&me_date_month"]
  642. [./option[@value="2"][@selected="selected"]]
  643. /following-sibling::select
  644. [@id="na&me_date_day"]
  645. [./option[@value="3"][@selected="selected"]]
  646. /following-sibling::select
  647. [@id="na&me_date_year"]
  648. [./option[@value="2011"][@selected="selected"]]
  649. ]
  650. /following-sibling::div
  651. [@id="na&me_time"]
  652. [
  653. ./select
  654. [@id="na&me_time_hour"]
  655. [./option[@value="4"][@selected="selected"]]
  656. /following-sibling::select
  657. [@id="na&me_time_minute"]
  658. [./option[@value="5"][@selected="selected"]]
  659. ]
  660. ]
  661. [count(.//select)=5]
  662. '
  663. );
  664. }
  665. public function testDateTimeWithEmptyValueGlobal()
  666. {
  667. $form = $this->factory->createNamed('datetime', 'na&me', null, array(
  668. 'property_path' => 'name',
  669. 'input' => 'string',
  670. 'empty_value' => 'Change&Me',
  671. 'required' => false,
  672. ));
  673. $this->assertWidgetMatchesXpath($form->createView(), array(),
  674. '/div
  675. [
  676. ./div
  677. [@id="na&me_date"]
  678. [
  679. ./select
  680. [@id="na&me_date_month"]
  681. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  682. /following-sibling::select
  683. [@id="na&me_date_day"]
  684. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  685. /following-sibling::select
  686. [@id="na&me_date_year"]
  687. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  688. ]
  689. /following-sibling::div
  690. [@id="na&me_time"]
  691. [
  692. ./select
  693. [@id="na&me_time_hour"]
  694. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  695. /following-sibling::select
  696. [@id="na&me_time_minute"]
  697. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  698. ]
  699. ]
  700. [count(.//select)=5]
  701. '
  702. );
  703. }
  704. public function testDateTimeWithEmptyValueOnTime()
  705. {
  706. $form = $this->factory->createNamed('datetime', 'na&me', '2011-02-03', array(
  707. 'property_path' => 'name',
  708. 'input' => 'string',
  709. 'empty_value' => array('hour' => 'Change&Me', 'minute' => 'Change&Me'),
  710. 'required' => false,
  711. ));
  712. $this->assertWidgetMatchesXpath($form->createView(), array(),
  713. '/div
  714. [
  715. ./div
  716. [@id="na&me_date"]
  717. [
  718. ./select
  719. [@id="na&me_date_month"]
  720. [./option[@value="2"][@selected="selected"]]
  721. /following-sibling::select
  722. [@id="na&me_date_day"]
  723. [./option[@value="3"][@selected="selected"]]
  724. /following-sibling::select
  725. [@id="na&me_date_year"]
  726. [./option[@value="2011"][@selected="selected"]]
  727. ]
  728. /following-sibling::div
  729. [@id="na&me_time"]
  730. [
  731. ./select
  732. [@id="na&me_time_hour"]
  733. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  734. /following-sibling::select
  735. [@id="na&me_time_minute"]
  736. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  737. ]
  738. ]
  739. [count(.//select)=5]
  740. '
  741. );
  742. }
  743. public function testDateTimeWithSeconds()
  744. {
  745. $form = $this->factory->createNamed('datetime', 'na&me', '2011-02-03 04:05:06', array(
  746. 'property_path' => 'name',
  747. 'input' => 'string',
  748. 'with_seconds' => true,
  749. ));
  750. $this->assertWidgetMatchesXpath($form->createView(), array(),
  751. '/div
  752. [
  753. ./div
  754. [@id="na&me_date"]
  755. [
  756. ./select
  757. [@id="na&me_date_month"]
  758. [./option[@value="2"][@selected="selected"]]
  759. /following-sibling::select
  760. [@id="na&me_date_day"]
  761. [./option[@value="3"][@selected="selected"]]
  762. /following-sibling::select
  763. [@id="na&me_date_year"]
  764. [./option[@value="2011"][@selected="selected"]]
  765. ]
  766. /following-sibling::div
  767. [@id="na&me_time"]
  768. [
  769. ./select
  770. [@id="na&me_time_hour"]
  771. [./option[@value="4"][@selected="selected"]]
  772. /following-sibling::select
  773. [@id="na&me_time_minute"]
  774. [./option[@value="5"][@selected="selected"]]
  775. /following-sibling::select
  776. [@id="na&me_time_second"]
  777. [./option[@value="6"][@selected="selected"]]
  778. ]
  779. ]
  780. [count(.//select)=6]
  781. '
  782. );
  783. }
  784. public function testDateChoice()
  785. {
  786. $form = $this->factory->createNamed('date', 'na&me', '2011-02-03', array(
  787. 'property_path' => 'name',
  788. 'input' => 'string',
  789. 'widget' => 'choice',
  790. ));
  791. $this->assertWidgetMatchesXpath($form->createView(), array(),
  792. '/div
  793. [
  794. ./select
  795. [@id="na&me_month"]
  796. [./option[@value="2"][@selected="selected"]]
  797. /following-sibling::select
  798. [@id="na&me_day"]
  799. [./option[@value="3"][@selected="selected"]]
  800. /following-sibling::select
  801. [@id="na&me_year"]
  802. [./option[@value="2011"][@selected="selected"]]
  803. ]
  804. [count(./select)=3]
  805. '
  806. );
  807. }
  808. public function testDateChoiceWithEmptyValueGlobal()
  809. {
  810. $form = $this->factory->createNamed('date', 'na&me', null, array(
  811. 'property_path' => 'name',
  812. 'input' => 'string',
  813. 'widget' => 'choice',
  814. 'empty_value' => 'Change&Me',
  815. 'required' => false,
  816. ));
  817. $this->assertWidgetMatchesXpath($form->createView(), array(),
  818. '/div
  819. [
  820. ./select
  821. [@id="na&me_month"]
  822. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  823. /following-sibling::select
  824. [@id="na&me_day"]
  825. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  826. /following-sibling::select
  827. [@id="na&me_year"]
  828. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  829. ]
  830. [count(./select)=3]
  831. '
  832. );
  833. }
  834. public function testDateChoiceWithEmptyValueOnYear()
  835. {
  836. $form = $this->factory->createNamed('date', 'na&me', null, array(
  837. 'property_path' => 'name',
  838. 'input' => 'string',
  839. 'widget' => 'choice',
  840. 'required' => false,
  841. 'empty_value' => array('year' => 'Change&Me'),
  842. ));
  843. $this->assertWidgetMatchesXpath($form->createView(), array(),
  844. '/div
  845. [
  846. ./select
  847. [@id="na&me_month"]
  848. [./option[@value="1"]]
  849. /following-sibling::select
  850. [@id="na&me_day"]
  851. [./option[@value="1"]]
  852. /following-sibling::select
  853. [@id="na&me_year"]
  854. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  855. ]
  856. [count(./select)=3]
  857. '
  858. );
  859. }
  860. public function testDateText()
  861. {
  862. $form = $this->factory->createNamed('date', 'na&me', '2011-02-03', array(
  863. 'property_path' => 'name',
  864. 'input' => 'string',
  865. 'widget' => 'text',
  866. ));
  867. $this->assertWidgetMatchesXpath($form->createView(), array(),
  868. '/div
  869. [
  870. ./input
  871. [@id="na&me_month"]
  872. [@type="text"]
  873. [@value="2"]
  874. /following-sibling::input
  875. [@id="na&me_day"]
  876. [@type="text"]
  877. [@value="3"]
  878. /following-sibling::input
  879. [@id="na&me_year"]
  880. [@type="text"]
  881. [@value="2011"]
  882. ]
  883. [count(./input)=3]
  884. '
  885. );
  886. }
  887. public function testDateSingleText()
  888. {
  889. $form = $this->factory->createNamed('date', 'na&me', '2011-02-03', array(
  890. 'property_path' => 'name',
  891. 'input' => 'string',
  892. 'widget' => 'single_text',
  893. ));
  894. $this->assertWidgetMatchesXpath($form->createView(), array(),
  895. '/input
  896. [@type="text"]
  897. [@name="na&me"]
  898. [@value="Feb 3, 2011"]
  899. '
  900. );
  901. }
  902. public function testEmail()
  903. {
  904. $form = $this->factory->createNamed('email', 'na&me', 'foo&bar', array(
  905. 'property_path' => 'name',
  906. ));
  907. $this->assertWidgetMatchesXpath($form->createView(), array(),
  908. '/input
  909. [@type="email"]
  910. [@name="na&me"]
  911. [@value="foo&bar"]
  912. [not(@maxlength)]
  913. '
  914. );
  915. }
  916. public function testEmailWithMaxLength()
  917. {
  918. $form = $this->factory->createNamed('email', 'na&me', 'foo&bar', array(
  919. 'property_path' => 'name',
  920. 'max_length' => 123,
  921. ));
  922. $this->assertWidgetMatchesXpath($form->createView(), array(),
  923. '/input
  924. [@type="email"]
  925. [@name="na&me"]
  926. [@value="foo&bar"]
  927. [@maxlength="123"]
  928. '
  929. );
  930. }
  931. public function testFile()
  932. {
  933. $form = $this->factory->createNamed('file', 'na&me', null, array(
  934. 'property_path' => 'name',
  935. ));
  936. $this->assertWidgetMatchesXpath($form->createView(), array(),
  937. '/input
  938. [@type="file"]
  939. '
  940. );
  941. }
  942. public function testHidden()
  943. {
  944. $form = $this->factory->createNamed('hidden', 'na&me', 'foo&bar', array(
  945. 'property_path' => 'name',
  946. ));
  947. $this->assertWidgetMatchesXpath($form->createView(), array(),
  948. '/input
  949. [@type="hidden"]
  950. [@name="na&me"]
  951. [@value="foo&bar"]
  952. '
  953. );
  954. }
  955. public function testInteger()
  956. {
  957. $form = $this->factory->createNamed('integer', 'na&me', 123, array(
  958. 'property_path' => 'name',
  959. ));
  960. $this->assertWidgetMatchesXpath($form->createView(), array(),
  961. '/input
  962. [@type="number"]
  963. [@name="na&me"]
  964. [@value="123"]
  965. '
  966. );
  967. }
  968. public function testLanguage()
  969. {
  970. $form = $this->factory->createNamed('language', 'na&me', 'de', array(
  971. 'property_path' => 'name',
  972. ));
  973. $this->assertWidgetMatchesXpath($form->createView(), array(),
  974. '/select
  975. [@name="na&me"]
  976. [./option[@value="de"][@selected="selected"][.="German"]]
  977. [count(./option)>200]
  978. '
  979. );
  980. }
  981. public function testLocale()
  982. {
  983. $form = $this->factory->createNamed('locale', 'na&me', 'de_AT', array(
  984. 'property_path' => 'name',
  985. ));
  986. $this->assertWidgetMatchesXpath($form->createView(), array(),
  987. '/select
  988. [@name="na&me"]
  989. [./option[@value="de_AT"][@selected="selected"][.="German (Austria)"]]
  990. [count(./option)>200]
  991. '
  992. );
  993. }
  994. public function testMoney()
  995. {
  996. $form = $this->factory->createNamed('money', 'na&me', 1234.56, array(
  997. 'property_path' => 'name',
  998. 'currency' => 'EUR',
  999. ));
  1000. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1001. '/input
  1002. [@type="text"]
  1003. [@name="na&me"]
  1004. [@value="1234.56"]
  1005. [contains(.., "€")]
  1006. '
  1007. );
  1008. }
  1009. public function testNumber()
  1010. {
  1011. $form = $this->factory->createNamed('number', 'na&me', 1234.56, array(
  1012. 'property_path' => 'name',
  1013. ));
  1014. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1015. '/input
  1016. [@type="text"]
  1017. [@name="na&me"]
  1018. [@value="1234.56"]
  1019. '
  1020. );
  1021. }
  1022. public function testPassword()
  1023. {
  1024. $form = $this->factory->createNamed('password', 'na&me', 'foo&bar', array(
  1025. 'property_path' => 'name',
  1026. ));
  1027. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1028. '/input
  1029. [@type="password"]
  1030. [@name="na&me"]
  1031. [@value=""]
  1032. '
  1033. );
  1034. }
  1035. public function testPasswordBoundNotAlwaysEmpty()
  1036. {
  1037. $form = $this->factory->createNamed('password', 'na&me', null, array(
  1038. 'property_path' => 'name',
  1039. 'always_empty' => false,
  1040. ));
  1041. $form->bind('foo&bar');
  1042. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1043. '/input
  1044. [@type="password"]
  1045. [@name="na&me"]
  1046. [@value="foo&bar"]
  1047. '
  1048. );
  1049. }
  1050. public function testPasswordWithMaxLength()
  1051. {
  1052. $form = $this->factory->createNamed('password', 'na&me', 'foo&bar', array(
  1053. 'property_path' => 'name',
  1054. 'max_length' => 123,
  1055. ));
  1056. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1057. '/input
  1058. [@type="password"]
  1059. [@name="na&me"]
  1060. [@value=""]
  1061. [@maxlength="123"]
  1062. '
  1063. );
  1064. }
  1065. public function testPercent()
  1066. {
  1067. $form = $this->factory->createNamed('percent', 'na&me', 0.1, array(
  1068. 'property_path' => 'name',
  1069. ));
  1070. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1071. '/input
  1072. [@type="text"]
  1073. [@name="na&me"]
  1074. [@value="10"]
  1075. [contains(.., "%")]
  1076. '
  1077. );
  1078. }
  1079. public function testCheckedRadio()
  1080. {
  1081. $form = $this->factory->createNamed('radio', 'na&me', true, array(
  1082. 'property_path' => 'name',
  1083. ));
  1084. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1085. '/input
  1086. [@type="radio"]
  1087. [@name="na&me"]
  1088. [@checked="checked"]
  1089. [@value=""]
  1090. '
  1091. );
  1092. }
  1093. public function testCheckedRadioWithValue()
  1094. {
  1095. $form = $this->factory->createNamed('radio', 'na&me', true, array(
  1096. 'property_path' => 'name',
  1097. 'value' => 'foo&bar',
  1098. ));
  1099. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1100. '/input
  1101. [@type="radio"]
  1102. [@name="na&me"]
  1103. [@checked="checked"]
  1104. [@value="foo&bar"]
  1105. '
  1106. );
  1107. }
  1108. public function testUncheckedRadio()
  1109. {
  1110. $form = $this->factory->createNamed('radio', 'na&me', false, array(
  1111. 'property_path' => 'name',
  1112. ));
  1113. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1114. '/input
  1115. [@type="radio"]
  1116. [@name="na&me"]
  1117. [not(@checked)]
  1118. '
  1119. );
  1120. }
  1121. public function testTextarea()
  1122. {
  1123. $form = $this->factory->createNamed('textarea', 'na&me', 'foo&bar', array(
  1124. 'property_path' => 'name',
  1125. ));
  1126. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1127. '/textarea
  1128. [@name="na&me"]
  1129. [.="foo&bar"]
  1130. '
  1131. );
  1132. }
  1133. public function testText()
  1134. {
  1135. $form = $this->factory->createNamed('text', 'na&me', 'foo&bar', array(
  1136. 'property_path' => 'name',
  1137. ));
  1138. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1139. '/input
  1140. [@type="text"]
  1141. [@name="na&me"]
  1142. [@value="foo&bar"]
  1143. [not(@maxlength)]
  1144. '
  1145. );
  1146. }
  1147. public function testTextWithMaxLength()
  1148. {
  1149. $form = $this->factory->createNamed('text', 'na&me', 'foo&bar', array(
  1150. 'property_path' => 'name',
  1151. 'max_length' => 123,
  1152. ));
  1153. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1154. '/input
  1155. [@type="text"]
  1156. [@name="na&me"]
  1157. [@value="foo&bar"]
  1158. [@maxlength="123"]
  1159. '
  1160. );
  1161. }
  1162. public function testSearch()
  1163. {
  1164. $form = $this->factory->createNamed('search', 'na&me', 'foo&bar', array(
  1165. 'property_path' => 'name',
  1166. ));
  1167. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1168. '/input
  1169. [@type="search"]
  1170. [@name="na&me"]
  1171. [@value="foo&bar"]
  1172. [not(@maxlength)]
  1173. '
  1174. );
  1175. }
  1176. public function testTime()
  1177. {
  1178. $form = $this->factory->createNamed('time', 'na&me', '04:05:06', array(
  1179. 'property_path' => 'name',
  1180. 'input' => 'string',
  1181. 'with_seconds' => false,
  1182. ));
  1183. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1184. '/div
  1185. [
  1186. ./select
  1187. [@id="na&me_hour"]
  1188. [@size="1"]
  1189. [./option[@value="4"][@selected="selected"]]
  1190. /following-sibling::select
  1191. [@id="na&me_minute"]
  1192. [@size="1"]
  1193. [./option[@value="5"][@selected="selected"]]
  1194. ]
  1195. [count(./select)=2]
  1196. '
  1197. );
  1198. }
  1199. public function testTimeWithSeconds()
  1200. {
  1201. $form = $this->factory->createNamed('time', 'na&me', '04:05:06', array(
  1202. 'property_path' => 'name',
  1203. 'input' => 'string',
  1204. 'with_seconds' => true,
  1205. ));
  1206. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1207. '/div
  1208. [
  1209. ./select
  1210. [@id="na&me_hour"]
  1211. [@size="1"]
  1212. [./option[@value="4"][@selected="selected"]]
  1213. /following-sibling::select
  1214. [@id="na&me_minute"]
  1215. [@size="1"]
  1216. [./option[@value="5"][@selected="selected"]]
  1217. /following-sibling::select
  1218. [@id="na&me_second"]
  1219. [@size="1"]
  1220. [./option[@value="6"][@selected="selected"]]
  1221. ]
  1222. [count(./select)=3]
  1223. '
  1224. );
  1225. }
  1226. public function testTimeWithEmptyValueGlobal()
  1227. {
  1228. $form = $this->factory->createNamed('time', 'na&me', null, array(
  1229. 'property_path' => 'name',
  1230. 'input' => 'string',
  1231. 'empty_value' => 'Change&Me',
  1232. 'required' => false,
  1233. ));
  1234. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1235. '/div
  1236. [
  1237. ./select
  1238. [@id="na&me_hour"]
  1239. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  1240. /following-sibling::select
  1241. [@id="na&me_minute"]
  1242. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  1243. ]
  1244. [count(./select)=2]
  1245. '
  1246. );
  1247. }
  1248. public function testTimeWithEmptyValueOnYear()
  1249. {
  1250. $form = $this->factory->createNamed('time', 'na&me', null, array(
  1251. 'property_path' => 'name',
  1252. 'input' => 'string',
  1253. 'required' => false,
  1254. 'empty_value' => array('hour' => 'Change&Me'),
  1255. ));
  1256. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1257. '/div
  1258. [
  1259. ./select
  1260. [@id="na&me_hour"]
  1261. [./option[@value=""][.="[trans]Change&Me[/trans]"]]
  1262. /following-sibling::select
  1263. [@id="na&me_minute"]
  1264. [./option[@value="1"]]
  1265. ]
  1266. [count(./select)=2]
  1267. '
  1268. );
  1269. }
  1270. public function testTimezone()
  1271. {
  1272. $form = $this->factory->createNamed('timezone', 'na&me', 'Europe/Vienna', array(
  1273. 'property_path' => 'name',
  1274. ));
  1275. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1276. '/select
  1277. [@name="na&me"]
  1278. [./optgroup
  1279. [@label="Europe"]
  1280. [./option[@value="Europe/Vienna"][@selected="selected"][.="Vienna"]]
  1281. ]
  1282. [count(./optgroup)>10]
  1283. [count(.//option)>200]
  1284. '
  1285. );
  1286. }
  1287. public function testUrl()
  1288. {
  1289. $url = 'http://www.google.com?foo1=bar1&foo2=bar2';
  1290. $form = $this->factory->createNamed('url', 'na&me', $url, array(
  1291. 'property_path' => 'name',
  1292. ));
  1293. $this->assertWidgetMatchesXpath($form->createView(), array(),
  1294. '/input
  1295. [@type="url"]
  1296. [@name="na&me"]
  1297. [@value="http://www.google.com?foo1=bar1&foo2=bar2"]
  1298. '
  1299. );
  1300. }
  1301. public function testCollectionPrototype()
  1302. {
  1303. $form = $this->factory->createNamedBuilder('form', 'na&me', array('items' => array('one', 'two', 'three')))
  1304. ->add('items', 'collection', array('allow_add' => true))
  1305. ->getForm()
  1306. ->createView();
  1307. $html = $this->renderWidget($form);
  1308. $this->assertMatchesXpath($html,
  1309. '//script
  1310. [@id="na&me_items_prototype"]
  1311. [@type="text/html"]
  1312. '
  1313. );
  1314. }
  1315. }