RadioTest.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  11. * @link http://cakephp.org CakePHP(tm) Project
  12. * @since 3.0.0
  13. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace Cake\Test\TestCase\View\Widget;
  16. use Cake\Collection\Collection;
  17. use Cake\TestSuite\TestCase;
  18. use Cake\View\StringTemplate;
  19. use Cake\View\Widget\Label;
  20. use Cake\View\Widget\Radio;
  21. /**
  22. * Radio test case
  23. */
  24. class RadioTest extends TestCase {
  25. /**
  26. * setup method.
  27. *
  28. * @return void
  29. */
  30. public function setUp() {
  31. parent::setUp();
  32. $templates = [
  33. 'radio' => '<input type="radio" name="{{name}}" value="{{value}}"{{attrs}}>',
  34. 'label' => '<label{{attrs}}>{{text}}</label>',
  35. 'radioWrapper' => '{{input}}{{label}}',
  36. ];
  37. $this->templates = new StringTemplate($templates);
  38. $this->context = $this->getMock('Cake\View\Form\ContextInterface');
  39. }
  40. /**
  41. * Test rendering basic radio buttons.
  42. *
  43. * @return void
  44. */
  45. public function testRenderSimple() {
  46. $label = new Label($this->templates);
  47. $radio = new Radio($this->templates, $label);
  48. $data = [
  49. 'name' => 'Crayons[color]',
  50. 'label' => null,
  51. 'options' => ['r' => 'Red', 'b' => 'Black']
  52. ];
  53. $result = $radio->render($data, $this->context);
  54. $expected = [
  55. ['input' => [
  56. 'type' => 'radio',
  57. 'name' => 'Crayons[color]',
  58. 'value' => 'r',
  59. 'id' => 'crayons-color-r'
  60. ]],
  61. ['label' => ['for' => 'crayons-color-r']],
  62. 'Red',
  63. '/label',
  64. ['input' => [
  65. 'type' => 'radio',
  66. 'name' => 'Crayons[color]',
  67. 'value' => 'b',
  68. 'id' => 'crayons-color-b'
  69. ]],
  70. ['label' => ['for' => 'crayons-color-b']],
  71. 'Black',
  72. '/label',
  73. ];
  74. $this->assertTags($result, $expected);
  75. $data = [
  76. 'name' => 'Crayons[color]',
  77. 'options' => new Collection(['r' => 'Red', 'b' => 'Black'])
  78. ];
  79. $result = $radio->render($data, $this->context);
  80. $this->assertTags($result, $expected);
  81. }
  82. /**
  83. * Test rendering inputs with the complex option form.
  84. *
  85. * @return void
  86. */
  87. public function testRenderComplex() {
  88. $label = new Label($this->templates);
  89. $radio = new Radio($this->templates, $label);
  90. $data = [
  91. 'name' => 'Crayons[color]',
  92. 'options' => [
  93. ['value' => 'r', 'text' => 'Red', 'id' => 'my_id'],
  94. ['value' => 'b', 'text' => 'Black', 'id' => 'my_id_2', 'data-test' => 'test'],
  95. ]
  96. ];
  97. $result = $radio->render($data, $this->context);
  98. $expected = [
  99. ['input' => [
  100. 'type' => 'radio',
  101. 'name' => 'Crayons[color]',
  102. 'value' => 'r',
  103. 'id' => 'my_id'
  104. ]],
  105. ['label' => ['for' => 'my_id']],
  106. 'Red',
  107. '/label',
  108. ['input' => [
  109. 'type' => 'radio',
  110. 'name' => 'Crayons[color]',
  111. 'value' => 'b',
  112. 'id' => 'my_id_2',
  113. 'data-test' => 'test'
  114. ]],
  115. ['label' => ['for' => 'my_id_2']],
  116. 'Black',
  117. '/label',
  118. ];
  119. $this->assertTags($result, $expected);
  120. }
  121. /**
  122. * Test that id suffixes are generated to not collide
  123. *
  124. * @return void
  125. */
  126. public function testRenderIdSuffixGeneration() {
  127. $label = new Label($this->templates);
  128. $radio = new Radio($this->templates, $label);
  129. $data = [
  130. 'name' => 'Thing[value]',
  131. 'options' => ['a>b' => 'First', 'a<b' => 'Second']
  132. ];
  133. $result = $radio->render($data, $this->context);
  134. $expected = [
  135. ['input' => [
  136. 'type' => 'radio',
  137. 'name' => 'Thing[value]',
  138. 'value' => 'a&gt;b',
  139. 'id' => 'thing-value-a-b'
  140. ]],
  141. ['label' => ['for' => 'thing-value-a-b']],
  142. 'First',
  143. '/label',
  144. ['input' => [
  145. 'type' => 'radio',
  146. 'name' => 'Thing[value]',
  147. 'value' => 'a&lt;b',
  148. 'id' => 'thing-value-a-b1',
  149. ]],
  150. ['label' => ['for' => 'thing-value-a-b1']],
  151. 'Second',
  152. '/label',
  153. ];
  154. $this->assertTags($result, $expected);
  155. }
  156. /**
  157. * Test rendering checks the right option with booleanish values.
  158. *
  159. * @return void
  160. */
  161. public function testRenderBooleanishValues() {
  162. $label = new Label($this->templates);
  163. $radio = new Radio($this->templates, $label);
  164. $data = [
  165. 'name' => 'Model[field]',
  166. 'options' => ['1' => 'Yes', '0' => 'No'],
  167. 'val' => '0'
  168. ];
  169. $result = $radio->render($data, $this->context);
  170. $expected = array(
  171. array('input' => array('type' => 'radio', 'name' => 'Model[field]', 'value' => '1', 'id' => 'model-field-1')),
  172. array('label' => array('for' => 'model-field-1')),
  173. 'Yes',
  174. '/label',
  175. array('input' => array('type' => 'radio', 'name' => 'Model[field]', 'value' => '0', 'id' => 'model-field-0', 'checked' => 'checked')),
  176. array('label' => array('for' => 'model-field-0')),
  177. 'No',
  178. '/label',
  179. );
  180. $this->assertTags($result, $expected);
  181. $data['val'] = 0;
  182. $result = $radio->render($data, $this->context);
  183. $this->assertTags($result, $expected);
  184. $data['val'] = false;
  185. $result = $radio->render($data, $this->context);
  186. $this->assertTags($result, $expected);
  187. $expected = array(
  188. array('input' => array('type' => 'radio', 'name' => 'Model[field]', 'value' => '1', 'id' => 'model-field-1')),
  189. array('label' => array('for' => 'model-field-1')),
  190. 'Yes',
  191. '/label',
  192. array('input' => array('type' => 'radio', 'name' => 'Model[field]', 'value' => '0', 'id' => 'model-field-0')),
  193. array('label' => array('for' => 'model-field-0')),
  194. 'No',
  195. '/label',
  196. );
  197. $data['val'] = null;
  198. $result = $radio->render($data, $this->context);
  199. $this->assertTags($result, $expected);
  200. $data['val'] = '';
  201. $result = $radio->render($data, $this->context);
  202. $this->assertTags($result, $expected);
  203. $expected = array(
  204. array('input' => array('type' => 'radio', 'name' => 'Model[field]', 'value' => '1', 'id' => 'model-field-1', 'checked' => 'checked')),
  205. array('label' => array('for' => 'model-field-1')),
  206. 'Yes',
  207. '/label',
  208. array('input' => array('type' => 'radio', 'name' => 'Model[field]', 'value' => '0', 'id' => 'model-field-0')),
  209. array('label' => array('for' => 'model-field-0')),
  210. 'No',
  211. '/label',
  212. );
  213. $data['val'] = '1';
  214. $result = $radio->render($data, $this->context);
  215. $this->assertTags($result, $expected);
  216. $data['val'] = 1;
  217. $result = $radio->render($data, $this->context);
  218. $this->assertTags($result, $expected);
  219. $data['val'] = true;
  220. $result = $radio->render($data, $this->context);
  221. $this->assertTags($result, $expected);
  222. }
  223. /**
  224. * Test that render() works with the required attribute.
  225. *
  226. * @return void
  227. */
  228. public function testRenderRequiredAndFormAttribute() {
  229. $label = new Label($this->templates);
  230. $radio = new Radio($this->templates, $label);
  231. $data = [
  232. 'name' => 'published',
  233. 'options' => ['option A', 'option B'],
  234. 'required' => true,
  235. 'form' => 'my-form',
  236. ];
  237. $result = $radio->render($data, $this->context);
  238. $expected = [
  239. ['input' => ['type' => 'radio', 'name' => 'published', 'value' => '0',
  240. 'id' => 'published-0', 'required' => 'required', 'form' => 'my-form']],
  241. ['label' => ['for' => 'published-0']],
  242. 'option A',
  243. '/label',
  244. ['input' => ['type' => 'radio', 'name' => 'published', 'value' => '1',
  245. 'id' => 'published-1', 'required' => 'required', 'form' => 'my-form']],
  246. ['label' => ['for' => 'published-1']],
  247. 'option B',
  248. '/label',
  249. ];
  250. $this->assertTags($result, $expected);
  251. }
  252. /**
  253. * Test rendering the empty option.
  254. *
  255. * @return void
  256. */
  257. public function testRenderEmptyOption() {
  258. $label = new Label($this->templates);
  259. $radio = new Radio($this->templates, $label);
  260. $data = [
  261. 'name' => 'Crayons[color]',
  262. 'options' => ['r' => 'Red'],
  263. 'empty' => true,
  264. ];
  265. $result = $radio->render($data, $this->context);
  266. $expected = [
  267. ['input' => [
  268. 'type' => 'radio',
  269. 'name' => 'Crayons[color]',
  270. 'value' => '',
  271. 'id' => 'crayons-color'
  272. ]],
  273. ['label' => ['for' => 'crayons-color']],
  274. 'empty',
  275. '/label',
  276. ['input' => [
  277. 'type' => 'radio',
  278. 'name' => 'Crayons[color]',
  279. 'value' => 'r',
  280. 'id' => 'crayons-color-r'
  281. ]],
  282. ['label' => ['for' => 'crayons-color-r']],
  283. 'Red',
  284. '/label',
  285. ];
  286. $this->assertTags($result, $expected);
  287. $data['empty'] = 'Choose one';
  288. $result = $radio->render($data, $this->context);
  289. $expected = [
  290. ['input' => [
  291. 'type' => 'radio',
  292. 'name' => 'Crayons[color]',
  293. 'value' => '',
  294. 'id' => 'crayons-color'
  295. ]],
  296. ['label' => ['for' => 'crayons-color']],
  297. 'Choose one',
  298. '/label',
  299. ['input' => [
  300. 'type' => 'radio',
  301. 'name' => 'Crayons[color]',
  302. 'value' => 'r',
  303. 'id' => 'crayons-color-r'
  304. ]],
  305. ['label' => ['for' => 'crayons-color-r']],
  306. 'Red',
  307. '/label',
  308. ];
  309. $this->assertTags($result, $expected);
  310. }
  311. /**
  312. * Test rendering the input inside the label.
  313. *
  314. * @return void
  315. */
  316. public function testRenderInputInsideLabel() {
  317. $this->templates->add([
  318. 'label' => '<label{{attrs}}>{{input}}{{text}}</label>',
  319. 'radioWrapper' => '{{label}}',
  320. ]);
  321. $label = new Label($this->templates);
  322. $radio = new Radio($this->templates, $label);
  323. $data = [
  324. 'name' => 'Crayons[color]',
  325. 'options' => ['r' => 'Red'],
  326. ];
  327. $result = $radio->render($data, $this->context);
  328. $expected = [
  329. ['label' => ['for' => 'crayons-color-r']],
  330. ['input' => [
  331. 'type' => 'radio',
  332. 'name' => 'Crayons[color]',
  333. 'value' => 'r',
  334. 'id' => 'crayons-color-r'
  335. ]],
  336. 'Red',
  337. '/label',
  338. ];
  339. $this->assertTags($result, $expected);
  340. }
  341. /**
  342. * test render() and selected inputs.
  343. *
  344. * @return void
  345. */
  346. public function testRenderSelected() {
  347. $label = new Label($this->templates);
  348. $radio = new Radio($this->templates, $label);
  349. $data = [
  350. 'name' => 'Versions[ver]',
  351. 'val' => '1',
  352. 'options' => [
  353. 1 => 'one',
  354. '1x' => 'one x',
  355. '2' => 'two',
  356. ]
  357. ];
  358. $result = $radio->render($data, $this->context);
  359. $expected = [
  360. ['input' => [
  361. 'id' => 'versions-ver-1',
  362. 'name' => 'Versions[ver]',
  363. 'type' => 'radio',
  364. 'value' => '1',
  365. 'checked' => 'checked'
  366. ]],
  367. ['label' => ['for' => 'versions-ver-1']],
  368. 'one',
  369. '/label',
  370. ['input' => [
  371. 'id' => 'versions-ver-1x',
  372. 'name' => 'Versions[ver]',
  373. 'type' => 'radio',
  374. 'value' => '1x'
  375. ]],
  376. ['label' => ['for' => 'versions-ver-1x']],
  377. 'one x',
  378. '/label',
  379. ['input' => [
  380. 'id' => 'versions-ver-2',
  381. 'name' => 'Versions[ver]',
  382. 'type' => 'radio',
  383. 'value' => '2'
  384. ]],
  385. ['label' => ['for' => 'versions-ver-2']],
  386. 'two',
  387. '/label',
  388. ];
  389. $this->assertTags($result, $expected);
  390. }
  391. /**
  392. * Test rendering with disable inputs
  393. *
  394. * @return void
  395. */
  396. public function testRenderDisabled() {
  397. $label = new Label($this->templates);
  398. $radio = new Radio($this->templates, $label);
  399. $data = [
  400. 'name' => 'Versions[ver]',
  401. 'options' => [
  402. 1 => 'one',
  403. '1x' => 'one x',
  404. '2' => 'two',
  405. ],
  406. 'disabled' => true,
  407. ];
  408. $result = $radio->render($data, $this->context);
  409. $expected = [
  410. ['input' => [
  411. 'id' => 'versions-ver-1',
  412. 'name' => 'Versions[ver]',
  413. 'type' => 'radio',
  414. 'value' => '1',
  415. 'disabled' => 'disabled'
  416. ]],
  417. ['label' => ['for' => 'versions-ver-1']],
  418. 'one',
  419. '/label',
  420. ['input' => [
  421. 'id' => 'versions-ver-1x',
  422. 'name' => 'Versions[ver]',
  423. 'type' => 'radio',
  424. 'value' => '1x',
  425. 'disabled' => 'disabled'
  426. ]],
  427. ['label' => ['for' => 'versions-ver-1x']],
  428. 'one x',
  429. '/label',
  430. ];
  431. $this->assertTags($result, $expected);
  432. $data['disabled'] = 'a string';
  433. $result = $radio->render($data, $this->context);
  434. $this->assertTags($result, $expected);
  435. $data['disabled'] = ['1'];
  436. $result = $radio->render($data, $this->context);
  437. $expected = [
  438. ['input' => [
  439. 'id' => 'versions-ver-1',
  440. 'name' => 'Versions[ver]',
  441. 'type' => 'radio',
  442. 'value' => '1',
  443. 'disabled' => 'disabled'
  444. ]],
  445. ['label' => ['for' => 'versions-ver-1']],
  446. 'one',
  447. '/label',
  448. ['input' => [
  449. 'id' => 'versions-ver-1x',
  450. 'name' => 'Versions[ver]',
  451. 'type' => 'radio',
  452. 'value' => '1x',
  453. ]],
  454. ['label' => ['for' => 'versions-ver-1x']],
  455. 'one x',
  456. '/label',
  457. ];
  458. $this->assertTags($result, $expected);
  459. }
  460. /**
  461. * Test rendering with label options.
  462. *
  463. * @return void
  464. */
  465. public function testRenderLabelOptions() {
  466. $label = new Label($this->templates);
  467. $radio = new Radio($this->templates, $label);
  468. $data = [
  469. 'name' => 'Versions[ver]',
  470. 'options' => [
  471. 1 => 'one',
  472. '1x' => 'one x',
  473. '2' => 'two',
  474. ],
  475. 'label' => false,
  476. ];
  477. $result = $radio->render($data, $this->context);
  478. $expected = [
  479. ['input' => [
  480. 'id' => 'versions-ver-1',
  481. 'name' => 'Versions[ver]',
  482. 'type' => 'radio',
  483. 'value' => '1',
  484. ]],
  485. ['input' => [
  486. 'id' => 'versions-ver-1x',
  487. 'name' => 'Versions[ver]',
  488. 'type' => 'radio',
  489. 'value' => '1x',
  490. ]],
  491. ];
  492. $this->assertTags($result, $expected);
  493. $data = [
  494. 'name' => 'Versions[ver]',
  495. 'options' => [
  496. 1 => 'one',
  497. '1x' => 'one x',
  498. '2' => 'two',
  499. ],
  500. 'label' => [
  501. 'class' => 'my-class',
  502. ]
  503. ];
  504. $result = $radio->render($data, $this->context);
  505. $expected = [
  506. ['input' => [
  507. 'id' => 'versions-ver-1',
  508. 'name' => 'Versions[ver]',
  509. 'type' => 'radio',
  510. 'value' => '1',
  511. ]],
  512. ['label' => ['class' => 'my-class', 'for' => 'versions-ver-1']],
  513. 'one',
  514. '/label',
  515. ['input' => [
  516. 'id' => 'versions-ver-1x',
  517. 'name' => 'Versions[ver]',
  518. 'type' => 'radio',
  519. 'value' => '1x',
  520. ]],
  521. ['label' => ['class' => 'my-class', 'for' => 'versions-ver-1x']],
  522. 'one x',
  523. '/label',
  524. ];
  525. $this->assertTags($result, $expected);
  526. }
  527. /**
  528. * Ensure that the input + label are composed with
  529. * a template.
  530. *
  531. * @return void
  532. */
  533. public function testRenderContainerTemplate() {
  534. $this->templates->add([
  535. 'radioWrapper' => '<div class="radio">{{input}}{{label}}</div>'
  536. ]);
  537. $label = new Label($this->templates);
  538. $radio = new Radio($this->templates, $label);
  539. $data = [
  540. 'name' => 'Versions[ver]',
  541. 'options' => [
  542. 1 => 'one',
  543. '1x' => 'one x',
  544. '2' => 'two',
  545. ],
  546. ];
  547. $result = $radio->render($data, $this->context);
  548. $this->assertContains(
  549. '<div class="radio"><input type="radio"',
  550. $result
  551. );
  552. $this->assertContains(
  553. '</label></div>',
  554. $result
  555. );
  556. }
  557. }