AbstractLayoutTest.php 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103
  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. $dispatcher = new EventDispatcher();
  25. $this->csrfProvider = $this->getMock('Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface');
  26. $storage = new \Symfony\Component\HttpFoundation\File\TemporaryStorage('foo', \sys_get_temp_dir());
  27. $this->factory = new FormFactory(array(
  28. new CoreExtension($storage),
  29. new CsrfExtension($this->csrfProvider),
  30. ));
  31. }
  32. protected function assertXpathNodeValue(\DomElement $element, $expression, $nodeValue)
  33. {
  34. $xpath = new \DOMXPath($element->ownerDocument);
  35. $nodeList = $xpath->evaluate($expression);
  36. $this->assertEquals(1, $nodeList->length);
  37. $this->assertEquals($nodeValue, $nodeList->item(0)->nodeValue);
  38. }
  39. protected function assertMatchesXpath($html, $expression, $count = 1)
  40. {
  41. $dom = new \DomDocument('UTF-8');
  42. try {
  43. // Wrap in <root> node so we can load HTML with multiple tags at
  44. // the top level
  45. $dom->loadXml('<root>'.$html.'</root>');
  46. } catch (\Exception $e) {
  47. return $this->fail(sprintf(
  48. "Failed loading HTML:\n\n%s\n\nError: %s",
  49. $html,
  50. $e->getMessage()
  51. ));
  52. }
  53. $xpath = new \DOMXPath($dom);
  54. $nodeList = $xpath->evaluate('/root'.$expression);
  55. if ($nodeList->length != $count) {
  56. $dom->formatOutput = true;
  57. $this->fail(sprintf(
  58. "Failed asserting that \n\n%s\n\nmatches exactly %s. Matches %s in \n\n%s",
  59. $expression,
  60. $count == 1 ? 'once' : $count . ' times',
  61. $nodeList->length == 1 ? 'once' : $nodeList->length . ' times',
  62. // strip away <root> and </root>
  63. substr($dom->saveHTML(), 6, -8)
  64. ));
  65. }
  66. }
  67. protected function assertWidgetMatchesXpath(FormView $view, array $vars, $xpath)
  68. {
  69. // include ampersands everywhere to validate escaping
  70. $html = $this->renderWidget($view, array_merge(array(
  71. 'id' => 'my&id',
  72. 'attr' => array('class' => 'my&class'),
  73. ), $vars));
  74. $xpath = trim($xpath).'
  75. [@id="my&id"]
  76. [@class="my&class"]';
  77. $this->assertMatchesXpath($html, $xpath);
  78. }
  79. abstract protected function renderEnctype(FormView $view);
  80. abstract protected function renderLabel(FormView $view, $label = null, array $vars = array());
  81. abstract protected function renderErrors(FormView $view);
  82. abstract protected function renderWidget(FormView $view, array $vars = array());
  83. abstract protected function renderRow(FormView $view, array $vars = array());
  84. abstract protected function renderRest(FormView $view, array $vars = array());
  85. public function testEnctype()
  86. {
  87. $form = $this->factory->createNamedBuilder('form', 'na&me', null, array(
  88. 'property_path' => 'name',
  89. ))
  90. ->add('file', 'file')
  91. ->getForm();
  92. $this->assertEquals('enctype="multipart/form-data"', $this->renderEnctype($form->createView()));
  93. }
  94. public function testNoEnctype()
  95. {
  96. $form = $this->factory->createNamedBuilder('form', 'na&me', null, array(
  97. 'property_path' => 'name',
  98. ))
  99. ->add('text', 'text')
  100. ->getForm();
  101. $this->assertEquals('', $this->renderEnctype($form->createView()));
  102. }
  103. public function testLabel()
  104. {
  105. $form = $this->factory->createNamed('text', 'na&me', null, array(
  106. 'property_path' => 'name',
  107. ));
  108. $view = $form->createView();
  109. $this->renderWidget($view, array('label' => 'foo'));
  110. $html = $this->renderLabel($view);
  111. $this->assertMatchesXpath($html,
  112. '/label
  113. [@for="na&me"]
  114. [.="[trans]Na&me[/trans]"]
  115. '
  116. );
  117. }
  118. public function testLabelWithCustomTextPassedAsOption()
  119. {
  120. $form = $this->factory->createNamed('text', 'na&me', null, array(
  121. 'property_path' => 'name',
  122. 'label' => 'Custom label',
  123. ));
  124. $html = $this->renderLabel($form->createView());
  125. $this->assertMatchesXpath($html,
  126. '/label
  127. [@for="na&me"]
  128. [.="[trans]Custom label[/trans]"]
  129. '
  130. );
  131. }
  132. public function testLabelWithCustomTextPassedDirectly()
  133. {
  134. $form = $this->factory->createNamed('text', 'na&me', null, array(
  135. 'property_path' => 'name',
  136. ));
  137. $html = $this->renderLabel($form->createView(), 'Custom label');
  138. $this->assertMatchesXpath($html,
  139. '/label
  140. [@for="na&me"]
  141. [.="[trans]Custom label[/trans]"]
  142. '
  143. );
  144. }
  145. public function testLabelWithCustomTextPassedAsOptionAndDirectly()
  146. {
  147. $form = $this->factory->createNamed('text', 'na&me', null, array(
  148. 'property_path' => 'name',
  149. 'label' => 'Custom label',
  150. ));
  151. $html = $this->renderLabel($form->createView(), 'Overridden label');
  152. $this->assertMatchesXpath($html,
  153. '/label
  154. [@for="na&me"]
  155. [.="[trans]Overridden label[/trans]"]
  156. '
  157. );
  158. }
  159. public function testLabelWithCustomOptionsPassedDirectly()
  160. {
  161. $form = $this->factory->createNamed('text', 'na&me', null, array(
  162. 'property_path' => 'name',
  163. ));
  164. $html = $this->renderLabel($form->createView(), null, array(
  165. 'attr' => array(
  166. 'class' => 'my&class'
  167. ),
  168. ));
  169. $this->assertMatchesXpath($html,
  170. '/label
  171. [@for="na&me"]
  172. [@class="my&class"]
  173. '
  174. );
  175. }
  176. public function testLabelWithCustomTextAndCustomOptionsPassedDirectly()
  177. {
  178. $form = $this->factory->createNamed('text', 'na&me', null, array(
  179. 'property_path' => 'name',
  180. ));
  181. $html = $this->renderLabel($form->createView(), 'Custom label', array(
  182. 'attr' => array(
  183. 'class' => 'my&class'
  184. ),
  185. ));
  186. $this->assertMatchesXpath($html,
  187. '/label
  188. [@for="na&me"]
  189. [@class="my&class"]
  190. [.="[trans]Custom label[/trans]"]
  191. '
  192. );
  193. }
  194. public function testErrors()
  195. {
  196. $form = $this->factory->createNamed('text', 'na&me', null, array(
  197. 'property_path' => 'name',
  198. ));
  199. $form->addError(new FormError('Error 1'));
  200. $form->addError(new FormError('Error 2'));
  201. $view = $form->createView();
  202. $html = $this->renderErrors($view);
  203. $this->assertMatchesXpath($html,
  204. '/ul
  205. [
  206. ./li[.="[trans]Error 1[/trans]"]
  207. /following-sibling::li[.="[trans]Error 2[/trans]"]
  208. ]
  209. [count(./li)=2]
  210. '
  211. );
  212. }
  213. public function testWidgetById()
  214. {
  215. $form = $this->factory->createNamed('text', 'text_id');
  216. $html = $this->renderWidget($form->createView());
  217. $this->assertMatchesXpath($html,
  218. '/div
  219. [
  220. ./input
  221. [@type="text"]
  222. [@id="text_id"]
  223. ]
  224. [@id="container"]
  225. '
  226. );
  227. }
  228. public function testCheckedCheckbox()
  229. {
  230. $form = $this->factory->createNamed('checkbox', 'na&me', true, array(
  231. 'property_path' => 'name',
  232. ));
  233. $this->assertWidgetMatchesXpath($form->createView(), array(),
  234. '/input
  235. [@type="checkbox"]
  236. [@name="na&me"]
  237. [@checked="checked"]
  238. [@value="1"]
  239. '
  240. );
  241. }
  242. public function testCheckedCheckboxWithValue()
  243. {
  244. $form = $this->factory->createNamed('checkbox', 'na&me', true, array(
  245. 'property_path' => 'name',
  246. 'value' => 'foo&bar',
  247. ));
  248. $this->assertWidgetMatchesXpath($form->createView(), array(),
  249. '/input
  250. [@type="checkbox"]
  251. [@name="na&me"]
  252. [@checked="checked"]
  253. [@value="foo&bar"]
  254. '
  255. );
  256. }
  257. public function testUncheckedCheckbox()
  258. {
  259. $form = $this->factory->createNamed('checkbox', 'na&me', false, array(
  260. 'property_path' => 'name',
  261. ));
  262. $this->assertWidgetMatchesXpath($form->createView(), array(),
  263. '/input
  264. [@type="checkbox"]
  265. [@name="na&me"]
  266. [not(@checked)]
  267. '
  268. );
  269. }
  270. public function testSingleChoice()
  271. {
  272. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  273. 'property_path' => 'name',
  274. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  275. 'multiple' => false,
  276. 'expanded' => false,
  277. ));
  278. $this->assertWidgetMatchesXpath($form->createView(), array(),
  279. '/select
  280. [@name="na&me"]
  281. [
  282. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  283. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  284. ]
  285. [count(./option)=2]
  286. '
  287. );
  288. }
  289. public function testSingleChoiceWithPreferred()
  290. {
  291. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  292. 'property_path' => 'name',
  293. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  294. 'preferred_choices' => array('&b'),
  295. 'multiple' => false,
  296. 'expanded' => false,
  297. ));
  298. $this->assertWidgetMatchesXpath($form->createView(), array('separator' => '-- sep --'),
  299. '/select
  300. [@name="na&me"]
  301. [
  302. ./option[@value="&b"][not(@selected)][.="Choice&B"]
  303. /following-sibling::option[@disabled="disabled"][not(@selected)][.="-- sep --"]
  304. /following-sibling::option[@value="&a"][@selected="selected"][.="Choice&A"]
  305. ]
  306. [count(./option)=3]
  307. '
  308. );
  309. }
  310. public function testSingleChoiceNonRequired()
  311. {
  312. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  313. 'property_path' => 'name',
  314. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  315. 'required' => false,
  316. 'multiple' => false,
  317. 'expanded' => false,
  318. ));
  319. $this->assertWidgetMatchesXpath($form->createView(), array(),
  320. '/select
  321. [@name="na&me"]
  322. [
  323. ./option[@value=""][.=""]
  324. /following-sibling::option[@value="&a"][@selected="selected"][.="Choice&A"]
  325. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  326. ]
  327. [count(./option)=3]
  328. '
  329. );
  330. }
  331. public function testSingleChoiceGrouped()
  332. {
  333. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  334. 'property_path' => 'name',
  335. 'choices' => array(
  336. 'Group&1' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  337. 'Group&2' => array('&c' => 'Choice&C'),
  338. ),
  339. 'multiple' => false,
  340. 'expanded' => false,
  341. ));
  342. $this->assertWidgetMatchesXpath($form->createView(), array(),
  343. '/select
  344. [@name="na&me"]
  345. [./optgroup[@label="Group&1"]
  346. [
  347. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  348. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  349. ]
  350. [count(./option)=2]
  351. ]
  352. [./optgroup[@label="Group&2"]
  353. [./option[@value="&c"][not(@selected)][.="Choice&C"]]
  354. [count(./option)=1]
  355. ]
  356. [count(./optgroup)=2]
  357. '
  358. );
  359. }
  360. public function testMultipleChoice()
  361. {
  362. $form = $this->factory->createNamed('choice', 'na&me', array('&a'), array(
  363. 'property_path' => 'name',
  364. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  365. 'multiple' => true,
  366. 'expanded' => false,
  367. ));
  368. $this->assertWidgetMatchesXpath($form->createView(), array(),
  369. '/select
  370. [@name="na&me[]"]
  371. [@multiple="multiple"]
  372. [
  373. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  374. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  375. ]
  376. [count(./option)=2]
  377. '
  378. );
  379. }
  380. public function testMultipleChoiceNonRequired()
  381. {
  382. $form = $this->factory->createNamed('choice', 'na&me', array('&a'), array(
  383. 'property_path' => 'name',
  384. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  385. 'required' => false,
  386. 'multiple' => true,
  387. 'expanded' => false,
  388. ));
  389. $this->assertWidgetMatchesXpath($form->createView(), array(),
  390. '/select
  391. [@name="na&me[]"]
  392. [@multiple="multiple"]
  393. [
  394. ./option[@value="&a"][@selected="selected"][.="Choice&A"]
  395. /following-sibling::option[@value="&b"][not(@selected)][.="Choice&B"]
  396. ]
  397. [count(./option)=2]
  398. '
  399. );
  400. }
  401. public function testSingleChoiceExpanded()
  402. {
  403. $form = $this->factory->createNamed('choice', 'na&me', '&a', array(
  404. 'property_path' => 'name',
  405. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B'),
  406. 'multiple' => false,
  407. 'expanded' => true,
  408. ));
  409. $this->assertWidgetMatchesXpath($form->createView(), array(),
  410. '/div
  411. [
  412. ./input[@type="radio"][@name="na&me"][@id="na&me_&a"][@checked]
  413. /following-sibling::label[@for="na&me_&a"][.="[trans]Choice&A[/trans]"]
  414. /following-sibling::input[@type="radio"][@name="na&me"][@id="na&me_&b"][not(@checked)]
  415. /following-sibling::label[@for="na&me_&b"][.="[trans]Choice&B[/trans]"]
  416. ]
  417. [count(./input)=2]
  418. '
  419. );
  420. }
  421. public function testMultipleChoiceExpanded()
  422. {
  423. $form = $this->factory->createNamed('choice', 'na&me', array('&a', '&c'), array(
  424. 'property_path' => 'name',
  425. 'choices' => array('&a' => 'Choice&A', '&b' => 'Choice&B', '&c' => 'Choice&C'),
  426. 'multiple' => true,
  427. 'expanded' => true,
  428. 'required' => true,
  429. ));
  430. $this->assertWidgetMatchesXpath($form->createView(), array(),
  431. '/div
  432. [
  433. ./input[@type="checkbox"][@name="na&me[&a]"][@id="na&me_&a"][@checked][not(@required)]
  434. /following-sibling::label[@for="na&me_&a"][.="[trans]Choice&A[/trans]"]
  435. /following-sibling::input[@type="checkbox"][@name="na&me[&b]"][@id="na&me_&b"][not(@checked)][not(@required)]
  436. /following-sibling::label[@for="na&me_&b"][.="[trans]Choice&B[/trans]"]
  437. /following-sibling::input[@type="checkbox"][@name="na&me[&c]"][@id="na&me_&c"][@checked][not(@required)]
  438. /following-sibling::label[@for="na&me_&c"][.="[trans]Choice&C[/trans]"]
  439. ]
  440. [count(./input)=3]
  441. '
  442. );
  443. }
  444. public function testCountry()
  445. {
  446. $form = $this->factory->createNamed('country', 'na&me', 'AT', array(
  447. 'property_path' => 'name',
  448. ));
  449. $this->assertWidgetMatchesXpath($form->createView(), array(),
  450. '/select
  451. [@name="na&me"]
  452. [./option[@value="AT"][@selected="selected"][.="Austria"]]
  453. [count(./option)>200]
  454. '
  455. );
  456. }
  457. public function testCsrf()
  458. {
  459. $this->csrfProvider->expects($this->any())
  460. ->method('generateCsrfToken')
  461. ->will($this->returnValue('foo&bar'));
  462. $form = $this->factory->createNamed('csrf', 'na&me', null, array(
  463. 'property_path' => 'name',
  464. ));
  465. $this->assertWidgetMatchesXpath($form->createView(), array(),
  466. '/input
  467. [@type="hidden"]
  468. [@value="foo&bar"]
  469. '
  470. );
  471. }
  472. public function testDateTime()
  473. {
  474. $form = $this->factory->createNamed('datetime', 'na&me', '2011-02-03 04:05:06', array(
  475. 'property_path' => 'name',
  476. 'input' => 'string',
  477. 'with_seconds' => false,
  478. ));
  479. $this->assertWidgetMatchesXpath($form->createView(), array(),
  480. '/div
  481. [
  482. ./div
  483. [@id="na&me_date"]
  484. [
  485. ./select
  486. [@id="na&me_date_month"]
  487. [./option[@value="2"][@selected="selected"]]
  488. /following-sibling::select
  489. [@id="na&me_date_day"]
  490. [./option[@value="3"][@selected="selected"]]
  491. /following-sibling::select
  492. [@id="na&me_date_year"]
  493. [./option[@value="2011"][@selected="selected"]]
  494. ]
  495. /following-sibling::div
  496. [@id="na&me_time"]
  497. [
  498. ./select
  499. [@id="na&me_time_hour"]
  500. [./option[@value="4"][@selected="selected"]]
  501. /following-sibling::select
  502. [@id="na&me_time_minute"]
  503. [./option[@value="5"][@selected="selected"]]
  504. ]
  505. ]
  506. [count(.//select)=5]
  507. '
  508. );
  509. }
  510. public function testDateTimeWithSeconds()
  511. {
  512. $form = $this->factory->createNamed('datetime', 'na&me', '2011-02-03 04:05:06', array(
  513. 'property_path' => 'name',
  514. 'input' => 'string',
  515. 'with_seconds' => true,
  516. ));
  517. $this->assertWidgetMatchesXpath($form->createView(), array(),
  518. '/div
  519. [
  520. ./div
  521. [@id="na&me_date"]
  522. [
  523. ./select
  524. [@id="na&me_date_month"]
  525. [./option[@value="2"][@selected="selected"]]
  526. /following-sibling::select
  527. [@id="na&me_date_day"]
  528. [./option[@value="3"][@selected="selected"]]
  529. /following-sibling::select
  530. [@id="na&me_date_year"]
  531. [./option[@value="2011"][@selected="selected"]]
  532. ]
  533. /following-sibling::div
  534. [@id="na&me_time"]
  535. [
  536. ./select
  537. [@id="na&me_time_hour"]
  538. [./option[@value="4"][@selected="selected"]]
  539. /following-sibling::select
  540. [@id="na&me_time_minute"]
  541. [./option[@value="5"][@selected="selected"]]
  542. /following-sibling::select
  543. [@id="na&me_time_second"]
  544. [./option[@value="6"][@selected="selected"]]
  545. ]
  546. ]
  547. [count(.//select)=6]
  548. '
  549. );
  550. }
  551. public function testDateChoice()
  552. {
  553. $form = $this->factory->createNamed('date', 'na&me', '2011-02-03', array(
  554. 'property_path' => 'name',
  555. 'input' => 'string',
  556. 'widget' => 'choice',
  557. ));
  558. $this->assertWidgetMatchesXpath($form->createView(), array(),
  559. '/div
  560. [
  561. ./select
  562. [@id="na&me_month"]
  563. [./option[@value="2"][@selected="selected"]]
  564. /following-sibling::select
  565. [@id="na&me_day"]
  566. [./option[@value="3"][@selected="selected"]]
  567. /following-sibling::select
  568. [@id="na&me_year"]
  569. [./option[@value="2011"][@selected="selected"]]
  570. ]
  571. [count(./select)=3]
  572. '
  573. );
  574. }
  575. public function testDateText()
  576. {
  577. $form = $this->factory->createNamed('date', 'na&me', '2011-02-03', array(
  578. 'property_path' => 'name',
  579. 'input' => 'string',
  580. 'widget' => 'text',
  581. ));
  582. $this->assertWidgetMatchesXpath($form->createView(), array(),
  583. '/div
  584. [
  585. ./input
  586. [@id="na&me_month"]
  587. [@type="text"]
  588. [@value="2"]
  589. /following-sibling::input
  590. [@id="na&me_day"]
  591. [@type="text"]
  592. [@value="3"]
  593. /following-sibling::input
  594. [@id="na&me_year"]
  595. [@type="text"]
  596. [@value="2011"]
  597. ]
  598. [count(./input)=3]
  599. '
  600. );
  601. }
  602. public function testDateSingleText()
  603. {
  604. $form = $this->factory->createNamed('date', 'na&me', '2011-02-03', array(
  605. 'property_path' => 'name',
  606. 'input' => 'string',
  607. 'widget' => 'single_text',
  608. ));
  609. $this->assertWidgetMatchesXpath($form->createView(), array(),
  610. '/input
  611. [@type="text"]
  612. [@name="na&me"]
  613. [@value="Feb 3, 2011"]
  614. '
  615. );
  616. }
  617. public function testEmail()
  618. {
  619. $form = $this->factory->createNamed('email', 'na&me', 'foo&bar', array(
  620. 'property_path' => 'name',
  621. ));
  622. $this->assertWidgetMatchesXpath($form->createView(), array(),
  623. '/input
  624. [@type="email"]
  625. [@name="na&me"]
  626. [@value="foo&bar"]
  627. [not(@maxlength)]
  628. '
  629. );
  630. }
  631. public function testEmailWithMaxLength()
  632. {
  633. $form = $this->factory->createNamed('email', 'na&me', 'foo&bar', array(
  634. 'property_path' => 'name',
  635. 'max_length' => 123,
  636. ));
  637. $this->assertWidgetMatchesXpath($form->createView(), array(),
  638. '/input
  639. [@type="email"]
  640. [@name="na&me"]
  641. [@value="foo&bar"]
  642. [@maxlength="123"]
  643. '
  644. );
  645. }
  646. public function testFile()
  647. {
  648. $form = $this->factory->createNamed('file', 'na&me', null, array(
  649. 'property_path' => 'name',
  650. ));
  651. $this->assertWidgetMatchesXpath($form->createView(), array(),
  652. '/div
  653. [
  654. ./input[@type="file"][@id="na&me_file"]
  655. /following-sibling::input[@type="hidden"][@id="na&me_token"]
  656. /following-sibling::input[@type="hidden"][@id="na&me_name"]
  657. /following-sibling::input[@type="hidden"][@id="na&me_originalName"]
  658. ]
  659. [count(./input)=4]
  660. '
  661. );
  662. }
  663. public function testHidden()
  664. {
  665. $form = $this->factory->createNamed('hidden', 'na&me', 'foo&bar', array(
  666. 'property_path' => 'name',
  667. ));
  668. $this->assertWidgetMatchesXpath($form->createView(), array(),
  669. '/input
  670. [@type="hidden"]
  671. [@name="na&me"]
  672. [@value="foo&bar"]
  673. '
  674. );
  675. }
  676. public function testInteger()
  677. {
  678. $form = $this->factory->createNamed('integer', 'na&me', 123, array(
  679. 'property_path' => 'name',
  680. ));
  681. $this->assertWidgetMatchesXpath($form->createView(), array(),
  682. '/input
  683. [@type="number"]
  684. [@name="na&me"]
  685. [@value="123"]
  686. '
  687. );
  688. }
  689. public function testLanguage()
  690. {
  691. $form = $this->factory->createNamed('language', 'na&me', 'de', array(
  692. 'property_path' => 'name',
  693. ));
  694. $this->assertWidgetMatchesXpath($form->createView(), array(),
  695. '/select
  696. [@name="na&me"]
  697. [./option[@value="de"][@selected="selected"][.="German"]]
  698. [count(./option)>200]
  699. '
  700. );
  701. }
  702. public function testLocale()
  703. {
  704. $form = $this->factory->createNamed('locale', 'na&me', 'de_AT', array(
  705. 'property_path' => 'name',
  706. ));
  707. $this->assertWidgetMatchesXpath($form->createView(), array(),
  708. '/select
  709. [@name="na&me"]
  710. [./option[@value="de_AT"][@selected="selected"][.="German (Austria)"]]
  711. [count(./option)>200]
  712. '
  713. );
  714. }
  715. public function testMoney()
  716. {
  717. $form = $this->factory->createNamed('money', 'na&me', 1234.56, array(
  718. 'property_path' => 'name',
  719. 'currency' => 'EUR',
  720. ));
  721. $this->assertWidgetMatchesXpath($form->createView(), array(),
  722. '/input
  723. [@type="text"]
  724. [@name="na&me"]
  725. [@value="1234.56"]
  726. [contains(.., "€")]
  727. '
  728. );
  729. }
  730. public function testNumber()
  731. {
  732. $form = $this->factory->createNamed('number', 'na&me', 1234.56, array(
  733. 'property_path' => 'name',
  734. ));
  735. $this->assertWidgetMatchesXpath($form->createView(), array(),
  736. '/input
  737. [@type="text"]
  738. [@name="na&me"]
  739. [@value="1234.56"]
  740. '
  741. );
  742. }
  743. public function testPassword()
  744. {
  745. $form = $this->factory->createNamed('password', 'na&me', 'foo&bar', array(
  746. 'property_path' => 'name',
  747. ));
  748. $this->assertWidgetMatchesXpath($form->createView(), array(),
  749. '/input
  750. [@type="password"]
  751. [@name="na&me"]
  752. [@value=""]
  753. '
  754. );
  755. }
  756. public function testPasswordBoundNotAlwaysEmpty()
  757. {
  758. $form = $this->factory->createNamed('password', 'na&me', null, array(
  759. 'property_path' => 'name',
  760. 'always_empty' => false,
  761. ));
  762. $form->bind('foo&bar');
  763. $this->assertWidgetMatchesXpath($form->createView(), array(),
  764. '/input
  765. [@type="password"]
  766. [@name="na&me"]
  767. [@value="foo&bar"]
  768. '
  769. );
  770. }
  771. public function testPasswordWithMaxLength()
  772. {
  773. $form = $this->factory->createNamed('password', 'na&me', 'foo&bar', array(
  774. 'property_path' => 'name',
  775. 'max_length' => 123,
  776. ));
  777. $this->assertWidgetMatchesXpath($form->createView(), array(),
  778. '/input
  779. [@type="password"]
  780. [@name="na&me"]
  781. [@value=""]
  782. [@maxlength="123"]
  783. '
  784. );
  785. }
  786. public function testPercent()
  787. {
  788. $form = $this->factory->createNamed('percent', 'na&me', 0.1, array(
  789. 'property_path' => 'name',
  790. ));
  791. $this->assertWidgetMatchesXpath($form->createView(), array(),
  792. '/input
  793. [@type="text"]
  794. [@name="na&me"]
  795. [@value="10"]
  796. [contains(.., "%")]
  797. '
  798. );
  799. }
  800. public function testCheckedRadio()
  801. {
  802. $form = $this->factory->createNamed('radio', 'na&me', true, array(
  803. 'property_path' => 'name',
  804. ));
  805. $this->assertWidgetMatchesXpath($form->createView(), array(),
  806. '/input
  807. [@type="radio"]
  808. [@name="na&me"]
  809. [@checked="checked"]
  810. [@value=""]
  811. '
  812. );
  813. }
  814. public function testCheckedRadioWithValue()
  815. {
  816. $form = $this->factory->createNamed('radio', 'na&me', true, array(
  817. 'property_path' => 'name',
  818. 'value' => 'foo&bar',
  819. ));
  820. $this->assertWidgetMatchesXpath($form->createView(), array(),
  821. '/input
  822. [@type="radio"]
  823. [@name="na&me"]
  824. [@checked="checked"]
  825. [@value="foo&bar"]
  826. '
  827. );
  828. }
  829. public function testUncheckedRadio()
  830. {
  831. $form = $this->factory->createNamed('radio', 'na&me', false, array(
  832. 'property_path' => 'name',
  833. ));
  834. $this->assertWidgetMatchesXpath($form->createView(), array(),
  835. '/input
  836. [@type="radio"]
  837. [@name="na&me"]
  838. [not(@checked)]
  839. '
  840. );
  841. }
  842. public function testTextarea()
  843. {
  844. $form = $this->factory->createNamed('textarea', 'na&me', 'foo&bar', array(
  845. 'property_path' => 'name',
  846. ));
  847. $this->assertWidgetMatchesXpath($form->createView(), array(),
  848. '/textarea
  849. [@name="na&me"]
  850. [.="foo&bar"]
  851. '
  852. );
  853. }
  854. public function testText()
  855. {
  856. $form = $this->factory->createNamed('text', 'na&me', 'foo&bar', array(
  857. 'property_path' => 'name',
  858. ));
  859. $this->assertWidgetMatchesXpath($form->createView(), array(),
  860. '/input
  861. [@type="text"]
  862. [@name="na&me"]
  863. [@value="foo&bar"]
  864. [not(@maxlength)]
  865. '
  866. );
  867. }
  868. public function testTextWithMaxLength()
  869. {
  870. $form = $this->factory->createNamed('text', 'na&me', 'foo&bar', array(
  871. 'property_path' => 'name',
  872. 'max_length' => 123,
  873. ));
  874. $this->assertWidgetMatchesXpath($form->createView(), array(),
  875. '/input
  876. [@type="text"]
  877. [@name="na&me"]
  878. [@value="foo&bar"]
  879. [@maxlength="123"]
  880. '
  881. );
  882. }
  883. public function testSearch()
  884. {
  885. $form = $this->factory->createNamed('search', 'na&me', 'foo&bar', array(
  886. 'property_path' => 'name',
  887. ));
  888. $this->assertWidgetMatchesXpath($form->createView(), array(),
  889. '/input
  890. [@type="search"]
  891. [@name="na&me"]
  892. [@value="foo&bar"]
  893. [not(@maxlength)]
  894. '
  895. );
  896. }
  897. public function testTime()
  898. {
  899. $form = $this->factory->createNamed('time', 'na&me', '04:05:06', array(
  900. 'property_path' => 'name',
  901. 'input' => 'string',
  902. 'with_seconds' => false,
  903. ));
  904. $this->assertWidgetMatchesXpath($form->createView(), array(),
  905. '/div
  906. [
  907. ./select
  908. [@id="na&me_hour"]
  909. [@size="1"]
  910. [./option[@value="4"][@selected="selected"]]
  911. /following-sibling::select
  912. [@id="na&me_minute"]
  913. [@size="1"]
  914. [./option[@value="5"][@selected="selected"]]
  915. ]
  916. [count(./select)=2]
  917. '
  918. );
  919. }
  920. public function testTimeWithSeconds()
  921. {
  922. $form = $this->factory->createNamed('time', 'na&me', '04:05:06', array(
  923. 'property_path' => 'name',
  924. 'input' => 'string',
  925. 'with_seconds' => true,
  926. ));
  927. $this->assertWidgetMatchesXpath($form->createView(), array(),
  928. '/div
  929. [
  930. ./select
  931. [@id="na&me_hour"]
  932. [@size="1"]
  933. [./option[@value="4"][@selected="selected"]]
  934. /following-sibling::select
  935. [@id="na&me_minute"]
  936. [@size="1"]
  937. [./option[@value="5"][@selected="selected"]]
  938. /following-sibling::select
  939. [@id="na&me_second"]
  940. [@size="1"]
  941. [./option[@value="6"][@selected="selected"]]
  942. ]
  943. [count(./select)=3]
  944. '
  945. );
  946. }
  947. public function testTimezone()
  948. {
  949. $form = $this->factory->createNamed('timezone', 'na&me', 'Europe/Vienna', array(
  950. 'property_path' => 'name',
  951. ));
  952. $this->assertWidgetMatchesXpath($form->createView(), array(),
  953. '/select
  954. [@name="na&me"]
  955. [./optgroup
  956. [@label="Europe"]
  957. [./option[@value="Europe/Vienna"][@selected="selected"][.="Vienna"]]
  958. ]
  959. [count(./optgroup)>10]
  960. [count(.//option)>200]
  961. '
  962. );
  963. }
  964. public function testUrl()
  965. {
  966. $url = 'http://www.google.com?foo1=bar1&foo2=bar2';
  967. $form = $this->factory->createNamed('url', 'na&me', $url, array(
  968. 'property_path' => 'name',
  969. ));
  970. $this->assertWidgetMatchesXpath($form->createView(), array(),
  971. '/input
  972. [@type="url"]
  973. [@name="na&me"]
  974. [@value="http://www.google.com?foo1=bar1&foo2=bar2"]
  975. '
  976. );
  977. }
  978. }