AbstractLayoutTest.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980
  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 testFile()
  536. {
  537. $form = $this->factory->create('file', 'na&me', array('property_path' => 'name'));
  538. $this->assertWidgetMatchesXpath($form->createView(), array(),
  539. '/div
  540. [
  541. ./input[@type="file"][@id="na&me_file"]
  542. /following-sibling::input[@type="hidden"][@id="na&me_token"]
  543. /following-sibling::input[@type="hidden"][@id="na&me_name"]
  544. ]
  545. [count(./input)=3]
  546. '
  547. );
  548. }
  549. public function testHidden()
  550. {
  551. $form = $this->factory->create('hidden', 'na&me', array(
  552. 'property_path' => 'name',
  553. 'data' => 'foo&bar',
  554. ));
  555. $this->assertWidgetMatchesXpath($form->createView(), array(),
  556. '/input
  557. [@type="hidden"]
  558. [@name="na&me"]
  559. [@value="foo&bar"]
  560. '
  561. );
  562. }
  563. public function testInteger()
  564. {
  565. $form = $this->factory->create('integer', 'na&me', array(
  566. 'property_path' => 'name',
  567. 'data' => '123',
  568. ));
  569. $this->assertWidgetMatchesXpath($form->createView(), array(),
  570. '/input
  571. [@type="number"]
  572. [@name="na&me"]
  573. [@value="123"]
  574. '
  575. );
  576. }
  577. public function testLanguage()
  578. {
  579. $form = $this->factory->create('language', 'na&me', array(
  580. 'property_path' => 'name',
  581. 'data' => 'de',
  582. ));
  583. $this->assertWidgetMatchesXpath($form->createView(), array(),
  584. '/select
  585. [@name="na&me"]
  586. [./option[@value="de"][@selected="selected"][.="German"]]
  587. [count(./option)>200]
  588. '
  589. );
  590. }
  591. public function testLocale()
  592. {
  593. $form = $this->factory->create('locale', 'na&me', array(
  594. 'property_path' => 'name',
  595. 'data' => 'de_AT',
  596. ));
  597. $this->assertWidgetMatchesXpath($form->createView(), array(),
  598. '/select
  599. [@name="na&me"]
  600. [./option[@value="de_AT"][@selected="selected"][.="German (Austria)"]]
  601. [count(./option)>200]
  602. '
  603. );
  604. }
  605. public function testMoney()
  606. {
  607. $form = $this->factory->create('money', 'na&me', array(
  608. 'property_path' => 'name',
  609. 'data' => 1234.56,
  610. 'currency' => 'EUR',
  611. ));
  612. $this->assertWidgetMatchesXpath($form->createView(), array(),
  613. '/input
  614. [@type="text"]
  615. [@name="na&me"]
  616. [@value="1234.56"]
  617. [contains(.., "€")]
  618. '
  619. );
  620. }
  621. public function testNumber()
  622. {
  623. $form = $this->factory->create('number', 'na&me', array(
  624. 'property_path' => 'name',
  625. 'data' => 1234.56,
  626. ));
  627. $this->assertWidgetMatchesXpath($form->createView(), array(),
  628. '/input
  629. [@type="text"]
  630. [@name="na&me"]
  631. [@value="1234.56"]
  632. '
  633. );
  634. }
  635. public function testPassword()
  636. {
  637. $form = $this->factory->create('password', 'na&me', array(
  638. 'property_path' => 'name',
  639. 'data' => 'foo&bar',
  640. ));
  641. $this->assertWidgetMatchesXpath($form->createView(), array(),
  642. '/input
  643. [@type="password"]
  644. [@name="na&me"]
  645. [@value=""]
  646. '
  647. );
  648. }
  649. public function testPasswordBoundNotAlwaysEmpty()
  650. {
  651. $form = $this->factory->create('password', 'na&me', array(
  652. 'property_path' => 'name',
  653. 'always_empty' => false,
  654. ));
  655. $form->bind('foo&bar');
  656. $this->assertWidgetMatchesXpath($form->createView(), array(),
  657. '/input
  658. [@type="password"]
  659. [@name="na&me"]
  660. [@value="foo&bar"]
  661. '
  662. );
  663. }
  664. public function testPasswordWithMaxLength()
  665. {
  666. $form = $this->factory->create('password', 'na&me', array(
  667. 'property_path' => 'name',
  668. 'data' => 'foo&bar',
  669. 'max_length' => 123,
  670. ));
  671. $this->assertWidgetMatchesXpath($form->createView(), array(),
  672. '/input
  673. [@type="password"]
  674. [@name="na&me"]
  675. [@value=""]
  676. [@maxlength="123"]
  677. '
  678. );
  679. }
  680. public function testPercent()
  681. {
  682. $form = $this->factory->create('percent', 'na&me', array(
  683. 'property_path' => 'name',
  684. 'data' => 0.1,
  685. ));
  686. $this->assertWidgetMatchesXpath($form->createView(), array(),
  687. '/input
  688. [@type="text"]
  689. [@name="na&me"]
  690. [@value="10"]
  691. [contains(.., "%")]
  692. '
  693. );
  694. }
  695. public function testCheckedRadio()
  696. {
  697. $form = $this->factory->create('radio', 'na&me', array(
  698. 'property_path' => 'name',
  699. 'data' => true,
  700. ));
  701. $this->assertWidgetMatchesXpath($form->createView(), array(),
  702. '/input
  703. [@type="radio"]
  704. [@name="na&me"]
  705. [@checked="checked"]
  706. [@value=""]
  707. '
  708. );
  709. }
  710. public function testCheckedRadioWithValue()
  711. {
  712. $form = $this->factory->create('radio', 'na&me', array(
  713. 'property_path' => 'name',
  714. 'data' => true,
  715. 'value' => 'foo&bar',
  716. ));
  717. $this->assertWidgetMatchesXpath($form->createView(), array(),
  718. '/input
  719. [@type="radio"]
  720. [@name="na&me"]
  721. [@checked="checked"]
  722. [@value="foo&bar"]
  723. '
  724. );
  725. }
  726. public function testUncheckedRadio()
  727. {
  728. $form = $this->factory->create('radio', 'na&me', array(
  729. 'property_path' => 'name',
  730. 'data' => false,
  731. ));
  732. $this->assertWidgetMatchesXpath($form->createView(), array(),
  733. '/input
  734. [@type="radio"]
  735. [@name="na&me"]
  736. [not(@checked)]
  737. '
  738. );
  739. }
  740. public function testTextarea()
  741. {
  742. $form = $this->factory->create('textarea', 'na&me', array(
  743. 'property_path' => 'name',
  744. 'data' => 'foo&bar',
  745. ));
  746. $this->assertWidgetMatchesXpath($form->createView(), array(),
  747. '/textarea
  748. [@name="na&me"]
  749. [.="foo&bar"]
  750. '
  751. );
  752. }
  753. public function testText()
  754. {
  755. $form = $this->factory->create('text', 'na&me', array(
  756. 'property_path' => 'name',
  757. 'data' => 'foo&bar',
  758. ));
  759. $this->assertWidgetMatchesXpath($form->createView(), array(),
  760. '/input
  761. [@type="text"]
  762. [@name="na&me"]
  763. [@value="foo&bar"]
  764. [not(@maxlength)]
  765. '
  766. );
  767. }
  768. public function testTextWithMaxLength()
  769. {
  770. $form = $this->factory->create('text', 'na&me', array(
  771. 'property_path' => 'name',
  772. 'data' => 'foo&bar',
  773. 'max_length' => 123,
  774. ));
  775. $this->assertWidgetMatchesXpath($form->createView(), array(),
  776. '/input
  777. [@type="text"]
  778. [@name="na&me"]
  779. [@value="foo&bar"]
  780. [@maxlength="123"]
  781. '
  782. );
  783. }
  784. public function testTime()
  785. {
  786. $form = $this->factory->create('time', 'na&me', array(
  787. 'property_path' => 'name',
  788. 'data' => '04:05:06',
  789. 'input' => 'string',
  790. 'with_seconds' => false,
  791. ));
  792. $this->assertWidgetMatchesXpath($form->createView(), array(),
  793. '/div
  794. [
  795. ./select
  796. [@id="na&me_hour"]
  797. [@size="1"]
  798. [./option[@value="4"][@selected="selected"]]
  799. /following-sibling::select
  800. [@id="na&me_minute"]
  801. [@size="1"]
  802. [./option[@value="5"][@selected="selected"]]
  803. ]
  804. [count(./select)=2]
  805. '
  806. );
  807. }
  808. public function testTimeWithSeconds()
  809. {
  810. $form = $this->factory->create('time', 'na&me', array(
  811. 'property_path' => 'name',
  812. 'data' => '04:05:06',
  813. 'input' => 'string',
  814. 'with_seconds' => true,
  815. ));
  816. $this->assertWidgetMatchesXpath($form->createView(), array(),
  817. '/div
  818. [
  819. ./select
  820. [@id="na&me_hour"]
  821. [@size="1"]
  822. [./option[@value="4"][@selected="selected"]]
  823. /following-sibling::select
  824. [@id="na&me_minute"]
  825. [@size="1"]
  826. [./option[@value="5"][@selected="selected"]]
  827. /following-sibling::select
  828. [@id="na&me_second"]
  829. [@size="1"]
  830. [./option[@value="6"][@selected="selected"]]
  831. ]
  832. [count(./select)=3]
  833. '
  834. );
  835. }
  836. public function testTimezone()
  837. {
  838. $form = $this->factory->create('timezone', 'na&me', array(
  839. 'property_path' => 'name',
  840. 'data' => 'Europe/Vienna',
  841. ));
  842. $this->assertWidgetMatchesXpath($form->createView(), array(),
  843. '/select
  844. [@name="na&me"]
  845. [./optgroup
  846. [@label="Europe"]
  847. [./option[@value="Europe/Vienna"][@selected="selected"][.="Vienna"]]
  848. ]
  849. [count(./optgroup)>10]
  850. [count(.//option)>200]
  851. '
  852. );
  853. }
  854. public function testUrl()
  855. {
  856. $form = $this->factory->create('url', 'na&me', array(
  857. 'property_path' => 'name',
  858. 'data' => 'http://www.google.com?foo1=bar1&foo2=bar2',
  859. ));
  860. $this->assertWidgetMatchesXpath($form->createView(), array(),
  861. '/input
  862. [@type="url"]
  863. [@name="na&me"]
  864. [@value="http://www.google.com?foo1=bar1&foo2=bar2"]
  865. '
  866. );
  867. }
  868. }