1
0

combobox.spec.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  1. import { beVisible, beHidden, haveAttribute, haveClasses, notHaveClasses, haveText, contain, notContain, html, notBeVisible, notHaveAttribute, notExist, haveFocus, test, haveValue} from '../../../utils'
  2. test('it works with x-model',
  3. [html`
  4. <div
  5. x-data="{ active: null, people: [
  6. { id: 1, name: 'Wade Cooper' },
  7. { id: 2, name: 'Arlene Mccoy' },
  8. { id: 3, name: 'Devon Webb' },
  9. { id: 4, name: 'Tom Cook' },
  10. { id: 5, name: 'Tanya Fox', disabled: true },
  11. { id: 6, name: 'Hellen Schmidt' },
  12. { id: 7, name: 'Caroline Schultz' },
  13. { id: 8, name: 'Mason Heaney' },
  14. { id: 9, name: 'Claudie Smitham' },
  15. { id: 10, name: 'Emil Schaefer' },
  16. ]}"
  17. x-combobox
  18. x-model="active"
  19. >
  20. <label x-combobox:label>Assigned to</label>
  21. <input x-combobox:input :display-value="(person) => person.name" type="text">
  22. <button x-combobox:button x-text="active ? active.name : 'Select Person'"></button>
  23. <ul x-combobox:options>
  24. <template x-for="person in people" :key="person.id">
  25. <li
  26. x-combobox:option
  27. :value="person"
  28. :disabled="person.disabled"
  29. :option="person.id"
  30. >
  31. <span x-text="person.name"></span>
  32. </li>
  33. </template>
  34. </ul>
  35. <article x-text="active?.name"></article>
  36. </div>
  37. `],
  38. ({ get }) => {
  39. get('ul').should(notBeVisible())
  40. get('button')
  41. .should(haveText('Select Person'))
  42. .click()
  43. get('ul').should(beVisible())
  44. get('button').click()
  45. get('ul').should(notBeVisible())
  46. get('button').click()
  47. get('[option="2"]').click()
  48. get('ul').should(notBeVisible())
  49. get('button').should(haveText('Arlene Mccoy'))
  50. get('input').should(haveValue('Arlene Mccoy'))
  51. get('article').should(haveText('Arlene Mccoy'))
  52. },
  53. )
  54. test('it works with internal state',
  55. [html`
  56. <div
  57. x-data="{ people: [
  58. { id: 1, name: 'Wade Cooper' },
  59. { id: 2, name: 'Arlene Mccoy' },
  60. { id: 3, name: 'Devon Webb' },
  61. { id: 4, name: 'Tom Cook' },
  62. { id: 5, name: 'Tanya Fox', disabled: true },
  63. { id: 6, name: 'Hellen Schmidt' },
  64. { id: 7, name: 'Caroline Schultz' },
  65. { id: 8, name: 'Mason Heaney' },
  66. { id: 9, name: 'Claudie Smitham' },
  67. { id: 10, name: 'Emil Schaefer' },
  68. ]}"
  69. x-combobox
  70. >
  71. <label x-combobox:label>Assigned to</label>
  72. <input x-combobox:input :display-value="(person) => person.name" type="text">
  73. <button x-combobox:button x-text="$combobox.value ? $combobox.value.name : 'Select Person'"></button>
  74. <ul x-combobox:options>
  75. <template x-for="person in people" :key="person.id">
  76. <li
  77. :option="person.id"
  78. x-combobox:option
  79. :value="person"
  80. :disabled="person.disabled"
  81. >
  82. <span x-text="person.name"></span>
  83. </li>
  84. </template>
  85. </ul>
  86. </div>
  87. `],
  88. ({ get }) => {
  89. get('ul').should(notBeVisible())
  90. get('button')
  91. .should(haveText('Select Person'))
  92. .click()
  93. get('ul').should(beVisible())
  94. get('button').click()
  95. get('ul').should(notBeVisible())
  96. get('button').click()
  97. get('[option="2"]').click()
  98. get('ul').should(notBeVisible())
  99. get('button').should(haveText('Arlene Mccoy'))
  100. get('input').should(haveValue('Arlene Mccoy'))
  101. },
  102. )
  103. test('$combobox/$comboboxOption',
  104. [html`
  105. <div
  106. x-data="{ people: [
  107. { id: 1, name: 'Wade Cooper' },
  108. { id: 2, name: 'Arlene Mccoy' },
  109. { id: 3, name: 'Devon Webb' },
  110. { id: 4, name: 'Tom Cook' },
  111. { id: 5, name: 'Tanya Fox', disabled: true },
  112. { id: 6, name: 'Hellen Schmidt' },
  113. { id: 7, name: 'Caroline Schultz' },
  114. { id: 8, name: 'Mason Heaney' },
  115. { id: 9, name: 'Claudie Smitham' },
  116. { id: 10, name: 'Emil Schaefer' },
  117. ]}"
  118. x-combobox
  119. >
  120. <label x-combobox:label>Assigned to</label>
  121. <input x-combobox:input :display-value="(person) => person.name" type="text">
  122. <button x-combobox:button x-text="$combobox.value ? $combobox.value.name : 'Select Person'"></button>
  123. <p x-text="$combobox.activeIndex"></p>
  124. <article x-text="$combobox.activeOption?.name"></article>
  125. <ul x-combobox:options>
  126. <template x-for="person in people" :key="person.id">
  127. <li
  128. :option="person.id"
  129. x-combobox:option
  130. :value="person"
  131. :disabled="person.disabled"
  132. :class="{
  133. 'selected': $comboboxOption.isSelected,
  134. 'active': $comboboxOption.isActive,
  135. 'disabled': $comboboxOption.isDisabled,
  136. }"
  137. >
  138. <span x-text="person.name"></span>
  139. </li>
  140. </template>
  141. </ul>
  142. </div>
  143. `],
  144. ({ get }) => {
  145. get('article').should(haveText(''))
  146. get('[option="5"]').should(haveClasses(['disabled']))
  147. get('button')
  148. .should(haveText('Select Person'))
  149. .click()
  150. get('[option="1"]').should(haveClasses(['active']))
  151. get('input').type('{downarrow}')
  152. get('article').should(haveText('Arlene Mccoy'))
  153. get('p').should(haveText('1'))
  154. get('[option="2"]').should(haveClasses(['active']))
  155. get('button').should(haveText('Select Person'))
  156. get('[option="2"]').click()
  157. get('button').should(haveText('Arlene Mccoy'))
  158. get('[option="2"]').should(haveClasses(['selected']))
  159. },
  160. )
  161. test('"name" prop',
  162. [html`
  163. <div
  164. x-data="{ people: [
  165. { id: 1, name: 'Wade Cooper' },
  166. { id: 2, name: 'Arlene Mccoy' },
  167. { id: 3, name: 'Devon Webb' },
  168. { id: 4, name: 'Tom Cook' },
  169. { id: 5, name: 'Tanya Fox', disabled: true },
  170. { id: 6, name: 'Hellen Schmidt' },
  171. { id: 7, name: 'Caroline Schultz' },
  172. { id: 8, name: 'Mason Heaney' },
  173. { id: 9, name: 'Claudie Smitham' },
  174. { id: 10, name: 'Emil Schaefer' },
  175. ]}"
  176. x-combobox
  177. name="person"
  178. >
  179. <label x-combobox:label>Assigned to</label>
  180. <input x-combobox:input :display-value="(person) => person.name" type="text">
  181. <button x-combobox:button x-text="$combobox.value ? $combobox.value : 'Select Person'"></button>
  182. <ul x-combobox:options>
  183. <template x-for="person in people" :key="person.id">
  184. <li
  185. :option="person.id"
  186. x-combobox:option
  187. :value="person.id"
  188. :disabled="person.disabled"
  189. :class="{
  190. 'selected': $comboboxOption.isSelected,
  191. 'active': $comboboxOption.isActive,
  192. }"
  193. >
  194. <span x-text="person.name"></span>
  195. </li>
  196. </template>
  197. </ul>
  198. </div>
  199. `],
  200. ({ get }) => {
  201. get('input').should(haveAttribute('value', 'null'))
  202. get('button').click()
  203. get('input').should(haveAttribute('value', 'null'))
  204. get('[option="2"]').click()
  205. get('input').should(beHidden())
  206. .should(haveAttribute('name', 'person'))
  207. .should(haveAttribute('value', '2'))
  208. .should(haveAttribute('type', 'hidden'))
  209. get('button').click()
  210. get('[option="4"]').click()
  211. get('input').should(beHidden())
  212. .should(haveAttribute('name', 'person'))
  213. .should(haveAttribute('value', '4'))
  214. .should(haveAttribute('type', 'hidden'))
  215. },
  216. );
  217. test('"name" prop with object value',
  218. [html`
  219. <div
  220. x-data="{ people: [
  221. { id: 1, name: 'Wade Cooper' },
  222. { id: 2, name: 'Arlene Mccoy' },
  223. { id: 3, name: 'Devon Webb' },
  224. { id: 4, name: 'Tom Cook' },
  225. { id: 5, name: 'Tanya Fox', disabled: true },
  226. { id: 6, name: 'Hellen Schmidt' },
  227. { id: 7, name: 'Caroline Schultz' },
  228. { id: 8, name: 'Mason Heaney' },
  229. { id: 9, name: 'Claudie Smitham' },
  230. { id: 10, name: 'Emil Schaefer' },
  231. ]}"
  232. x-combobox
  233. name="person"
  234. >
  235. <label x-combobox:label>Assigned to</label>
  236. <input x-combobox:input :display-value="(person) => person.name" type="text">
  237. <button x-combobox:button x-text="$combobox.value ? $combobox.value.name : 'Select Person'"></button>
  238. <ul x-combobox:options>
  239. <template x-for="person in people" :key="person.id">
  240. <li
  241. :option="person.id"
  242. x-combobox:option
  243. :value="person"
  244. :disabled="person.disabled"
  245. :class="{
  246. 'selected': $comboboxOption.isSelected,
  247. 'active': $comboboxOption.isActive,
  248. }"
  249. >
  250. <span x-text="person.name"></span>
  251. </li>
  252. </template>
  253. </ul>
  254. </div>
  255. `],
  256. ({ get }) => {
  257. get('input[name="person"]').should(haveAttribute('value', 'null'))
  258. get('button').click()
  259. get('[name="person[id]"]').should(notExist())
  260. get('[option="2"]').click()
  261. get('input[name="person"]').should(notExist())
  262. get('[name="person[id]"]').should(beHidden())
  263. .should(haveAttribute('value', '2'))
  264. .should(haveAttribute('type', 'hidden'))
  265. get('[name="person[name]"]').should(beHidden())
  266. .should(haveAttribute('value', 'Arlene Mccoy'))
  267. .should(haveAttribute('type', 'hidden'))
  268. get('button').click()
  269. get('[option="4"]').click()
  270. get('[name="person[id]"]').should(beHidden())
  271. .should(haveAttribute('value', '4'))
  272. .should(haveAttribute('type', 'hidden'))
  273. get('[name="person[name]"]').should(beHidden())
  274. .should(haveAttribute('value', 'Tom Cook'))
  275. .should(haveAttribute('type', 'hidden'))
  276. },
  277. );
  278. test('"default-value" prop',
  279. [html`
  280. <div
  281. x-data="{ people: [
  282. { id: 1, name: 'Wade Cooper' },
  283. { id: 2, name: 'Arlene Mccoy' },
  284. { id: 3, name: 'Devon Webb' },
  285. { id: 4, name: 'Tom Cook' },
  286. { id: 5, name: 'Tanya Fox', disabled: true },
  287. { id: 6, name: 'Hellen Schmidt' },
  288. { id: 7, name: 'Caroline Schultz' },
  289. { id: 8, name: 'Mason Heaney' },
  290. { id: 9, name: 'Claudie Smitham' },
  291. { id: 10, name: 'Emil Schaefer' },
  292. ]}"
  293. x-combobox
  294. name="person"
  295. default-value="2"
  296. >
  297. <label x-combobox:label>Assigned to</label>
  298. <input x-combobox:input :display-value="(person) => person.name" type="text">
  299. <button x-combobox:button x-text="$combobox.value ? $combobox.value : 'Select Person'"></button>
  300. <ul x-combobox:options>
  301. <template x-for="person in people" :key="person.id">
  302. <li
  303. :option="person.id"
  304. x-combobox:option
  305. :value="person.id"
  306. :disabled="person.disabled"
  307. :class="{
  308. 'selected': $comboboxOption.isSelected,
  309. 'active': $comboboxOption.isActive,
  310. }"
  311. >
  312. <span x-text="person.name"></span>
  313. </li>
  314. </template>
  315. </ul>
  316. </div>
  317. `],
  318. ({ get }) => {
  319. get('input[name="person"]').should(beHidden())
  320. .should(haveAttribute('value', '2'))
  321. .should(haveAttribute('type', 'hidden'))
  322. },
  323. );
  324. test('"multiple" prop',
  325. [html`
  326. <div
  327. x-data="{
  328. people: [
  329. { id: 1, name: 'Wade Cooper' },
  330. { id: 2, name: 'Arlene Mccoy' },
  331. { id: 3, name: 'Devon Webb' },
  332. { id: 4, name: 'Tom Cook' },
  333. { id: 5, name: 'Tanya Fox', disabled: true },
  334. { id: 6, name: 'Hellen Schmidt' },
  335. { id: 7, name: 'Caroline Schultz' },
  336. { id: 8, name: 'Mason Heaney' },
  337. { id: 9, name: 'Claudie Smitham' },
  338. { id: 10, name: 'Emil Schaefer' },
  339. ]
  340. }"
  341. x-combobox
  342. multiple
  343. >
  344. <label x-combobox:label>Assigned to</label>
  345. <input x-combobox:input :display-value="(person) => person.name" type="text">
  346. <button x-combobox:button x-text="$combobox.value ? $combobox.value.join(',') : 'Select People'"></button>
  347. <ul x-combobox:options>
  348. <template x-for="person in people" :key="person.id">
  349. <li
  350. :option="person.id"
  351. x-combobox:option
  352. :value="person.id"
  353. :disabled="person.disabled"
  354. :class="{
  355. 'selected': $comboboxOption.isSelected,
  356. 'active': $comboboxOption.isActive,
  357. }"
  358. >
  359. <span x-text="person.name"></span>
  360. </li>
  361. </template>
  362. </ul>
  363. </div>
  364. `],
  365. ({ get }) => {
  366. get('button').click()
  367. get('[option="2"]').click()
  368. get('ul').should(beVisible())
  369. get('button').should(haveText('2'))
  370. get('[option="4"]').click()
  371. get('button').should(haveText('2,4'))
  372. get('ul').should(beVisible())
  373. get('[option="4"]').click()
  374. get('button').should(haveText('2'))
  375. get('ul').should(beVisible())
  376. },
  377. );
  378. test('"multiple" and "name" props together',
  379. [html`
  380. <div
  381. x-data="{
  382. people: [
  383. { id: 1, name: 'Wade Cooper' },
  384. { id: 2, name: 'Arlene Mccoy' },
  385. { id: 3, name: 'Devon Webb' },
  386. { id: 4, name: 'Tom Cook' },
  387. { id: 5, name: 'Tanya Fox', disabled: true },
  388. { id: 6, name: 'Hellen Schmidt' },
  389. { id: 7, name: 'Caroline Schultz' },
  390. { id: 8, name: 'Mason Heaney' },
  391. { id: 9, name: 'Claudie Smitham' },
  392. { id: 10, name: 'Emil Schaefer' },
  393. ]
  394. }"
  395. x-combobox
  396. multiple
  397. name="people"
  398. >
  399. <label x-combobox:label>Assigned to</label>
  400. <input x-combobox:input :display-value="(person) => person.name" type="text">
  401. <button x-combobox:button x-text="$combobox.value ? $combobox.value.map(p => p.id).join(',') : 'Select People'"></button>
  402. <ul x-combobox:options>
  403. <template x-for="person in people" :key="person.id">
  404. <li
  405. :option="person.id"
  406. x-combobox:option
  407. :value="person"
  408. :disabled="person.disabled"
  409. :class="{
  410. 'selected': $comboboxOption.isSelected,
  411. 'active': $comboboxOption.isActive,
  412. }"
  413. >
  414. <span x-text="person.name"></span>
  415. </li>
  416. </template>
  417. </ul>
  418. </div>
  419. `],
  420. ({ get }) => {
  421. // get('input[name="people"]').should(haveAttribute('value', 'null'))
  422. get('button').click()
  423. get('[name="people[0][id]"]').should(notExist())
  424. get('[option="2"]').click()
  425. get('ul').should(beVisible())
  426. get('button').should(haveText('2'))
  427. get('input[name="people"]').should(notExist())
  428. get('[name="people[0][id]"]').should(beHidden())
  429. .should(haveAttribute('value', '2'))
  430. .should(haveAttribute('type', 'hidden'))
  431. get('[name="people[0][name]"]').should(beHidden())
  432. .should(haveAttribute('value', 'Arlene Mccoy'))
  433. .should(haveAttribute('type', 'hidden'))
  434. get('[option="4"]').click()
  435. get('[name="people[0][id]"]').should(beHidden())
  436. .should(haveAttribute('value', '2'))
  437. .should(haveAttribute('type', 'hidden'))
  438. get('[name="people[0][name]"]').should(beHidden())
  439. .should(haveAttribute('value', 'Arlene Mccoy'))
  440. .should(haveAttribute('type', 'hidden'))
  441. get('[name="people[1][id]"]').should(beHidden())
  442. .should(haveAttribute('value', '4'))
  443. .should(haveAttribute('type', 'hidden'))
  444. get('[name="people[1][name]"]').should(beHidden())
  445. .should(haveAttribute('value', 'Tom Cook'))
  446. .should(haveAttribute('type', 'hidden'))
  447. get('button').should(haveText('2,4'))
  448. get('ul').should(beVisible())
  449. get('[option="4"]').click()
  450. get('[name="people[0][id]"]').should(beHidden())
  451. .should(haveAttribute('value', '2'))
  452. .should(haveAttribute('type', 'hidden'))
  453. get('[name="people[0][name]"]').should(beHidden())
  454. .should(haveAttribute('value', 'Arlene Mccoy'))
  455. .should(haveAttribute('type', 'hidden'))
  456. get('[name="people[1][id]"]').should(notExist())
  457. get('[name="people[1][name]"]').should(notExist())
  458. get('button').should(haveText('2'))
  459. get('ul').should(beVisible())
  460. },
  461. );
  462. test('keyboard controls',
  463. [html`
  464. <div
  465. x-data="{ active: null, people: [
  466. { id: 1, name: 'Wade Cooper' },
  467. { id: 2, name: 'Arlene Mccoy' },
  468. { id: 3, name: 'Devon Webb', disabled: true },
  469. { id: 4, name: 'Tom Cook' },
  470. { id: 5, name: 'Tanya Fox', disabled: true },
  471. { id: 6, name: 'Hellen Schmidt' },
  472. { id: 7, name: 'Caroline Schultz' },
  473. { id: 8, name: 'Mason Heaney' },
  474. { id: 9, name: 'Claudie Smitham' },
  475. { id: 10, name: 'Emil Schaefer' },
  476. ]}"
  477. x-combobox
  478. x-model="active"
  479. >
  480. <label x-combobox:label>Assigned to</label>
  481. <input x-combobox:input :display-value="(person) => person.name" type="text">
  482. <button x-combobox:button x-text="active ? active.name : 'Select Person'"></button>
  483. <ul x-combobox:options options>
  484. <template x-for="person in people" :key="person.id">
  485. <li
  486. :option="person.id"
  487. x-combobox:option
  488. :value="person"
  489. :disabled="person.disabled"
  490. :class="{
  491. 'selected': $comboboxOption.isSelected,
  492. 'active': $comboboxOption.isActive,
  493. }"
  494. >
  495. <span x-text="person.name"></span>
  496. </li>
  497. </template>
  498. </ul>
  499. </div>
  500. `],
  501. ({ get }) => {
  502. get('.active').should(notExist())
  503. get('button').click()
  504. get('[options]')
  505. .should(beVisible())
  506. get('input').should(haveFocus())
  507. get('[option="1"]')
  508. .should(haveClasses(['active']))
  509. get('input')
  510. .type('{downarrow}')
  511. get('[option="2"]')
  512. .should(haveClasses(['active']))
  513. get('input')
  514. .type('{downarrow}')
  515. get('[option="4"]')
  516. .should(haveClasses(['active']))
  517. get('input')
  518. .type('{uparrow}')
  519. get('[option="2"]')
  520. .should(haveClasses(['active']))
  521. get('input')
  522. .type('{home}')
  523. get('[option="1"]')
  524. .should(haveClasses(['active']))
  525. get('input')
  526. .type('{end}')
  527. get('[option="10"]')
  528. .should(haveClasses(['active']))
  529. get('input')
  530. .type('{pageUp}')
  531. get('[option="1"]')
  532. .should(haveClasses(['active']))
  533. get('input')
  534. .type('{pageDown}')
  535. get('[option="10"]')
  536. .should(haveClasses(['active']))
  537. get('input')
  538. .tab()
  539. .should(haveFocus())
  540. get('[options]')
  541. .should(beVisible())
  542. get('input')
  543. .type('{esc}')
  544. get('[options]')
  545. .should(notBeVisible())
  546. },
  547. )
  548. test('changing value manually changes internal state',
  549. [html`
  550. <div
  551. x-data="{ active: null, people: [
  552. { id: 1, name: 'Wade Cooper' },
  553. { id: 2, name: 'Arlene Mccoy' },
  554. { id: 3, name: 'Devon Webb', disabled: true },
  555. { id: 4, name: 'Tom Cook' },
  556. { id: 5, name: 'Tanya Fox', disabled: true },
  557. { id: 6, name: 'Hellen Schmidt' },
  558. { id: 7, name: 'Caroline Schultz' },
  559. { id: 8, name: 'Mason Heaney' },
  560. { id: 9, name: 'Claudie Smitham' },
  561. { id: 10, name: 'Emil Schaefer' },
  562. ]}"
  563. x-combobox
  564. x-model="active"
  565. >
  566. <label x-combobox:label>Assigned to</label>
  567. <input x-combobox:input :display-value="(person) => person.name" type="text">
  568. <button toggle x-combobox:button x-text="$combobox.value ? $combobox.value : 'Select Person'"></button>
  569. <button select-tim @click="active = 4">Select Tim</button>
  570. <ul x-combobox:options options>
  571. <template x-for="person in people" :key="person.id">
  572. <li
  573. :option="person.id"
  574. x-combobox:option
  575. :value="person.id"
  576. :disabled="person.disabled"
  577. :class="{
  578. 'selected': $comboboxOption.isSelected,
  579. 'active': $comboboxOption.isActive,
  580. }"
  581. >
  582. <span x-text="person.name"></span>
  583. </li>
  584. </template>
  585. </ul>
  586. </div>
  587. `],
  588. ({ get }) => {
  589. get('[select-tim]').click()
  590. get('[option="4"]').should(haveClasses(['selected']))
  591. get('[option="1"]').should(notHaveClasses(['selected']))
  592. get('[toggle]').should(haveText('4'))
  593. },
  594. )
  595. test('has accessibility attributes',
  596. [html`
  597. <div
  598. x-data="{ active: null, people: [
  599. { id: 1, name: 'Wade Cooper' },
  600. { id: 2, name: 'Arlene Mccoy' },
  601. { id: 3, name: 'Devon Webb', disabled: true },
  602. { id: 4, name: 'Tom Cook' },
  603. { id: 5, name: 'Tanya Fox', disabled: true },
  604. { id: 6, name: 'Hellen Schmidt' },
  605. { id: 7, name: 'Caroline Schultz' },
  606. { id: 8, name: 'Mason Heaney' },
  607. { id: 9, name: 'Claudie Smitham' },
  608. { id: 10, name: 'Emil Schaefer' },
  609. ]}"
  610. x-combobox
  611. x-model="active"
  612. >
  613. <label x-combobox:label>Assigned to</label>
  614. <input x-combobox:input :display-value="(person) => person.name" type="text">
  615. <button x-combobox:button x-text="active ? active.name : 'Select Person'"></button>
  616. <ul x-combobox:options options>
  617. <template x-for="person in people" :key="person.id">
  618. <li
  619. :option="person.id"
  620. x-combobox:option
  621. :value="person"
  622. :disabled="person.disabled"
  623. :class="{
  624. 'selected': $comboboxOption.isSelected,
  625. 'active': $comboboxOption.isActive,
  626. }"
  627. >
  628. <span x-text="person.name"></span>
  629. </li>
  630. </template>
  631. </ul>
  632. </div>
  633. `],
  634. ({ get }) => {
  635. get('button')
  636. .should(haveAttribute('aria-haspopup', 'true'))
  637. // @todo: decide if this is correct or if it should join the label and button IDs
  638. .should(haveAttribute('aria-labelledby', 'alpine-combobox-label-1 alpine-combobox-button-1'))
  639. .should(haveAttribute('aria-expanded', 'false'))
  640. .should(notHaveAttribute('aria-controls'))
  641. .should(haveAttribute('id', 'alpine-combobox-button-1'))
  642. .click()
  643. .should(haveAttribute('aria-expanded', 'true'))
  644. .should(haveAttribute('aria-controls', 'alpine-combobox-options-1'))
  645. get('[options]')
  646. .should(haveAttribute('role', 'combobox'))
  647. .should(haveAttribute('id', 'alpine-combobox-options-1'))
  648. .should(haveAttribute('aria-labelledby', 'alpine-combobox-label-1'))
  649. .should(notHaveAttribute('aria-activedescendant'))
  650. .should(haveAttribute('aria-activedescendant', 'alpine-combobox-option-1'))
  651. get('[option="1"]')
  652. .should(haveAttribute('role', 'option'))
  653. .should(haveAttribute('id', 'alpine-combobox-option-1'))
  654. .should(haveAttribute('tabindex', '-1'))
  655. .should(haveAttribute('aria-selected', 'false'))
  656. get('[option="2"]')
  657. .should(haveAttribute('role', 'option'))
  658. .should(haveAttribute('id', 'alpine-combobox-option-2'))
  659. .should(haveAttribute('tabindex', '-1'))
  660. .should(haveAttribute('aria-selected', 'false'))
  661. get('input')
  662. .type('{downarrow}')
  663. .should(haveAttribute('aria-activedescendant', 'alpine-combobox-option-2'))
  664. get('[option="2"]')
  665. .click()
  666. .should(haveAttribute('aria-selected', 'true'))
  667. },
  668. )
  669. test('"static" prop',
  670. [html`
  671. <div
  672. x-data="{ active: null, show: false, people: [
  673. { id: 1, name: 'Wade Cooper' },
  674. { id: 2, name: 'Arlene Mccoy' },
  675. { id: 3, name: 'Devon Webb' },
  676. { id: 4, name: 'Tom Cook' },
  677. { id: 5, name: 'Tanya Fox', disabled: true },
  678. { id: 6, name: 'Hellen Schmidt' },
  679. { id: 7, name: 'Caroline Schultz' },
  680. { id: 8, name: 'Mason Heaney' },
  681. { id: 9, name: 'Claudie Smitham' },
  682. { id: 10, name: 'Emil Schaefer' },
  683. ]}"
  684. x-combobox
  685. x-model="active"
  686. >
  687. <label x-combobox:label>Assigned to</label>
  688. <input x-combobox:input :display-value="(person) => person.name" type="text">
  689. <button normal-toggle x-combobox:button x-text="active ? active.name : 'Select Person'"></button>
  690. <button real-toggle @click="show = ! show">Toggle</button>
  691. <ul x-combobox:options x-show="show" static>
  692. <template x-for="person in people" :key="person.id">
  693. <li
  694. :option="person.id"
  695. x-combobox:option
  696. :value="person"
  697. :disabled="person.disabled"
  698. >
  699. <span x-text="person.name"></span>
  700. </li>
  701. </template>
  702. </ul>
  703. </div>
  704. `],
  705. ({ get }) => {
  706. get('ul').should(notBeVisible())
  707. get('[normal-toggle]')
  708. .should(haveText('Select Person'))
  709. .click()
  710. get('ul').should(notBeVisible())
  711. get('[real-toggle]').click()
  712. get('ul').should(beVisible())
  713. get('[option="2"]').click()
  714. get('ul').should(beVisible())
  715. get('[normal-toggle]').should(haveText('Arlene Mccoy'))
  716. },
  717. )