AbstractLayoutTest.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979
  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. 'Group1' => array('a' => 'Choice A', 'b' => 'Choice B'),
  266. 'Group2' => 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="Group1"]
  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="Group2"]
  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. ));
  363. $this->assertWidgetMatchesXpath($form->createView(), array(),
  364. '/div
  365. [
  366. ./input[@type="checkbox"][@name="na&me[a]"][@id="na&me_a"][@checked]
  367. /following-sibling::label[@for="na&me_a"][.="[trans]Choice A[/trans]"]
  368. /following-sibling::input[@type="checkbox"][@name="na&me[b]"][@id="na&me_b"][not(@checked)]
  369. /following-sibling::label[@for="na&me_b"][.="[trans]Choice B[/trans]"]
  370. /following-sibling::input[@type="checkbox"][@name="na&me[c]"][@id="na&me_c"][@checked]
  371. /following-sibling::label[@for="na&me_c"][.="[trans]Choice C[/trans]"]
  372. ]
  373. [count(./input)=3]
  374. '
  375. );
  376. }
  377. public function testCountry()
  378. {
  379. $form = $this->factory->create('country', 'na&me', array(
  380. 'property_path' => 'name',
  381. 'data' => 'AT',
  382. ));
  383. $this->assertWidgetMatchesXpath($form->createView(), array(),
  384. '/select
  385. [@name="na&me"]
  386. [./option[@value="AT"][@selected="selected"][.="Austria"]]
  387. [count(./option)>200]
  388. '
  389. );
  390. }
  391. public function testCsrf()
  392. {
  393. $this->csrfProvider->expects($this->any())
  394. ->method('generateCsrfToken')
  395. ->will($this->returnValue('foo&bar'));
  396. $form = $this->factory->create('csrf', 'na&me', array('property_path' => 'name'));
  397. $this->assertWidgetMatchesXpath($form->createView(), array(),
  398. '/input
  399. [@type="hidden"]
  400. [@value="foo&bar"]
  401. '
  402. );
  403. }
  404. public function testCsrfWithNonRootParent()
  405. {
  406. $form = $this->factory->create('csrf', 'na&me', array('property_path' => 'name'));
  407. $form->setParent($this->factory->create('form'));
  408. $form->getParent()->setParent($this->factory->create('form'));
  409. $html = $this->renderWidget($form->createView());
  410. $this->assertEquals('', trim($html));
  411. }
  412. public function testDateTime()
  413. {
  414. $form = $this->factory->create('datetime', 'na&me', array(
  415. 'property_path' => 'name',
  416. 'data' => '2011-02-03 04:05:06',
  417. 'input' => 'string',
  418. 'with_seconds' => false,
  419. ));
  420. $this->assertWidgetMatchesXpath($form->createView(), array(),
  421. '/div
  422. [
  423. ./div
  424. [@id="na&me_date"]
  425. [
  426. ./select
  427. [@id="na&me_date_month"]
  428. [./option[@value="2"][@selected="selected"]]
  429. /following-sibling::select
  430. [@id="na&me_date_day"]
  431. [./option[@value="3"][@selected="selected"]]
  432. /following-sibling::select
  433. [@id="na&me_date_year"]
  434. [./option[@value="2011"][@selected="selected"]]
  435. ]
  436. /following-sibling::div
  437. [@id="na&me_time"]
  438. [
  439. ./select
  440. [@id="na&me_time_hour"]
  441. [./option[@value="4"][@selected="selected"]]
  442. /following-sibling::select
  443. [@id="na&me_time_minute"]
  444. [./option[@value="5"][@selected="selected"]]
  445. ]
  446. ]
  447. [count(.//select)=5]
  448. '
  449. );
  450. }
  451. public function testDateTimeWithSeconds()
  452. {
  453. $form = $this->factory->create('datetime', 'na&me', array(
  454. 'property_path' => 'name',
  455. 'data' => '2011-02-03 04:05:06',
  456. 'input' => 'string',
  457. 'with_seconds' => true,
  458. ));
  459. $this->assertWidgetMatchesXpath($form->createView(), array(),
  460. '/div
  461. [
  462. ./div
  463. [@id="na&me_date"]
  464. [
  465. ./select
  466. [@id="na&me_date_month"]
  467. [./option[@value="2"][@selected="selected"]]
  468. /following-sibling::select
  469. [@id="na&me_date_day"]
  470. [./option[@value="3"][@selected="selected"]]
  471. /following-sibling::select
  472. [@id="na&me_date_year"]
  473. [./option[@value="2011"][@selected="selected"]]
  474. ]
  475. /following-sibling::div
  476. [@id="na&me_time"]
  477. [
  478. ./select
  479. [@id="na&me_time_hour"]
  480. [./option[@value="4"][@selected="selected"]]
  481. /following-sibling::select
  482. [@id="na&me_time_minute"]
  483. [./option[@value="5"][@selected="selected"]]
  484. /following-sibling::select
  485. [@id="na&me_time_second"]
  486. [./option[@value="6"][@selected="selected"]]
  487. ]
  488. ]
  489. [count(.//select)=6]
  490. '
  491. );
  492. }
  493. public function testDateChoice()
  494. {
  495. $form = $this->factory->create('date', 'na&me', array(
  496. 'property_path' => 'name',
  497. 'data' => '2011-02-03',
  498. 'input' => 'string',
  499. 'widget' => 'choice',
  500. ));
  501. $this->assertWidgetMatchesXpath($form->createView(), array(),
  502. '/div
  503. [
  504. ./select
  505. [@id="na&me_month"]
  506. [./option[@value="2"][@selected="selected"]]
  507. /following-sibling::select
  508. [@id="na&me_day"]
  509. [./option[@value="3"][@selected="selected"]]
  510. /following-sibling::select
  511. [@id="na&me_year"]
  512. [./option[@value="2011"][@selected="selected"]]
  513. ]
  514. [count(./select)=3]
  515. '
  516. );
  517. }
  518. public function testDateText()
  519. {
  520. $form = $this->factory->create('date', 'na&me', array(
  521. 'property_path' => 'name',
  522. 'data' => '2011-02-03',
  523. 'input' => 'string',
  524. 'widget' => 'text',
  525. ));
  526. $this->assertWidgetMatchesXpath($form->createView(), array(),
  527. '/input
  528. [@type="text"]
  529. [@name="na&me"]
  530. [@value="Feb 3, 2011"]
  531. '
  532. );
  533. }
  534. public function testFile()
  535. {
  536. $form = $this->factory->create('file', 'na&me', array('property_path' => 'name'));
  537. $this->assertWidgetMatchesXpath($form->createView(), array(),
  538. '/div
  539. [
  540. ./input[@type="file"][@id="na&me_file"]
  541. /following-sibling::input[@type="hidden"][@id="na&me_token"]
  542. /following-sibling::input[@type="hidden"][@id="na&me_name"]
  543. ]
  544. [count(./input)=3]
  545. '
  546. );
  547. }
  548. public function testHidden()
  549. {
  550. $form = $this->factory->create('hidden', 'na&me', array(
  551. 'property_path' => 'name',
  552. 'data' => 'foo&bar',
  553. ));
  554. $this->assertWidgetMatchesXpath($form->createView(), array(),
  555. '/input
  556. [@type="hidden"]
  557. [@name="na&me"]
  558. [@value="foo&bar"]
  559. '
  560. );
  561. }
  562. public function testInteger()
  563. {
  564. $form = $this->factory->create('integer', 'na&me', array(
  565. 'property_path' => 'name',
  566. 'data' => '123',
  567. ));
  568. $this->assertWidgetMatchesXpath($form->createView(), array(),
  569. '/input
  570. [@type="number"]
  571. [@name="na&me"]
  572. [@value="123"]
  573. '
  574. );
  575. }
  576. public function testLanguage()
  577. {
  578. $form = $this->factory->create('language', 'na&me', array(
  579. 'property_path' => 'name',
  580. 'data' => 'de',
  581. ));
  582. $this->assertWidgetMatchesXpath($form->createView(), array(),
  583. '/select
  584. [@name="na&me"]
  585. [./option[@value="de"][@selected="selected"][.="German"]]
  586. [count(./option)>200]
  587. '
  588. );
  589. }
  590. public function testLocale()
  591. {
  592. $form = $this->factory->create('locale', 'na&me', array(
  593. 'property_path' => 'name',
  594. 'data' => 'de_AT',
  595. ));
  596. $this->assertWidgetMatchesXpath($form->createView(), array(),
  597. '/select
  598. [@name="na&me"]
  599. [./option[@value="de_AT"][@selected="selected"][.="German (Austria)"]]
  600. [count(./option)>200]
  601. '
  602. );
  603. }
  604. public function testMoney()
  605. {
  606. $form = $this->factory->create('money', 'na&me', array(
  607. 'property_path' => 'name',
  608. 'data' => 1234.56,
  609. 'currency' => 'EUR',
  610. ));
  611. $this->assertWidgetMatchesXpath($form->createView(), array(),
  612. '/input
  613. [@type="text"]
  614. [@name="na&me"]
  615. [@value="1234.56"]
  616. [contains(.., "€")]
  617. '
  618. );
  619. }
  620. public function testNumber()
  621. {
  622. $form = $this->factory->create('number', 'na&me', array(
  623. 'property_path' => 'name',
  624. 'data' => 1234.56,
  625. ));
  626. $this->assertWidgetMatchesXpath($form->createView(), array(),
  627. '/input
  628. [@type="text"]
  629. [@name="na&me"]
  630. [@value="1234.56"]
  631. '
  632. );
  633. }
  634. public function testPassword()
  635. {
  636. $form = $this->factory->create('password', 'na&me', array(
  637. 'property_path' => 'name',
  638. 'data' => 'foo&bar',
  639. ));
  640. $this->assertWidgetMatchesXpath($form->createView(), array(),
  641. '/input
  642. [@type="password"]
  643. [@name="na&me"]
  644. [@value=""]
  645. '
  646. );
  647. }
  648. public function testPasswordBoundNotAlwaysEmpty()
  649. {
  650. $form = $this->factory->create('password', 'na&me', array(
  651. 'property_path' => 'name',
  652. 'always_empty' => false,
  653. ));
  654. $form->bind('foo&bar');
  655. $this->assertWidgetMatchesXpath($form->createView(), array(),
  656. '/input
  657. [@type="password"]
  658. [@name="na&me"]
  659. [@value="foo&bar"]
  660. '
  661. );
  662. }
  663. public function testPasswordWithMaxLength()
  664. {
  665. $form = $this->factory->create('password', 'na&me', array(
  666. 'property_path' => 'name',
  667. 'data' => 'foo&bar',
  668. 'max_length' => 123,
  669. ));
  670. $this->assertWidgetMatchesXpath($form->createView(), array(),
  671. '/input
  672. [@type="password"]
  673. [@name="na&me"]
  674. [@value=""]
  675. [@maxlength="123"]
  676. '
  677. );
  678. }
  679. public function testPercent()
  680. {
  681. $form = $this->factory->create('percent', 'na&me', array(
  682. 'property_path' => 'name',
  683. 'data' => 0.1,
  684. ));
  685. $this->assertWidgetMatchesXpath($form->createView(), array(),
  686. '/input
  687. [@type="text"]
  688. [@name="na&me"]
  689. [@value="10"]
  690. [contains(.., "%")]
  691. '
  692. );
  693. }
  694. public function testCheckedRadio()
  695. {
  696. $form = $this->factory->create('radio', 'na&me', array(
  697. 'property_path' => 'name',
  698. 'data' => true,
  699. ));
  700. $this->assertWidgetMatchesXpath($form->createView(), array(),
  701. '/input
  702. [@type="radio"]
  703. [@name="na&me"]
  704. [@checked="checked"]
  705. [@value=""]
  706. '
  707. );
  708. }
  709. public function testCheckedRadioWithValue()
  710. {
  711. $form = $this->factory->create('radio', 'na&me', array(
  712. 'property_path' => 'name',
  713. 'data' => true,
  714. 'value' => 'foo&bar',
  715. ));
  716. $this->assertWidgetMatchesXpath($form->createView(), array(),
  717. '/input
  718. [@type="radio"]
  719. [@name="na&me"]
  720. [@checked="checked"]
  721. [@value="foo&bar"]
  722. '
  723. );
  724. }
  725. public function testUncheckedRadio()
  726. {
  727. $form = $this->factory->create('radio', 'na&me', array(
  728. 'property_path' => 'name',
  729. 'data' => false,
  730. ));
  731. $this->assertWidgetMatchesXpath($form->createView(), array(),
  732. '/input
  733. [@type="radio"]
  734. [@name="na&me"]
  735. [not(@checked)]
  736. '
  737. );
  738. }
  739. public function testTextarea()
  740. {
  741. $form = $this->factory->create('textarea', 'na&me', array(
  742. 'property_path' => 'name',
  743. 'data' => 'foo&bar',
  744. ));
  745. $this->assertWidgetMatchesXpath($form->createView(), array(),
  746. '/textarea
  747. [@name="na&me"]
  748. [.="foo&bar"]
  749. '
  750. );
  751. }
  752. public function testText()
  753. {
  754. $form = $this->factory->create('text', 'na&me', array(
  755. 'property_path' => 'name',
  756. 'data' => 'foo&bar',
  757. ));
  758. $this->assertWidgetMatchesXpath($form->createView(), array(),
  759. '/input
  760. [@type="text"]
  761. [@name="na&me"]
  762. [@value="foo&bar"]
  763. [not(@maxlength)]
  764. '
  765. );
  766. }
  767. public function testTextWithMaxLength()
  768. {
  769. $form = $this->factory->create('text', 'na&me', array(
  770. 'property_path' => 'name',
  771. 'data' => 'foo&bar',
  772. 'max_length' => 123,
  773. ));
  774. $this->assertWidgetMatchesXpath($form->createView(), array(),
  775. '/input
  776. [@type="text"]
  777. [@name="na&me"]
  778. [@value="foo&bar"]
  779. [@maxlength="123"]
  780. '
  781. );
  782. }
  783. public function testTime()
  784. {
  785. $form = $this->factory->create('time', 'na&me', array(
  786. 'property_path' => 'name',
  787. 'data' => '04:05:06',
  788. 'input' => 'string',
  789. 'with_seconds' => false,
  790. ));
  791. $this->assertWidgetMatchesXpath($form->createView(), array(),
  792. '/div
  793. [
  794. ./select
  795. [@id="na&me_hour"]
  796. [@size="1"]
  797. [./option[@value="4"][@selected="selected"]]
  798. /following-sibling::select
  799. [@id="na&me_minute"]
  800. [@size="1"]
  801. [./option[@value="5"][@selected="selected"]]
  802. ]
  803. [count(./select)=2]
  804. '
  805. );
  806. }
  807. public function testTimeWithSeconds()
  808. {
  809. $form = $this->factory->create('time', 'na&me', array(
  810. 'property_path' => 'name',
  811. 'data' => '04:05:06',
  812. 'input' => 'string',
  813. 'with_seconds' => true,
  814. ));
  815. $this->assertWidgetMatchesXpath($form->createView(), array(),
  816. '/div
  817. [
  818. ./select
  819. [@id="na&me_hour"]
  820. [@size="1"]
  821. [./option[@value="4"][@selected="selected"]]
  822. /following-sibling::select
  823. [@id="na&me_minute"]
  824. [@size="1"]
  825. [./option[@value="5"][@selected="selected"]]
  826. /following-sibling::select
  827. [@id="na&me_second"]
  828. [@size="1"]
  829. [./option[@value="6"][@selected="selected"]]
  830. ]
  831. [count(./select)=3]
  832. '
  833. );
  834. }
  835. public function testTimezone()
  836. {
  837. $form = $this->factory->create('timezone', 'na&me', array(
  838. 'property_path' => 'name',
  839. 'data' => 'Europe/Vienna',
  840. ));
  841. $this->assertWidgetMatchesXpath($form->createView(), array(),
  842. '/select
  843. [@name="na&me"]
  844. [./optgroup
  845. [@label="Europe"]
  846. [./option[@value="Europe/Vienna"][@selected="selected"][.="Vienna"]]
  847. ]
  848. [count(./optgroup)>10]
  849. [count(.//option)>200]
  850. '
  851. );
  852. }
  853. public function testUrl()
  854. {
  855. $form = $this->factory->create('url', 'na&me', array(
  856. 'property_path' => 'name',
  857. 'data' => 'http://www.google.com?foo1=bar1&foo2=bar2',
  858. ));
  859. $this->assertWidgetMatchesXpath($form->createView(), array(),
  860. '/input
  861. [@type="url"]
  862. [@name="na&me"]
  863. [@value="http://www.google.com?foo1=bar1&foo2=bar2"]
  864. '
  865. );
  866. }
  867. }