SelectBoxWidgetTest.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  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\SelectBoxWidget;
  20. /**
  21. * SelectBox test case
  22. */
  23. class SelectBoxWidgetTest extends TestCase {
  24. /**
  25. * setup method.
  26. *
  27. * @return void
  28. */
  29. public function setUp() {
  30. parent::setUp();
  31. $templates = [
  32. 'select' => '<select name="{{name}}"{{attrs}}>{{content}}</select>',
  33. 'selectMultiple' => '<select name="{{name}}[]" multiple="multiple"{{attrs}}>{{content}}</select>',
  34. 'option' => '<option value="{{value}}"{{attrs}}>{{text}}</option>',
  35. 'optgroup' => '<optgroup label="{{label}}"{{attrs}}>{{content}}</optgroup>',
  36. ];
  37. $this->context = $this->getMock('Cake\View\Form\ContextInterface');
  38. $this->templates = new StringTemplate($templates);
  39. }
  40. /**
  41. * test render no options
  42. *
  43. * @return void
  44. */
  45. public function testRenderNoOptions() {
  46. $select = new SelectBoxWidget($this->templates);
  47. $data = [
  48. 'id' => 'BirdName',
  49. 'name' => 'Birds[name]',
  50. 'options' => []
  51. ];
  52. $result = $select->render($data, $this->context);
  53. $expected = [
  54. 'select' => ['name' => 'Birds[name]', 'id' => 'BirdName'],
  55. '/select'
  56. ];
  57. $this->assertHtml($expected, $result);
  58. }
  59. /**
  60. * test simple rendering
  61. *
  62. * @return void
  63. */
  64. public function testRenderSimple() {
  65. $select = new SelectBoxWidget($this->templates);
  66. $data = [
  67. 'id' => 'BirdName',
  68. 'name' => 'Birds[name]',
  69. 'options' => ['a' => 'Albatross', 'b' => 'Budgie']
  70. ];
  71. $result = $select->render($data, $this->context);
  72. $expected = [
  73. 'select' => ['name' => 'Birds[name]', 'id' => 'BirdName'],
  74. ['option' => ['value' => 'a']], 'Albatross', '/option',
  75. ['option' => ['value' => 'b']], 'Budgie', '/option',
  76. '/select'
  77. ];
  78. $this->assertHtml($expected, $result);
  79. }
  80. /**
  81. * test simple iterator rendering
  82. *
  83. * @return void
  84. */
  85. public function testRenderSimpleIterator() {
  86. $select = new SelectBoxWidget($this->templates);
  87. $options = new \ArrayObject(['a' => 'Albatross', 'b' => 'Budgie']);
  88. $data = [
  89. 'name' => 'Birds[name]',
  90. 'options' => $options,
  91. 'empty' => true
  92. ];
  93. $result = $select->render($data, $this->context);
  94. $expected = [
  95. 'select' => ['name' => 'Birds[name]'],
  96. ['option' => ['value' => '']], '/option',
  97. ['option' => ['value' => 'a']], 'Albatross', '/option',
  98. ['option' => ['value' => 'b']], 'Budgie', '/option',
  99. '/select'
  100. ];
  101. $this->assertHtml($expected, $result);
  102. }
  103. /**
  104. * test simple iterator rendering with empty option
  105. *
  106. * @return void
  107. */
  108. public function testRenderSimpleIteratorWithEmpty() {
  109. $select = new SelectBoxWidget($this->templates);
  110. $options = new Collection(['a' => 'Albatross', 'b' => 'Budgie']);
  111. $data = [
  112. 'name' => 'Birds[name]',
  113. 'options' => $options,
  114. 'empty' => 'Pick one'
  115. ];
  116. $result = $select->render($data, $this->context);
  117. $expected = [
  118. 'select' => ['name' => 'Birds[name]'],
  119. ['option' => ['value' => '']], 'Pick one', '/option',
  120. ['option' => ['value' => 'a']], 'Albatross', '/option',
  121. ['option' => ['value' => 'b']], 'Budgie', '/option',
  122. '/select'
  123. ];
  124. $this->assertHtml($expected, $result);
  125. }
  126. /**
  127. * test complex option rendering
  128. *
  129. * @return void
  130. */
  131. public function testRenderComplex() {
  132. $select = new SelectBoxWidget($this->templates);
  133. $data = [
  134. 'id' => 'BirdName',
  135. 'name' => 'Birds[name]',
  136. 'options' => [
  137. ['value' => 'a', 'text' => 'Albatross'],
  138. ['value' => 'b', 'text' => 'Budgie', 'data-foo' => 'bar'],
  139. ]
  140. ];
  141. $result = $select->render($data, $this->context);
  142. $expected = [
  143. 'select' => ['name' => 'Birds[name]', 'id' => 'BirdName'],
  144. ['option' => ['value' => 'a']],
  145. 'Albatross',
  146. '/option',
  147. ['option' => ['value' => 'b', 'data-foo' => 'bar']],
  148. 'Budgie',
  149. '/option',
  150. '/select'
  151. ];
  152. $this->assertHtml($expected, $result);
  153. }
  154. /**
  155. * test rendering with a selected value
  156. *
  157. * @return void
  158. */
  159. public function testRenderSelected() {
  160. $select = new SelectBoxWidget($this->templates);
  161. $data = [
  162. 'id' => 'BirdName',
  163. 'name' => 'Birds[name]',
  164. 'val' => '1',
  165. 'options' => [
  166. 1 => 'one',
  167. '1x' => 'one x',
  168. '2' => 'two',
  169. '2x' => 'two x',
  170. ]
  171. ];
  172. $result = $select->render($data, $this->context);
  173. $expected = [
  174. 'select' => ['name' => 'Birds[name]', 'id' => 'BirdName'],
  175. ['option' => ['value' => '1', 'selected' => 'selected']], 'one', '/option',
  176. ['option' => ['value' => '1x']], 'one x', '/option',
  177. ['option' => ['value' => '2']], 'two', '/option',
  178. ['option' => ['value' => '2x']], 'two x', '/option',
  179. '/select'
  180. ];
  181. $this->assertHtml($expected, $result);
  182. $data['val'] = 2;
  183. $result = $select->render($data, $this->context);
  184. $expected = [
  185. 'select' => ['name' => 'Birds[name]', 'id' => 'BirdName'],
  186. ['option' => ['value' => '1']], 'one', '/option',
  187. ['option' => ['value' => '1x']], 'one x', '/option',
  188. ['option' => ['value' => '2', 'selected' => 'selected']], 'two', '/option',
  189. ['option' => ['value' => '2x']], 'two x', '/option',
  190. '/select'
  191. ];
  192. $this->assertHtml($expected, $result);
  193. }
  194. /**
  195. * test rendering a multi select
  196. *
  197. * @return void
  198. */
  199. public function testRenderMultipleSelect() {
  200. $select = new SelectBoxWidget($this->templates);
  201. $data = [
  202. 'id' => 'BirdName',
  203. 'name' => 'Birds[name]',
  204. 'multiple' => true,
  205. 'options' => ['a' => 'Albatross', 'b' => 'Budgie']
  206. ];
  207. $result = $select->render($data, $this->context);
  208. $expected = [
  209. 'select' => [
  210. 'name' => 'Birds[name][]',
  211. 'id' => 'BirdName',
  212. 'multiple' => 'multiple',
  213. ],
  214. ['option' => ['value' => 'a']], 'Albatross', '/option',
  215. ['option' => ['value' => 'b']], 'Budgie', '/option',
  216. '/select'
  217. ];
  218. $this->assertHtml($expected, $result);
  219. }
  220. /**
  221. * test rendering multi select & selected values
  222. *
  223. * @return void
  224. */
  225. public function testRenderMultipleSelected() {
  226. $select = new SelectBoxWidget($this->templates);
  227. $data = [
  228. 'multiple' => true,
  229. 'id' => 'BirdName',
  230. 'name' => 'Birds[name]',
  231. 'val' => ['1', '2', 'burp'],
  232. 'options' => [
  233. 1 => 'one',
  234. '1x' => 'one x',
  235. '2' => 'two',
  236. '2x' => 'two x',
  237. ]
  238. ];
  239. $result = $select->render($data, $this->context);
  240. $expected = [
  241. 'select' => [
  242. 'name' => 'Birds[name][]',
  243. 'multiple' => 'multiple',
  244. 'id' => 'BirdName'
  245. ],
  246. ['option' => ['value' => '1', 'selected' => 'selected']], 'one', '/option',
  247. ['option' => ['value' => '1x']], 'one x', '/option',
  248. ['option' => ['value' => '2', 'selected' => 'selected']], 'two', '/option',
  249. ['option' => ['value' => '2x']], 'two x', '/option',
  250. '/select'
  251. ];
  252. $this->assertHtml($expected, $result);
  253. }
  254. /**
  255. * test rendering with option groups
  256. *
  257. * @return void
  258. */
  259. public function testRenderOptionGroups() {
  260. $select = new SelectBoxWidget($this->templates);
  261. $data = [
  262. 'name' => 'Birds[name]',
  263. 'options' => [
  264. 'Mammal' => [
  265. 'beaver' => 'Beaver',
  266. 'elk' => 'Elk',
  267. ],
  268. 'Bird' => [
  269. 'budgie' => 'Budgie',
  270. 'eagle' => 'Eagle',
  271. ]
  272. ]
  273. ];
  274. $result = $select->render($data, $this->context);
  275. $expected = [
  276. 'select' => [
  277. 'name' => 'Birds[name]',
  278. ],
  279. ['optgroup' => ['label' => 'Mammal']],
  280. ['option' => ['value' => 'beaver']],
  281. 'Beaver',
  282. '/option',
  283. ['option' => ['value' => 'elk']],
  284. 'Elk',
  285. '/option',
  286. '/optgroup',
  287. ['optgroup' => ['label' => 'Bird']],
  288. ['option' => ['value' => 'budgie']],
  289. 'Budgie',
  290. '/option',
  291. ['option' => ['value' => 'eagle']],
  292. 'Eagle',
  293. '/option',
  294. '/optgroup',
  295. '/select'
  296. ];
  297. $this->assertHtml($expected, $result);
  298. }
  299. /**
  300. * test rendering with option groups and escaping
  301. *
  302. * @return void
  303. */
  304. public function testRenderOptionGroupsEscape() {
  305. $select = new SelectBoxWidget($this->templates);
  306. $data = [
  307. 'name' => 'Birds[name]',
  308. 'options' => [
  309. '>XSS<' => [
  310. '1' => 'One>',
  311. ],
  312. ]
  313. ];
  314. $result = $select->render($data, $this->context);
  315. $expected = [
  316. 'select' => [
  317. 'name' => 'Birds[name]',
  318. ],
  319. ['optgroup' => ['label' => '&gt;XSS&lt;']],
  320. ['option' => ['value' => '1']],
  321. 'One&gt;',
  322. '/option',
  323. '/optgroup',
  324. '/select'
  325. ];
  326. $this->assertHtml($expected, $result);
  327. $data['escape'] = false;
  328. $result = $select->render($data, $this->context);
  329. $expected = [
  330. 'select' => [
  331. 'name' => 'Birds[name]',
  332. ],
  333. ['optgroup' => ['label' => '>XSS<']],
  334. ['option' => ['value' => '1']],
  335. 'One>',
  336. '/option',
  337. '/optgroup',
  338. '/select'
  339. ];
  340. $this->assertHtml($expected, $result);
  341. }
  342. /**
  343. * test rendering with option groups
  344. *
  345. * @return void
  346. */
  347. public function testRenderOptionGroupsWithAttributes() {
  348. $select = new SelectBoxWidget($this->templates);
  349. $data = [
  350. 'name' => 'Birds[name]',
  351. 'options' => [
  352. [
  353. 'text' => 'Mammal',
  354. 'data-foo' => 'bar',
  355. 'options' => [
  356. 'beaver' => 'Beaver',
  357. 'elk' => 'Elk',
  358. ]
  359. ]
  360. ]
  361. ];
  362. $result = $select->render($data, $this->context);
  363. $expected = [
  364. 'select' => [
  365. 'name' => 'Birds[name]',
  366. ],
  367. ['optgroup' => ['data-foo' => 'bar', 'label' => 'Mammal']],
  368. ['option' => ['value' => 'beaver']],
  369. 'Beaver',
  370. '/option',
  371. ['option' => ['value' => 'elk']],
  372. 'Elk',
  373. '/option',
  374. '/optgroup',
  375. '/select'
  376. ];
  377. $this->assertHtml($expected, $result);
  378. }
  379. /**
  380. * test rendering with option groups with traversable nodes
  381. *
  382. * @return void
  383. */
  384. public function testRenderOptionGroupsTraversable() {
  385. $select = new SelectBoxWidget($this->templates);
  386. $mammals = new \ArrayObject(['beaver' => 'Beaver', 'elk' => 'Elk']);
  387. $data = [
  388. 'name' => 'Birds[name]',
  389. 'options' => [
  390. 'Mammal' => $mammals,
  391. 'Bird' => [
  392. 'budgie' => 'Budgie',
  393. 'eagle' => 'Eagle',
  394. ]
  395. ]
  396. ];
  397. $result = $select->render($data, $this->context);
  398. $expected = [
  399. 'select' => [
  400. 'name' => 'Birds[name]',
  401. ],
  402. ['optgroup' => ['label' => 'Mammal']],
  403. ['option' => ['value' => 'beaver']],
  404. 'Beaver',
  405. '/option',
  406. ['option' => ['value' => 'elk']],
  407. 'Elk',
  408. '/option',
  409. '/optgroup',
  410. ['optgroup' => ['label' => 'Bird']],
  411. ['option' => ['value' => 'budgie']],
  412. 'Budgie',
  413. '/option',
  414. ['option' => ['value' => 'eagle']],
  415. 'Eagle',
  416. '/option',
  417. '/optgroup',
  418. '/select'
  419. ];
  420. $this->assertHtml($expected, $result);
  421. }
  422. /**
  423. * test rendering option groups and selected values
  424. *
  425. * @return void
  426. */
  427. public function testRenderOptionGroupsSelectedAndDisabled() {
  428. $select = new SelectBoxWidget($this->templates);
  429. $data = [
  430. 'name' => 'Birds[name]',
  431. 'val' => ['1', '2', 'burp'],
  432. 'disabled' => ['1x', '2x', 'nope'],
  433. 'options' => [
  434. 'ones' => [
  435. 1 => 'one',
  436. '1x' => 'one x',
  437. ],
  438. 'twos' => [
  439. '2' => 'two',
  440. '2x' => 'two x',
  441. ]
  442. ]
  443. ];
  444. $result = $select->render($data, $this->context);
  445. $expected = [
  446. 'select' => [
  447. 'name' => 'Birds[name]',
  448. ],
  449. ['optgroup' => ['label' => 'ones']],
  450. ['option' => ['value' => '1', 'selected' => 'selected']], 'one', '/option',
  451. ['option' => ['value' => '1x', 'disabled' => 'disabled']], 'one x', '/option',
  452. '/optgroup',
  453. ['optgroup' => ['label' => 'twos']],
  454. ['option' => ['value' => '2', 'selected' => 'selected']], 'two', '/option',
  455. ['option' => ['value' => '2x', 'disabled' => 'disabled']], 'two x', '/option',
  456. '/optgroup',
  457. '/select'
  458. ];
  459. $this->assertHtml($expected, $result);
  460. }
  461. /**
  462. * test rendering a totally disabled element
  463. *
  464. * @return void
  465. */
  466. public function testRenderDisabled() {
  467. $select = new SelectBoxWidget($this->templates);
  468. $data = [
  469. 'disabled' => true,
  470. 'name' => 'Birds[name]',
  471. 'options' => ['a' => 'Albatross', 'b' => 'Budgie'],
  472. 'val' => 'a',
  473. ];
  474. $result = $select->render($data, $this->context);
  475. $expected = [
  476. 'select' => [
  477. 'name' => 'Birds[name]',
  478. 'disabled' => 'disabled',
  479. ],
  480. ['option' => ['value' => 'a', 'selected' => 'selected']], 'Albatross', '/option',
  481. ['option' => ['value' => 'b']], 'Budgie', '/option',
  482. '/select'
  483. ];
  484. $this->assertHtml($expected, $result);
  485. $select = new SelectBoxWidget($this->templates);
  486. $data = [
  487. 'disabled' => [1],
  488. 'name' => 'numbers',
  489. 'options' => ['1' => 'One', '2' => 'Two'],
  490. ];
  491. $result = $select->render($data, $this->context);
  492. $expected = [
  493. 'select' => [
  494. 'name' => 'numbers',
  495. ],
  496. ['option' => ['value' => '1', 'disabled' => 'disabled']], 'One', '/option',
  497. ['option' => ['value' => '2']], 'Two', '/option',
  498. '/select'
  499. ];
  500. $this->assertHtml($expected, $result);
  501. }
  502. /**
  503. * test rendering a disabled element
  504. *
  505. * @return void
  506. */
  507. public function testRenderDisabledMultiple() {
  508. $select = new SelectBoxWidget($this->templates);
  509. $data = [
  510. 'disabled' => ['a', 'c'],
  511. 'val' => 'a',
  512. 'name' => 'Birds[name]',
  513. 'options' => [
  514. 'a' => 'Albatross',
  515. 'b' => 'Budgie',
  516. 'c' => 'Canary',
  517. ]
  518. ];
  519. $result = $select->render($data, $this->context);
  520. $expected = [
  521. 'select' => [
  522. 'name' => 'Birds[name]',
  523. ],
  524. ['option' => ['value' => 'a', 'selected' => 'selected', 'disabled' => 'disabled']],
  525. 'Albatross',
  526. '/option',
  527. ['option' => ['value' => 'b']],
  528. 'Budgie',
  529. '/option',
  530. ['option' => ['value' => 'c', 'disabled' => 'disabled']],
  531. 'Canary',
  532. '/option',
  533. '/select'
  534. ];
  535. $this->assertHtml($expected, $result);
  536. }
  537. /**
  538. * test rendering with an empty value
  539. *
  540. * @return void
  541. */
  542. public function testRenderEmptyOption() {
  543. $select = new SelectBoxWidget($this->templates);
  544. $data = [
  545. 'id' => 'BirdName',
  546. 'name' => 'Birds[name]',
  547. 'empty' => true,
  548. 'options' => ['a' => 'Albatross', 'b' => 'Budgie']
  549. ];
  550. $result = $select->render($data, $this->context);
  551. $expected = [
  552. 'select' => ['name' => 'Birds[name]', 'id' => 'BirdName'],
  553. ['option' => ['value' => '']], '/option',
  554. ['option' => ['value' => 'a']], 'Albatross', '/option',
  555. ['option' => ['value' => 'b']], 'Budgie', '/option',
  556. '/select'
  557. ];
  558. $this->assertHtml($expected, $result);
  559. $data['empty'] = 'empty';
  560. $result = $select->render($data, $this->context);
  561. $expected = [
  562. 'select' => ['name' => 'Birds[name]', 'id' => 'BirdName'],
  563. ['option' => ['value' => '']], 'empty', '/option',
  564. ['option' => ['value' => 'a']], 'Albatross', '/option',
  565. ['option' => ['value' => 'b']], 'Budgie', '/option',
  566. '/select'
  567. ];
  568. $this->assertHtml($expected, $result);
  569. $data['empty'] = 'empty';
  570. $data['val'] = '';
  571. $result = $select->render($data, $this->context);
  572. $expected = [
  573. 'select' => ['name' => 'Birds[name]', 'id' => 'BirdName'],
  574. ['option' => ['value' => '', 'selected' => 'selected']], 'empty', '/option',
  575. ['option' => ['value' => 'a']], 'Albatross', '/option',
  576. ['option' => ['value' => 'b']], 'Budgie', '/option',
  577. '/select'
  578. ];
  579. $this->assertHtml($expected, $result);
  580. $data['val'] = false;
  581. $result = $select->render($data, $this->context);
  582. $this->assertHtml($expected, $result);
  583. }
  584. /**
  585. * Test rendering with disabling escaping.
  586. *
  587. * @return void
  588. */
  589. public function testRenderEscapingOption() {
  590. $select = new SelectBoxWidget($this->templates);
  591. $data = [
  592. 'name' => 'Birds[name]',
  593. 'options' => [
  594. 'a' => '>Albatross',
  595. 'b' => '>Budgie',
  596. 'c' => '>Canary',
  597. ]
  598. ];
  599. $result = $select->render($data, $this->context);
  600. $expected = [
  601. 'select' => [
  602. 'name' => 'Birds[name]',
  603. ],
  604. ['option' => ['value' => 'a']],
  605. '&gt;Albatross',
  606. '/option',
  607. ['option' => ['value' => 'b']],
  608. '&gt;Budgie',
  609. '/option',
  610. ['option' => ['value' => 'c']],
  611. '&gt;Canary',
  612. '/option',
  613. '/select'
  614. ];
  615. $this->assertHtml($expected, $result);
  616. $data = [
  617. 'escape' => false,
  618. 'name' => 'Birds[name]',
  619. 'options' => [
  620. '>a' => '>Albatross',
  621. ]
  622. ];
  623. $result = $select->render($data, $this->context);
  624. $expected = [
  625. 'select' => [
  626. 'name' => 'Birds[name]',
  627. ],
  628. ['option' => ['value' => '>a']],
  629. '>Albatross',
  630. '/option',
  631. '/select'
  632. ];
  633. $this->assertHtml($expected, $result);
  634. }
  635. /**
  636. * test render with null options
  637. *
  638. * @return void
  639. */
  640. public function testRenderNullOptions() {
  641. $select = new SelectBoxWidget($this->templates);
  642. $data = [
  643. 'id' => 'BirdName',
  644. 'name' => 'Birds[name]',
  645. 'options' => null
  646. ];
  647. $result = $select->render($data, $this->context);
  648. $expected = [
  649. 'select' => ['name' => 'Birds[name]', 'id' => 'BirdName'],
  650. '/select'
  651. ];
  652. $this->assertHtml($expected, $result);
  653. $data['empty'] = true;
  654. $result = $select->render($data, $this->context);
  655. $expected = [
  656. 'select' => ['name' => 'Birds[name]', 'id' => 'BirdName'],
  657. ['option' => ['value' => '']], '/option',
  658. '/select'
  659. ];
  660. $this->assertHtml($expected, $result);
  661. $data['empty'] = 'empty';
  662. $result = $select->render($data, $this->context);
  663. $expected = [
  664. 'select' => ['name' => 'Birds[name]', 'id' => 'BirdName'],
  665. ['option' => ['value' => '']], 'empty', '/option',
  666. '/select'
  667. ];
  668. $this->assertHtml($expected, $result);
  669. }
  670. }