AbstractLayoutTest.php 27 KB

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