@patternfly/elements 4.1.0 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (318) hide show
  1. package/custom-elements.json +14909 -12588
  2. package/package.json +26 -17
  3. package/pf-accordion/pf-accordion-header.css +37 -0
  4. package/pf-accordion/pf-accordion-header.d.ts +0 -61
  5. package/pf-accordion/pf-accordion-header.js +180 -2
  6. package/pf-accordion/pf-accordion-header.js.map +1 -1
  7. package/pf-accordion/pf-accordion-panel.css +12 -0
  8. package/pf-accordion/pf-accordion-panel.d.ts +0 -34
  9. package/pf-accordion/pf-accordion-panel.js +87 -2
  10. package/pf-accordion/pf-accordion-panel.js.map +1 -1
  11. package/pf-accordion/pf-accordion.css +62 -0
  12. package/pf-accordion/pf-accordion.d.ts +1 -64
  13. package/pf-accordion/pf-accordion.js +156 -2
  14. package/pf-accordion/pf-accordion.js.map +1 -1
  15. package/pf-alert/pf-alert.css +193 -0
  16. package/pf-alert/pf-alert.d.ts +95 -0
  17. package/pf-alert/pf-alert.js +406 -0
  18. package/pf-alert/pf-alert.js.map +1 -0
  19. package/pf-alert/test/pf-alert.e2e.d.ts +1 -0
  20. package/pf-alert/test/pf-alert.e2e.js +45 -0
  21. package/pf-alert/test/pf-alert.e2e.js.map +1 -0
  22. package/pf-alert/test/pf-alert.spec.d.ts +1 -0
  23. package/pf-alert/test/pf-alert.spec.js +42 -0
  24. package/pf-alert/test/pf-alert.spec.js.map +1 -0
  25. package/pf-avatar/pf-avatar.css +14 -0
  26. package/pf-avatar/pf-avatar.d.ts +1 -14
  27. package/pf-avatar/pf-avatar.js +82 -2
  28. package/pf-avatar/pf-avatar.js.map +1 -1
  29. package/pf-back-to-top/pf-back-to-top.css +12 -0
  30. package/pf-back-to-top/pf-back-to-top.d.ts +1 -17
  31. package/pf-back-to-top/pf-back-to-top.js +87 -3
  32. package/pf-back-to-top/pf-back-to-top.js.map +1 -1
  33. package/pf-back-to-top/test/pf-back-to-top.spec.js +3 -2
  34. package/pf-back-to-top/test/pf-back-to-top.spec.js.map +1 -1
  35. package/pf-background-image/pf-background-image.css +7 -0
  36. package/pf-background-image/pf-background-image.d.ts +1 -8
  37. package/pf-background-image/pf-background-image.js +76 -2
  38. package/pf-background-image/pf-background-image.js.map +1 -1
  39. package/pf-badge/pf-badge.css +13 -0
  40. package/pf-badge/pf-badge.d.ts +1 -13
  41. package/pf-badge/pf-badge.js +53 -2
  42. package/pf-badge/pf-badge.js.map +1 -1
  43. package/pf-banner/pf-banner.css +21 -0
  44. package/pf-banner/pf-banner.d.ts +1 -19
  45. package/pf-banner/pf-banner.js +122 -2
  46. package/pf-banner/pf-banner.js.map +1 -1
  47. package/pf-button/pf-button-tokens.css +38 -0
  48. package/pf-button/pf-button.d.ts +1 -106
  49. package/pf-button/pf-button.js +837 -4
  50. package/pf-button/pf-button.js.map +1 -1
  51. package/pf-card/pf-card.css +24 -0
  52. package/pf-card/pf-card.d.ts +1 -38
  53. package/pf-card/pf-card.js +248 -2
  54. package/pf-card/pf-card.js.map +1 -1
  55. package/pf-chip/pf-chip-group.css +15 -0
  56. package/pf-chip/pf-chip-group.d.ts +0 -15
  57. package/pf-chip/pf-chip-group.js +111 -2
  58. package/pf-chip/pf-chip-group.js.map +1 -1
  59. package/pf-chip/pf-chip.css +30 -1
  60. package/pf-chip/pf-chip.d.ts +1 -20
  61. package/pf-chip/pf-chip.js +135 -2
  62. package/pf-chip/pf-chip.js.map +1 -1
  63. package/pf-clipboard-copy/pf-clipboard-copy.css +25 -0
  64. package/pf-clipboard-copy/pf-clipboard-copy.d.ts +1 -27
  65. package/pf-clipboard-copy/pf-clipboard-copy.js +318 -3
  66. package/pf-clipboard-copy/pf-clipboard-copy.js.map +1 -1
  67. package/pf-code-block/pf-code-block.css +11 -1
  68. package/pf-code-block/pf-code-block.js +70 -18
  69. package/pf-code-block/pf-code-block.js.map +1 -1
  70. package/pf-dropdown/pf-dropdown-group.js +40 -2
  71. package/pf-dropdown/pf-dropdown-group.js.map +1 -1
  72. package/pf-dropdown/pf-dropdown-item.css +10 -0
  73. package/pf-dropdown/pf-dropdown-item.d.ts +0 -27
  74. package/pf-dropdown/pf-dropdown-item.js +155 -2
  75. package/pf-dropdown/pf-dropdown-item.js.map +1 -1
  76. package/pf-dropdown/pf-dropdown-menu.js +39 -2
  77. package/pf-dropdown/pf-dropdown-menu.js.map +1 -1
  78. package/pf-dropdown/pf-dropdown.css +13 -1
  79. package/pf-dropdown/pf-dropdown.d.ts +1 -9
  80. package/pf-dropdown/pf-dropdown.js +357 -2
  81. package/pf-dropdown/pf-dropdown.js.map +1 -1
  82. package/pf-helper-text/pf-helper-text.css +35 -0
  83. package/pf-helper-text/pf-helper-text.d.ts +41 -0
  84. package/pf-helper-text/pf-helper-text.js +107 -0
  85. package/pf-helper-text/pf-helper-text.js.map +1 -0
  86. package/pf-helper-text/test/pf-helper-text.e2e.d.ts +1 -0
  87. package/pf-helper-text/test/pf-helper-text.e2e.js +23 -0
  88. package/pf-helper-text/test/pf-helper-text.e2e.js.map +1 -0
  89. package/pf-helper-text/test/pf-helper-text.spec.d.ts +1 -0
  90. package/pf-helper-text/test/pf-helper-text.spec.js +57 -0
  91. package/pf-helper-text/test/pf-helper-text.spec.js.map +1 -0
  92. package/pf-hint/pf-hint.css +120 -0
  93. package/pf-hint/pf-hint.d.ts +19 -0
  94. package/pf-hint/pf-hint.js +180 -0
  95. package/pf-hint/pf-hint.js.map +1 -0
  96. package/pf-hint/test/pf-hint.e2e.d.ts +1 -0
  97. package/pf-hint/test/pf-hint.e2e.js +23 -0
  98. package/pf-hint/test/pf-hint.e2e.js.map +1 -0
  99. package/pf-hint/test/pf-hint.spec.d.ts +1 -0
  100. package/pf-hint/test/pf-hint.spec.js +87 -0
  101. package/pf-hint/test/pf-hint.spec.js.map +1 -0
  102. package/pf-icon/pf-icon.css +1 -0
  103. package/pf-icon/pf-icon.d.ts +1 -3
  104. package/pf-icon/pf-icon.js +44 -4
  105. package/pf-icon/pf-icon.js.map +1 -1
  106. package/pf-jump-links/pf-jump-links-item.css +7 -1
  107. package/pf-jump-links/pf-jump-links-item.d.ts +0 -8
  108. package/pf-jump-links/pf-jump-links-item.js +77 -2
  109. package/pf-jump-links/pf-jump-links-item.js.map +1 -1
  110. package/pf-jump-links/pf-jump-links-list.css +3 -0
  111. package/pf-jump-links/pf-jump-links-list.d.ts +0 -5
  112. package/pf-jump-links/pf-jump-links-list.js +20 -2
  113. package/pf-jump-links/pf-jump-links-list.js.map +1 -1
  114. package/pf-jump-links/pf-jump-links.css +36 -0
  115. package/pf-jump-links/pf-jump-links.d.ts +1 -38
  116. package/pf-jump-links/pf-jump-links.js +179 -2
  117. package/pf-jump-links/pf-jump-links.js.map +1 -1
  118. package/pf-label/pf-label.css +51 -1
  119. package/pf-label/pf-label.d.ts +1 -58
  120. package/pf-label/pf-label.js +257 -2
  121. package/pf-label/pf-label.js.map +1 -1
  122. package/pf-modal/pf-modal.css +11 -0
  123. package/pf-modal/pf-modal.d.ts +2 -25
  124. package/pf-modal/pf-modal.js +215 -2
  125. package/pf-modal/pf-modal.js.map +1 -1
  126. package/pf-panel/pf-panel.css +29 -0
  127. package/pf-panel/pf-panel.d.ts +1 -32
  128. package/pf-panel/pf-panel.js +204 -2
  129. package/pf-panel/pf-panel.js.map +1 -1
  130. package/pf-popover/pf-popover.css +33 -0
  131. package/pf-popover/pf-popover.d.ts +1 -108
  132. package/pf-popover/pf-popover.js +251 -3
  133. package/pf-popover/pf-popover.js.map +1 -1
  134. package/pf-progress/pf-progress.css +19 -0
  135. package/pf-progress/pf-progress.d.ts +1 -57
  136. package/pf-progress/pf-progress.js +231 -2
  137. package/pf-progress/pf-progress.js.map +1 -1
  138. package/pf-progress-stepper/pf-progress-step.js +126 -2
  139. package/pf-progress-stepper/pf-progress-step.js.map +1 -1
  140. package/pf-progress-stepper/pf-progress-stepper.css +96 -0
  141. package/pf-progress-stepper/pf-progress-stepper.d.ts +1 -115
  142. package/pf-progress-stepper/pf-progress-stepper.js +326 -2
  143. package/pf-progress-stepper/pf-progress-stepper.js.map +1 -1
  144. package/pf-search-input/pf-search-input.css +308 -0
  145. package/pf-search-input/pf-search-input.d.ts +75 -0
  146. package/pf-search-input/pf-search-input.js +630 -0
  147. package/pf-search-input/pf-search-input.js.map +1 -0
  148. package/pf-search-input/test/pf-search-input.e2e.d.ts +1 -0
  149. package/pf-search-input/test/pf-search-input.e2e.js +23 -0
  150. package/pf-search-input/test/pf-search-input.e2e.js.map +1 -0
  151. package/pf-search-input/test/pf-search-input.spec.d.ts +1 -0
  152. package/pf-search-input/test/pf-search-input.spec.js +1021 -0
  153. package/pf-search-input/test/pf-search-input.spec.js.map +1 -0
  154. package/pf-select/pf-option-group.js +27 -2
  155. package/pf-select/pf-option-group.js.map +1 -1
  156. package/pf-select/pf-option.css +9 -1
  157. package/pf-select/pf-option.js +83 -2
  158. package/pf-select/pf-option.js.map +1 -1
  159. package/pf-select/pf-select.css +157 -0
  160. package/pf-select/pf-select.d.ts +1 -158
  161. package/pf-select/pf-select.js +542 -5
  162. package/pf-select/pf-select.js.map +1 -1
  163. package/pf-spinner/pf-spinner.css +13 -0
  164. package/pf-spinner/pf-spinner.d.ts +1 -14
  165. package/pf-spinner/pf-spinner.js +101 -2
  166. package/pf-spinner/pf-spinner.js.map +1 -1
  167. package/pf-switch/pf-switch.css +22 -0
  168. package/pf-switch/pf-switch.d.ts +1 -30
  169. package/pf-switch/pf-switch.js +156 -2
  170. package/pf-switch/pf-switch.js.map +1 -1
  171. package/pf-table/pf-caption.js +10 -2
  172. package/pf-table/pf-caption.js.map +1 -1
  173. package/pf-table/pf-table.css +211 -0
  174. package/pf-table/pf-table.d.ts +1 -635
  175. package/pf-table/pf-table.js +437 -2
  176. package/pf-table/pf-table.js.map +1 -1
  177. package/pf-table/pf-tbody.js +18 -2
  178. package/pf-table/pf-tbody.js.map +1 -1
  179. package/pf-table/pf-td.js +107 -2
  180. package/pf-table/pf-td.js.map +1 -1
  181. package/pf-table/pf-th.js +95 -2
  182. package/pf-table/pf-th.js.map +1 -1
  183. package/pf-table/pf-thead.js +20 -2
  184. package/pf-table/pf-thead.js.map +1 -1
  185. package/pf-table/pf-tr.js +89 -2
  186. package/pf-table/pf-tr.js.map +1 -1
  187. package/pf-tabs/pf-tab-panel.css +1 -0
  188. package/pf-tabs/pf-tab-panel.d.ts +0 -2
  189. package/pf-tabs/pf-tab-panel.js +19 -3
  190. package/pf-tabs/pf-tab-panel.js.map +1 -1
  191. package/pf-tabs/pf-tab.css +33 -0
  192. package/pf-tabs/pf-tab.d.ts +0 -40
  193. package/pf-tabs/pf-tab.js +231 -2
  194. package/pf-tabs/pf-tab.js.map +1 -1
  195. package/pf-tabs/pf-tabs.css +26 -0
  196. package/pf-tabs/pf-tabs.d.ts +1 -34
  197. package/pf-tabs/pf-tabs.js +307 -2
  198. package/pf-tabs/pf-tabs.js.map +1 -1
  199. package/pf-text-area/pf-text-area.css +125 -0
  200. package/pf-text-area/pf-text-area.d.ts +1 -125
  201. package/pf-text-area/pf-text-area.js +320 -2
  202. package/pf-text-area/pf-text-area.js.map +1 -1
  203. package/pf-text-input/pf-text-input.css +126 -0
  204. package/pf-text-input/pf-text-input.d.ts +1 -126
  205. package/pf-text-input/pf-text-input.js +395 -2
  206. package/pf-text-input/pf-text-input.js.map +1 -1
  207. package/pf-tile/pf-tile.css +28 -8
  208. package/pf-tile/pf-tile.d.ts +1 -24
  209. package/pf-tile/pf-tile.js +156 -2
  210. package/pf-tile/pf-tile.js.map +1 -1
  211. package/pf-timestamp/pf-timestamp.d.ts +1 -0
  212. package/pf-timestamp/pf-timestamp.js +10 -2
  213. package/pf-timestamp/pf-timestamp.js.map +1 -1
  214. package/pf-tooltip/pf-tooltip.css +10 -0
  215. package/pf-tooltip/pf-tooltip.d.ts +1 -79
  216. package/pf-tooltip/pf-tooltip.js +113 -3
  217. package/pf-tooltip/pf-tooltip.js.map +1 -1
  218. package/pfe.min.js +0 -7439
  219. package/pfe.min.js.LEGAL.txt +0 -57
  220. package/pfe.min.js.map +0 -7
  221. package/react/pf-accordion/pf-accordion-header.d.ts +0 -5
  222. package/react/pf-accordion/pf-accordion-header.js +0 -12
  223. package/react/pf-accordion/pf-accordion-panel.d.ts +0 -5
  224. package/react/pf-accordion/pf-accordion-panel.js +0 -10
  225. package/react/pf-accordion/pf-accordion.d.ts +0 -5
  226. package/react/pf-accordion/pf-accordion.js +0 -13
  227. package/react/pf-avatar/pf-avatar.d.ts +0 -5
  228. package/react/pf-avatar/pf-avatar.js +0 -12
  229. package/react/pf-back-to-top/pf-back-to-top.d.ts +0 -5
  230. package/react/pf-back-to-top/pf-back-to-top.js +0 -10
  231. package/react/pf-background-image/pf-background-image.d.ts +0 -5
  232. package/react/pf-background-image/pf-background-image.js +0 -10
  233. package/react/pf-badge/pf-badge.d.ts +0 -5
  234. package/react/pf-badge/pf-badge.js +0 -10
  235. package/react/pf-banner/pf-banner.d.ts +0 -5
  236. package/react/pf-banner/pf-banner.js +0 -10
  237. package/react/pf-button/pf-button.d.ts +0 -5
  238. package/react/pf-button/pf-button.js +0 -12
  239. package/react/pf-card/pf-card.d.ts +0 -5
  240. package/react/pf-card/pf-card.js +0 -10
  241. package/react/pf-chip/pf-chip-group.d.ts +0 -5
  242. package/react/pf-chip/pf-chip-group.js +0 -13
  243. package/react/pf-chip/pf-chip.d.ts +0 -5
  244. package/react/pf-chip/pf-chip.js +0 -13
  245. package/react/pf-clipboard-copy/pf-clipboard-copy.d.ts +0 -5
  246. package/react/pf-clipboard-copy/pf-clipboard-copy.js +0 -12
  247. package/react/pf-code-block/pf-code-block.d.ts +0 -5
  248. package/react/pf-code-block/pf-code-block.js +0 -10
  249. package/react/pf-dropdown/pf-dropdown-group.d.ts +0 -5
  250. package/react/pf-dropdown/pf-dropdown-group.js +0 -10
  251. package/react/pf-dropdown/pf-dropdown-item.d.ts +0 -5
  252. package/react/pf-dropdown/pf-dropdown-item.js +0 -10
  253. package/react/pf-dropdown/pf-dropdown-menu.d.ts +0 -5
  254. package/react/pf-dropdown/pf-dropdown-menu.js +0 -10
  255. package/react/pf-dropdown/pf-dropdown.d.ts +0 -5
  256. package/react/pf-dropdown/pf-dropdown.js +0 -14
  257. package/react/pf-icon/pf-icon.d.ts +0 -5
  258. package/react/pf-icon/pf-icon.js +0 -13
  259. package/react/pf-jump-links/pf-jump-links-item.d.ts +0 -5
  260. package/react/pf-jump-links/pf-jump-links-item.js +0 -13
  261. package/react/pf-jump-links/pf-jump-links-list.d.ts +0 -5
  262. package/react/pf-jump-links/pf-jump-links-list.js +0 -10
  263. package/react/pf-jump-links/pf-jump-links.d.ts +0 -5
  264. package/react/pf-jump-links/pf-jump-links.js +0 -12
  265. package/react/pf-label/pf-label.d.ts +0 -5
  266. package/react/pf-label/pf-label.js +0 -12
  267. package/react/pf-modal/pf-modal.d.ts +0 -5
  268. package/react/pf-modal/pf-modal.js +0 -13
  269. package/react/pf-panel/pf-panel.d.ts +0 -5
  270. package/react/pf-panel/pf-panel.js +0 -10
  271. package/react/pf-popover/pf-popover.d.ts +0 -5
  272. package/react/pf-popover/pf-popover.js +0 -10
  273. package/react/pf-progress/pf-progress.d.ts +0 -5
  274. package/react/pf-progress/pf-progress.js +0 -10
  275. package/react/pf-progress-stepper/pf-progress-step.d.ts +0 -5
  276. package/react/pf-progress-stepper/pf-progress-step.js +0 -10
  277. package/react/pf-progress-stepper/pf-progress-stepper.d.ts +0 -5
  278. package/react/pf-progress-stepper/pf-progress-stepper.js +0 -10
  279. package/react/pf-select/pf-option-group.d.ts +0 -5
  280. package/react/pf-select/pf-option-group.js +0 -10
  281. package/react/pf-select/pf-option.d.ts +0 -5
  282. package/react/pf-select/pf-option.js +0 -10
  283. package/react/pf-select/pf-select.d.ts +0 -5
  284. package/react/pf-select/pf-select.js +0 -13
  285. package/react/pf-spinner/pf-spinner.d.ts +0 -5
  286. package/react/pf-spinner/pf-spinner.js +0 -10
  287. package/react/pf-switch/pf-switch.d.ts +0 -5
  288. package/react/pf-switch/pf-switch.js +0 -12
  289. package/react/pf-table/pf-caption.d.ts +0 -5
  290. package/react/pf-table/pf-caption.js +0 -10
  291. package/react/pf-table/pf-table.d.ts +0 -5
  292. package/react/pf-table/pf-table.js +0 -10
  293. package/react/pf-table/pf-tbody.d.ts +0 -5
  294. package/react/pf-table/pf-tbody.js +0 -10
  295. package/react/pf-table/pf-td.d.ts +0 -5
  296. package/react/pf-table/pf-td.js +0 -10
  297. package/react/pf-table/pf-th.d.ts +0 -5
  298. package/react/pf-table/pf-th.js +0 -10
  299. package/react/pf-table/pf-thead.d.ts +0 -5
  300. package/react/pf-table/pf-thead.js +0 -10
  301. package/react/pf-table/pf-tr.d.ts +0 -5
  302. package/react/pf-table/pf-tr.js +0 -10
  303. package/react/pf-tabs/pf-tab-panel.d.ts +0 -5
  304. package/react/pf-tabs/pf-tab-panel.js +0 -10
  305. package/react/pf-tabs/pf-tab.d.ts +0 -5
  306. package/react/pf-tabs/pf-tab.js +0 -12
  307. package/react/pf-tabs/pf-tabs.d.ts +0 -5
  308. package/react/pf-tabs/pf-tabs.js +0 -10
  309. package/react/pf-text-area/pf-text-area.d.ts +0 -5
  310. package/react/pf-text-area/pf-text-area.js +0 -10
  311. package/react/pf-text-input/pf-text-input.d.ts +0 -5
  312. package/react/pf-text-input/pf-text-input.js +0 -10
  313. package/react/pf-tile/pf-tile.d.ts +0 -5
  314. package/react/pf-tile/pf-tile.js +0 -10
  315. package/react/pf-timestamp/pf-timestamp.d.ts +0 -5
  316. package/react/pf-timestamp/pf-timestamp.js +0 -10
  317. package/react/pf-tooltip/pf-tooltip.d.ts +0 -5
  318. package/react/pf-tooltip/pf-tooltip.js +0 -10
@@ -0,0 +1,1021 @@
1
+ import { aTimeout, expect, html, nextFrame } from '@open-wc/testing';
2
+ import { createFixture } from '@patternfly/pfe-tools/test/create-fixture.js';
3
+ import { PfSearchInput } from '../pf-search-input.js';
4
+ import { a11ySnapshot } from '@patternfly/pfe-tools/test/a11y-snapshot.js';
5
+ import { sendKeys } from '@web/test-runner-commands';
6
+ import { clickElementAtCenter, clickElementAtOffset } from '@patternfly/pfe-tools/test/utils.js';
7
+ function press(key) {
8
+ return async function () {
9
+ await sendKeys({ press: key });
10
+ };
11
+ }
12
+ // a11yShapshot does not surface the options
13
+ function getVisibleOptionValues(element) {
14
+ return element.options.filter(x => !x.hidden).map(x => x.value);
15
+ }
16
+ // a11yShapshot does not surface the options
17
+ function getActiveOption(element) {
18
+ return element.options.find(x => x.active);
19
+ }
20
+ /**
21
+ * NOTE because of the copy-to-shadow-root shtick in ActivedescendantController,
22
+ * we can't just pick an option (from light dom);
23
+ * @param element pf-select
24
+ * @param index item index
25
+ */
26
+ async function clickItemAtIndex(element, index) {
27
+ const itemHeight = 44;
28
+ await clickElementAtOffset(element, [
29
+ 10,
30
+ element.offsetHeight + (itemHeight * (index + 1)) - itemHeight / 2,
31
+ ], {
32
+ allowOutOfBounds: true,
33
+ });
34
+ }
35
+ describe('<pf-search-input>', function () {
36
+ describe('simply instantiating', function () {
37
+ let element;
38
+ it('imperatively instantiates', function () {
39
+ expect(document.createElement('pf-search-input')).to.be.an.instanceof(PfSearchInput);
40
+ });
41
+ it('should upgrade', async function () {
42
+ element = await createFixture(html `<pf-search-input></pf-search-input>`);
43
+ const klass = customElements.get('pf-search-input');
44
+ expect(element)
45
+ .to.be.an.instanceOf(klass)
46
+ .and
47
+ .to.be.an.instanceOf(PfSearchInput);
48
+ });
49
+ });
50
+ describe('with accessible-label attribute and 3 items', function () {
51
+ let element;
52
+ const updateComplete = () => element.updateComplete;
53
+ beforeEach(async function () {
54
+ element = await createFixture(html `
55
+ <pf-search-input accessible-label="label">
56
+ <pf-option value="1">1</pf-option>
57
+ <pf-option value="2">2</pf-option>
58
+ <pf-option value="3">3</pf-option>
59
+ </pf-search-input>`);
60
+ });
61
+ it('passes aXe audit', async function () {
62
+ await expect(element).to.be.accessible();
63
+ });
64
+ it('labels the combobox with the accessible-label attribuet', async function () {
65
+ expect(await a11ySnapshot()).to.axContainQuery({
66
+ role: 'combobox',
67
+ name: 'label',
68
+ });
69
+ });
70
+ it('does not have redundant role', async function () {
71
+ expect(element.shadowRoot?.firstElementChild).to.not.contain('[role="button"]');
72
+ });
73
+ it('sets aria-setsize="3" and aria-posinset on items', function () {
74
+ element.options.forEach((option, i) => {
75
+ expect(option).to.have.attr('aria-setsize', '3');
76
+ expect(option).to.have.attr('aria-posinset', `${i + 1}`);
77
+ });
78
+ });
79
+ describe('focus()', function () {
80
+ beforeEach(press('Tab'));
81
+ beforeEach(updateComplete);
82
+ describe('ArrowDown', function () {
83
+ beforeEach(press('ArrowDown'));
84
+ beforeEach(() => aTimeout(300));
85
+ beforeEach(updateComplete);
86
+ it('labels the listbox with the accessible-label attribute', async function () {
87
+ const snap = await a11ySnapshot();
88
+ expect(snap).to.axContainQuery({
89
+ role: 'listbox',
90
+ name: 'label',
91
+ });
92
+ });
93
+ it('focuses on the first item', async function () {
94
+ expect(getActiveOption(element)).to.have.value('1');
95
+ });
96
+ });
97
+ });
98
+ });
99
+ describe('with 3 items and associated <label> elements', function () {
100
+ let element;
101
+ const updateComplete = () => element.updateComplete;
102
+ beforeEach(async function () {
103
+ element = await createFixture(html `
104
+ <pf-search-input id="search">
105
+ <pf-option value="1">1</pf-option>
106
+ <pf-option value="2">2</pf-option>
107
+ <pf-option value="3">3</pf-option>
108
+ </pf-search-input>
109
+ <label for="search">label1</label>
110
+ <label for="search">label2</label>
111
+ `);
112
+ });
113
+ it('passes aXe audit', async function () {
114
+ await expect(element).to.be.accessible();
115
+ });
116
+ it('does not have redundant role', async function () {
117
+ expect(element.shadowRoot?.firstElementChild).to.not.contain('[role="button"]');
118
+ });
119
+ it('labels the combobox with the label elements', async function () {
120
+ expect(await a11ySnapshot()).to.axContainQuery({
121
+ role: 'combobox',
122
+ name: 'label1label2',
123
+ });
124
+ });
125
+ it('sets aria-setsize="3" and aria-posinset on items', function () {
126
+ element.options.forEach((option, i) => {
127
+ expect(option).to.have.attr('aria-setsize', '3');
128
+ expect(option).to.have.attr('aria-posinset', `${i + 1}`);
129
+ });
130
+ });
131
+ describe('focus()', function () {
132
+ beforeEach(press('Tab'));
133
+ beforeEach(updateComplete);
134
+ describe('ArrowDown', function () {
135
+ beforeEach(press('ArrowDown'));
136
+ beforeEach(() => aTimeout(300));
137
+ beforeEach(updateComplete);
138
+ it('labels the listbox with the label elements', async function () {
139
+ expect(await a11ySnapshot()).to.axContainQuery({
140
+ role: 'listbox',
141
+ name: 'label1label2',
142
+ });
143
+ });
144
+ });
145
+ });
146
+ });
147
+ describe('in a deep shadow root', function () {
148
+ let element;
149
+ const focus = () => element.focus();
150
+ const updateComplete = () => element.updateComplete;
151
+ beforeEach(async function () {
152
+ const fixture = await createFixture(html `
153
+ <shadow-root>
154
+ <template shadowrootmode="open">
155
+ <shadow-root>
156
+ <template shadowrootmode="open">
157
+ <pf-search-input
158
+ accessible-label="Search"
159
+ placeholder="Search">
160
+ <pf-option value="1">1</pf-option>
161
+ <pf-option value="2">2</pf-option>
162
+ <pf-option value="3">3</pf-option>
163
+ <pf-option value="4">4</pf-option>
164
+ <pf-option value="5">5</pf-option>
165
+ <pf-option value="6">6</pf-option>
166
+ <pf-option value="7">7</pf-option>
167
+ <pf-option value="8">8</pf-option>
168
+ </pf-search-input>
169
+ </template>
170
+ </shadow-root>
171
+ </template>
172
+ </shadow-root>`);
173
+ function attachShadowRoots(root) {
174
+ root?.querySelectorAll('template[shadowrootmode]').forEach(template => {
175
+ const mode = template.getAttribute('shadowrootmode');
176
+ const shadowRoot = template.parentElement?.attachShadow?.({ mode });
177
+ shadowRoot?.appendChild(template.content);
178
+ template.remove();
179
+ attachShadowRoots(shadowRoot);
180
+ });
181
+ }
182
+ attachShadowRoots(document);
183
+ const select = fixture.shadowRoot?.firstElementChild?.shadowRoot?.querySelector('pf-search-input');
184
+ if (select) {
185
+ element = select;
186
+ await element?.updateComplete;
187
+ }
188
+ else {
189
+ throw new Error('no element!');
190
+ }
191
+ });
192
+ describe('expanding', function () {
193
+ beforeEach(focus);
194
+ beforeEach(press('Enter'));
195
+ describe('ArrowDown', function () {
196
+ beforeEach(press('ArrowDown'));
197
+ beforeEach(() => aTimeout(300));
198
+ beforeEach(updateComplete);
199
+ it('remains expanded', function () {
200
+ expect(element.expanded).to.be.true;
201
+ });
202
+ describe('ArrowDown', function () {
203
+ beforeEach(press('ArrowDown'));
204
+ beforeEach(updateComplete);
205
+ it('remains expanded', function () {
206
+ expect(element.expanded).to.be.true;
207
+ });
208
+ });
209
+ });
210
+ });
211
+ });
212
+ describe('with 8 items', function () {
213
+ let element;
214
+ const updateComplete = () => element.updateComplete;
215
+ const focus = () => element.focus();
216
+ beforeEach(async function () {
217
+ element = await createFixture(html `
218
+ <pf-search-input>
219
+ <pf-option value="1">1</pf-option>
220
+ <pf-option value="2">2</pf-option>
221
+ <pf-option value="3">3</pf-option>
222
+ <pf-option value="4">4</pf-option>
223
+ <pf-option value="5">5</pf-option>
224
+ <pf-option value="6">6</pf-option>
225
+ <pf-option value="7">7</pf-option>
226
+ <pf-option value="8">8</pf-option>
227
+ </pf-search-input>`);
228
+ });
229
+ it('does not pass aXe audit', async function () {
230
+ await expect(element).to.not.be.accessible();
231
+ });
232
+ it('sets aria-setsize and aria-posinset on items', function () {
233
+ element.options.forEach((option, i) => {
234
+ expect(option).to.have.attr('aria-setsize', '8');
235
+ expect(option).to.have.attr('aria-posinset', `${i + 1}`);
236
+ });
237
+ });
238
+ describe('click combobox button', function () {
239
+ beforeEach(() => clickElementAtCenter(element));
240
+ beforeEach(() => aTimeout(300));
241
+ beforeEach(updateComplete);
242
+ it('does not pass aXe audit', async function () {
243
+ await expect(element).to.not.be.accessible();
244
+ });
245
+ it('expands the listbox', async function () {
246
+ expect(await a11ySnapshot()).to.axContainRole('listbox');
247
+ });
248
+ describe('Tab', function () {
249
+ beforeEach(press('Tab'));
250
+ it('does not focus the combobox button', async function () {
251
+ expect(await a11ySnapshot()).to.not.have.axTreeFocusedNode;
252
+ });
253
+ });
254
+ });
255
+ describe('focus()', function () {
256
+ beforeEach(focus);
257
+ beforeEach(updateComplete);
258
+ it('focuses on the combobox button', async function () {
259
+ expect(await a11ySnapshot()).axTreeFocusedNode.to.have.axRole('combobox');
260
+ });
261
+ it('does not expand the listbox', async function () {
262
+ expect(element.expanded).to.be.false;
263
+ expect(await a11ySnapshot()).to.not.axContainRole('listbox');
264
+ });
265
+ describe('Space', function () {
266
+ beforeEach(function () {
267
+ document.body.style.height = '8000px';
268
+ });
269
+ afterEach(function () {
270
+ document.body.style.height = 'initial';
271
+ });
272
+ beforeEach(press(' '));
273
+ beforeEach(updateComplete);
274
+ it('does not scroll the screen', function () {
275
+ expect(window.scrollY).to.equal(0);
276
+ });
277
+ });
278
+ describe('Home', function () {
279
+ beforeEach(press('Home'));
280
+ beforeEach(() => aTimeout(300));
281
+ beforeEach(updateComplete);
282
+ it('expands the listbox', async function () {
283
+ expect(await a11ySnapshot()).to.axContainRole('listbox');
284
+ });
285
+ });
286
+ describe('End', function () {
287
+ beforeEach(press('End'));
288
+ beforeEach(() => aTimeout(300));
289
+ beforeEach(updateComplete);
290
+ it('expands the listbox', async function () {
291
+ expect(await a11ySnapshot()).to.axContainRole('listbox');
292
+ });
293
+ });
294
+ describe('ArrowDown', function () {
295
+ beforeEach(press('ArrowDown'));
296
+ beforeEach(() => aTimeout(300));
297
+ beforeEach(updateComplete);
298
+ it('expands the listbox', async function () {
299
+ expect(element.expanded).to.be.true;
300
+ expect(await a11ySnapshot()).to.axContainRole('listbox');
301
+ });
302
+ describe('ArrowDown', function () {
303
+ beforeEach(press('ArrowDown'));
304
+ beforeEach(updateComplete);
305
+ it('focuses on option 2', async function () {
306
+ expect(getActiveOption(element)).to.have.value('2');
307
+ });
308
+ describe('ArrowUp', function () {
309
+ beforeEach(press('ArrowUp'));
310
+ beforeEach(updateComplete);
311
+ it('focuses on option 1', async function () {
312
+ expect(getActiveOption(element)).to.have.value('1');
313
+ });
314
+ });
315
+ describe('ArrowDown', async function () {
316
+ beforeEach(press('ArrowDown'));
317
+ beforeEach(updateComplete);
318
+ it('focuses on option 3', async function () {
319
+ expect(getActiveOption(element)).to.have.value('3');
320
+ });
321
+ describe('Enter', function () {
322
+ beforeEach(press('Enter'));
323
+ beforeEach(updateComplete);
324
+ it('selects option 3', function () {
325
+ expect(element.value).to.equal('3');
326
+ });
327
+ it('exposes selection to assistive technology', async function () {
328
+ expect(await a11ySnapshot()).to.axContainQuery({
329
+ role: 'combobox',
330
+ value: '3',
331
+ });
332
+ });
333
+ it('hides the listbox', async function () {
334
+ expect(element.expanded).to.be.false;
335
+ expect(await a11ySnapshot()).to.not.axContainRole('listbox');
336
+ });
337
+ });
338
+ });
339
+ });
340
+ describe('Escape', function () {
341
+ beforeEach(press('Escape'));
342
+ beforeEach(nextFrame);
343
+ beforeEach(updateComplete);
344
+ it('hides the listbox', async function () {
345
+ expect(element.expanded).to.be.false;
346
+ expect(await a11ySnapshot()).to.not.axContainRole('listbox');
347
+ });
348
+ it('focuses the button', async function () {
349
+ expect(await a11ySnapshot())
350
+ .axTreeFocusedNode
351
+ .to.have.axRole('combobox');
352
+ });
353
+ });
354
+ });
355
+ });
356
+ });
357
+ describe('with alphabetically sorted items', function () {
358
+ let element;
359
+ const label = 'label';
360
+ const updateComplete = () => element.updateComplete;
361
+ const focus = () => element.focus();
362
+ beforeEach(async function () {
363
+ element = await createFixture(html `
364
+ <pf-search-input >
365
+ <pf-option>Blue</pf-option>
366
+ <pf-option>Green</pf-option>
367
+ <pf-option>Magenta</pf-option>
368
+ <pf-option>Orange</pf-option>
369
+ <pf-option>Purple</pf-option>
370
+ <pf-option>Periwinkle</pf-option>
371
+ <pf-option>Pink</pf-option>
372
+ <pf-option>Red</pf-option>
373
+ <pf-option>Yellow</pf-option>
374
+ </pf-search-input>`);
375
+ });
376
+ beforeEach(nextFrame);
377
+ it('does not have redundant role', async function () {
378
+ expect(element.shadowRoot?.firstElementChild).to.not.contain('[role="button"]');
379
+ });
380
+ describe('with an `accessible-label` attribute', function () {
381
+ beforeEach(function () {
382
+ element.setAttribute('accessible-label', label);
383
+ });
384
+ beforeEach(nextFrame);
385
+ it('passes aXe audit', async function () {
386
+ await expect(element).to.be.accessible();
387
+ });
388
+ it('does not have redundant role', async function () {
389
+ expect(element.shadowRoot?.firstElementChild).to.not.contain('[role="button"]');
390
+ });
391
+ it('labels the combobox with the label', async function () {
392
+ expect(await a11ySnapshot()).to.axContainQuery({
393
+ role: 'combobox',
394
+ name: label,
395
+ });
396
+ });
397
+ describe('show()', function () {
398
+ beforeEach(() => element.show());
399
+ it('labels the listbox with the placeholder attribute', async function () {
400
+ expect(await a11ySnapshot()).to.axContainQuery({
401
+ role: 'listbox',
402
+ name: 'label',
403
+ });
404
+ });
405
+ });
406
+ });
407
+ describe('clicking the combobox input', function () {
408
+ beforeEach(async function () {
409
+ await clickElementAtOffset(element, [10, 10]);
410
+ });
411
+ beforeEach(() => aTimeout(300));
412
+ it('shows the listbox', async function () {
413
+ expect(element.expanded).to.be.true;
414
+ expect(await a11ySnapshot()).to.axContainRole('listbox');
415
+ });
416
+ it('focuses the combobox', async function () {
417
+ expect(element.expanded).to.be.true;
418
+ expect(await a11ySnapshot()).to.axContainQuery({
419
+ focused: true,
420
+ role: 'combobox',
421
+ });
422
+ });
423
+ describe('clicking option 1', function () {
424
+ beforeEach(async function () {
425
+ await clickItemAtIndex(element, 0);
426
+ });
427
+ it('selects option 1', function () {
428
+ expect(element.value).to.equal('Blue');
429
+ });
430
+ it('closes the listbox', async function () {
431
+ expect(await a11ySnapshot()).to.not.axContainRole('listbox');
432
+ });
433
+ });
434
+ describe('clicking option 2', function () {
435
+ beforeEach(async function () {
436
+ await clickItemAtIndex(element, 1);
437
+ });
438
+ it('selects option 1', function () {
439
+ expect(element.value).to.equal('Green');
440
+ });
441
+ it('closes the listbox', async function () {
442
+ expect(await a11ySnapshot()).to.not.axContainRole('listbox');
443
+ });
444
+ });
445
+ });
446
+ describe('focus()', function () {
447
+ beforeEach(press('Tab'));
448
+ beforeEach(updateComplete);
449
+ describe('"r"', function () {
450
+ beforeEach(press('r'));
451
+ beforeEach(() => aTimeout(300));
452
+ beforeEach(updateComplete);
453
+ it('only shows options that start with "r" or "R"', async function () {
454
+ expect(getVisibleOptionValues(element)).to.deep.equal([
455
+ 'Red',
456
+ ]);
457
+ });
458
+ });
459
+ describe('Space', function () {
460
+ beforeEach(function () {
461
+ document.body.style.height = '8000px';
462
+ });
463
+ afterEach(function () {
464
+ document.body.style.height = 'initial';
465
+ });
466
+ beforeEach(press(' '));
467
+ beforeEach(updateComplete);
468
+ beforeEach(() => aTimeout(300));
469
+ it('does not expand the listbox', async function () {
470
+ expect(await a11ySnapshot()).to.not.axContainRole('listbox');
471
+ });
472
+ it('does not scroll the screen', function () {
473
+ expect(window.scrollY).to.equal(0);
474
+ });
475
+ });
476
+ describe('ArrowDown', function () {
477
+ beforeEach(press('ArrowDown'));
478
+ beforeEach(updateComplete);
479
+ beforeEach(() => aTimeout(200));
480
+ it('shows the listbox', async function () {
481
+ expect(element.expanded).to.be.true;
482
+ expect(await a11ySnapshot()).to.axContainRole('listbox');
483
+ });
484
+ // Skipping the test case as the role is visible in the accessibility tree,
485
+ // and since the pf-button uses ElementInternals, the test case is unable to access the role.
486
+ it.skip('labels the close button with the label', async function () {
487
+ expect(await a11ySnapshot()).to.axContainQuery({
488
+ role: 'button',
489
+ name: 'close',
490
+ });
491
+ });
492
+ it('focuses option 1', function () {
493
+ expect(getActiveOption(element)).to.have.value('Blue');
494
+ });
495
+ it('does not move keyboard focus', async function () {
496
+ expect(await a11ySnapshot()).axTreeFocusedNode.to.have.axRole('combobox');
497
+ });
498
+ describe('ArrowDown', function () {
499
+ beforeEach(press('ArrowDown'));
500
+ beforeEach(updateComplete);
501
+ it('focuses option 2', function () {
502
+ expect(getActiveOption(element)).to.have.text('Green');
503
+ });
504
+ describe('Enter', function () {
505
+ beforeEach(press('Enter'));
506
+ beforeEach(updateComplete);
507
+ it('selects option 2', function () {
508
+ expect(element.value).to.equal('Green');
509
+ });
510
+ it('sets typeahead input to second option value', async function () {
511
+ expect(await a11ySnapshot())
512
+ .axTreeFocusedNode
513
+ .to.have.axProperty('value', 'Green');
514
+ });
515
+ it('retains focus on combobox input', async function () {
516
+ expect(await a11ySnapshot()).axTreeFocusedNode.to.have.axRole('combobox');
517
+ });
518
+ it('hides the listbox', async function () {
519
+ expect(await a11ySnapshot()).to.not.axContainRole('listbox');
520
+ });
521
+ describe('focus()', function () {
522
+ beforeEach(focus);
523
+ describe('ArrowDown', function () {
524
+ beforeEach(press('ArrowDown'));
525
+ beforeEach(() => aTimeout(300));
526
+ beforeEach(updateComplete);
527
+ it('only shows option 2', function () {
528
+ expect(getVisibleOptionValues(element)).to.deep.equal([
529
+ 'Green',
530
+ ]);
531
+ });
532
+ });
533
+ });
534
+ });
535
+ });
536
+ describe('ArrowUp', function () {
537
+ beforeEach(press('ArrowUp'));
538
+ beforeEach(updateComplete);
539
+ it('focuses the last item', async function () {
540
+ expect(getActiveOption(element)).to.have.value('Yellow');
541
+ });
542
+ });
543
+ });
544
+ describe('"p"', function () {
545
+ beforeEach(press('p'));
546
+ beforeEach(() => aTimeout(300));
547
+ beforeEach(updateComplete);
548
+ it('shows the listbox and maintains focus', async function () {
549
+ expect(await a11ySnapshot())
550
+ .to.axContainRole('listbox')
551
+ .and.axTreeFocusedNode
552
+ .to.have.axRole('combobox')
553
+ .and.to.have.axProperty('value', 'p');
554
+ });
555
+ it('only shows listbox items starting with the letter p', function () {
556
+ expect(getVisibleOptionValues(element)).to.deep.equal([
557
+ 'Purple',
558
+ 'Periwinkle',
559
+ 'Pink',
560
+ ]);
561
+ });
562
+ describe('Backspace', function () {
563
+ beforeEach(press('Backspace'));
564
+ beforeEach(updateComplete);
565
+ it('shows the listbox and maintains focus', async function () {
566
+ expect(await a11ySnapshot())
567
+ .to.axContainRole('listbox')
568
+ .and.axTreeFocusedNode
569
+ .to.have.axRole('combobox')
570
+ .and.to.not.have.axProperty('value', 'p');
571
+ });
572
+ it('all options are visible', async function () {
573
+ expect(getVisibleOptionValues(element)).to.deep.equal([
574
+ 'Blue',
575
+ 'Green',
576
+ 'Magenta',
577
+ 'Orange',
578
+ 'Purple',
579
+ 'Periwinkle',
580
+ 'Pink',
581
+ 'Red',
582
+ 'Yellow',
583
+ ]);
584
+ });
585
+ });
586
+ describe('"u"', function () {
587
+ beforeEach(press('u'));
588
+ beforeEach(updateComplete);
589
+ it('only shows the option "Purple"', function () {
590
+ expect(getVisibleOptionValues(element)).to.deep.equal([
591
+ 'Purple',
592
+ ]);
593
+ });
594
+ describe('ArrowDown', function () {
595
+ beforeEach(press('ArrowDown'));
596
+ beforeEach(updateComplete);
597
+ it('focuses the option "Purple"', function () {
598
+ expect(getActiveOption(element)).to.have.text('Purple');
599
+ });
600
+ describe('Enter', function () {
601
+ beforeEach(press('Enter'));
602
+ beforeEach(() => aTimeout(300));
603
+ beforeEach(updateComplete);
604
+ it('selects the option "Purple"', function () {
605
+ expect(element.value).to.equal('Purple');
606
+ });
607
+ describe('Backspace (x5)', function () {
608
+ beforeEach(press('Backspace'));
609
+ beforeEach(press('Backspace'));
610
+ beforeEach(press('Backspace'));
611
+ beforeEach(press('Backspace'));
612
+ beforeEach(press('Backspace'));
613
+ beforeEach(() => aTimeout(300));
614
+ beforeEach(updateComplete);
615
+ it('shows the options starting with "P"', function () {
616
+ expect(getVisibleOptionValues(element)).to.deep.equal([
617
+ 'Purple',
618
+ 'Periwinkle',
619
+ 'Pink',
620
+ ]);
621
+ });
622
+ describe('Home', function () {
623
+ beforeEach(press('Home'));
624
+ it('retains focus on the option "Purple"', function () {
625
+ expect(getActiveOption(element)).to.have.text('Purple');
626
+ });
627
+ it('moves cursor to start', function () {
628
+ // WARNING: ties test to DOM structure
629
+ const input = element.shadowRoot?.querySelector('input');
630
+ expect(input?.selectionStart).to.equal(0);
631
+ });
632
+ });
633
+ describe('End', function () {
634
+ beforeEach(press('End'));
635
+ it('retains focus on the option "Purple"', function () {
636
+ expect(getActiveOption(element)).to.have.text('Purple');
637
+ });
638
+ it('moves cursor to start', function () {
639
+ // WARNING: ties test to DOM structure
640
+ const input = element.shadowRoot?.querySelector('input');
641
+ expect(input?.selectionStart).to.equal(1);
642
+ });
643
+ });
644
+ });
645
+ });
646
+ });
647
+ });
648
+ });
649
+ });
650
+ describe.skip('setting filter to "*"', function () {
651
+ beforeEach(function () {
652
+ // @ts-expect-error: todo: add filter feature
653
+ element.filter = '*';
654
+ });
655
+ beforeEach(updateComplete);
656
+ it('does not error', async function () {
657
+ const snapshot = await a11ySnapshot();
658
+ const [, , listbox] = snapshot.children ?? [];
659
+ expect(listbox?.children).to.not.be.ok;
660
+ });
661
+ });
662
+ describe.skip('custom filtering', function () {
663
+ beforeEach(function () {
664
+ // @ts-expect-error: we intend to implement this in the next release
665
+ element.customFilter = option =>
666
+ // @ts-expect-error: TODO add filter feature
667
+ new RegExp(element.filter).test(option.value);
668
+ });
669
+ beforeEach(focus);
670
+ beforeEach(updateComplete);
671
+ describe('r', function () {
672
+ beforeEach(press('r'));
673
+ beforeEach(updateComplete);
674
+ it('shows options that contain "r"', async function () {
675
+ expect(getVisibleOptionValues(element)).to.deep.equal([
676
+ 'Green',
677
+ 'Orange',
678
+ 'Purple',
679
+ ]);
680
+ });
681
+ });
682
+ describe('typing "R"', function () {
683
+ beforeEach(press('R'));
684
+ beforeEach(nextFrame);
685
+ beforeEach(updateComplete);
686
+ it('shows options that start with "r"', async function () {
687
+ expect(getVisibleOptionValues(element)).to.deep.equal([
688
+ 'Red',
689
+ ]);
690
+ });
691
+ });
692
+ });
693
+ });
694
+ describe('with `disabled` attribute', function () {
695
+ let element;
696
+ const updateComplete = () => element.updateComplete;
697
+ const focus = () => element.focus();
698
+ beforeEach(async function () {
699
+ element = await createFixture(html `
700
+ <pf-search-input id="disabled-search" disabled>
701
+ <pf-option value="1">1</pf-option>
702
+ <pf-option value="2">2</pf-option>
703
+ <pf-option value="3">3</pf-option>
704
+ </pf-search-input>
705
+ <label for="disabled-search">Disabled</label>`);
706
+ await updateComplete();
707
+ });
708
+ it('passes aXe audit', async function () {
709
+ await expect(element).to.be.accessible();
710
+ });
711
+ it('is marked as disabled in accessibility tree', async function () {
712
+ expect(await a11ySnapshot()).to.axContainQuery({
713
+ role: 'combobox',
714
+ disabled: true,
715
+ });
716
+ });
717
+ describe('focus()', function () {
718
+ beforeEach(focus);
719
+ beforeEach(updateComplete);
720
+ describe('ArrowDown', function () {
721
+ beforeEach(press('ArrowDown'));
722
+ beforeEach(updateComplete);
723
+ it('does not open on focus and keyboard interaction', async function () {
724
+ // Should remain closed
725
+ expect(element.expanded).to.be.false;
726
+ expect(await a11ySnapshot()).to.not.axContainRole('listbox');
727
+ });
728
+ });
729
+ describe('"1" when input is disabled', function () {
730
+ beforeEach(press('1'));
731
+ beforeEach(() => aTimeout(300));
732
+ beforeEach(updateComplete);
733
+ it('does not show any options', async function () {
734
+ expect(element.expanded).to.be.false;
735
+ expect(await a11ySnapshot()).to.not.axContainRole('listbox');
736
+ });
737
+ it('does not add any value to the input', async function () {
738
+ const input = element.shadowRoot?.querySelector('input');
739
+ expect(input?.value).to.equal('');
740
+ });
741
+ });
742
+ });
743
+ describe('clicking the element', function () {
744
+ beforeEach(async function () {
745
+ await clickElementAtOffset(element, [10, 10]);
746
+ });
747
+ it('cannot be interacted with via click', async function () {
748
+ expect(element.expanded).to.be.false;
749
+ expect(await a11ySnapshot()).to.not.axContainRole('listbox');
750
+ });
751
+ });
752
+ });
753
+ describe('clicking the close button', function () {
754
+ let element;
755
+ const updateComplete = () => element.updateComplete;
756
+ const focus = () => element.focus();
757
+ beforeEach(async function () {
758
+ element = await createFixture(html `
759
+ <pf-search-input id="disabled-search" disabled>
760
+ <pf-option value="1">1</pf-option>
761
+ <pf-option value="2">2</pf-option>
762
+ <pf-option value="3">3</pf-option>
763
+ </pf-search-input>
764
+ <label for="disabled-search">Disabled</label>`);
765
+ await updateComplete();
766
+ });
767
+ it('passes aXe audit', async function () {
768
+ await expect(element).to.be.accessible();
769
+ });
770
+ describe('clicking the close button when list box is open', function () {
771
+ beforeEach(async function () {
772
+ await clickElementAtOffset(element, [-10, 10]);
773
+ });
774
+ it('hides the listbox', async function () {
775
+ expect(element.expanded).not.to.be.true;
776
+ expect(await a11ySnapshot()).to.not.axContainRole('listbox');
777
+ });
778
+ it('hides the close button', async function () {
779
+ expect(await a11ySnapshot()).not.to.axContainQuery({
780
+ name: 'close',
781
+ role: 'button',
782
+ });
783
+ });
784
+ it('removes the selected option value', async function () {
785
+ expect(element.value).to.be.undefined;
786
+ });
787
+ it('clears the input value', async function () {
788
+ const input = element.shadowRoot?.querySelector('input');
789
+ expect(input?.value).to.equal('');
790
+ });
791
+ });
792
+ describe('clicking the close button when list box is closed and input has value', function () {
793
+ describe('focus()', function () {
794
+ beforeEach(focus);
795
+ beforeEach(updateComplete);
796
+ describe(' press "z"', function () {
797
+ beforeEach(press('z'));
798
+ beforeEach(() => aTimeout(300));
799
+ beforeEach(updateComplete);
800
+ it('does not show any options', async function () {
801
+ expect(element.expanded).to.be.false;
802
+ expect(await a11ySnapshot()).to.not.axContainRole('listbox');
803
+ });
804
+ });
805
+ beforeEach(async function () {
806
+ await clickElementAtOffset(element, [-10, 10]);
807
+ });
808
+ it('hides the listbox', async function () {
809
+ expect(element.expanded).not.to.be.true;
810
+ expect(await a11ySnapshot()).to.not.axContainRole('listbox');
811
+ });
812
+ it('hides the close button', async function () {
813
+ expect(await a11ySnapshot()).not.to.axContainQuery({
814
+ name: 'close',
815
+ role: 'button',
816
+ });
817
+ });
818
+ it('clears the input value', async function () {
819
+ const input = element.shadowRoot?.querySelector('input');
820
+ expect(input?.value).to.equal('');
821
+ });
822
+ });
823
+ });
824
+ });
825
+ describe('Outside click behavior', function () {
826
+ let element;
827
+ const updateComplete = () => element.updateComplete;
828
+ const focus = () => element.focus();
829
+ let outsideElement;
830
+ beforeEach(async function () {
831
+ element = await createFixture(html `
832
+ <pf-search-input>
833
+ <pf-option value="11">11</pf-option>
834
+ <pf-option value="12">12</pf-option>
835
+ <pf-option value="13">13</pf-option>
836
+ <pf-option value="21">21</pf-option>
837
+ <pf-option value="22">22</pf-option>
838
+ <pf-option value="23">23</pf-option>
839
+ </pf-search-input>
840
+ `);
841
+ // Create a dummy div to represent an "outside" area
842
+ outsideElement = document.createElement('div');
843
+ outsideElement.style.width = '200px';
844
+ outsideElement.style.height = '200px';
845
+ document.body.appendChild(outsideElement);
846
+ });
847
+ describe('focus()', function () {
848
+ beforeEach(focus);
849
+ beforeEach(updateComplete);
850
+ describe('"1"', function () {
851
+ beforeEach(press('1'));
852
+ beforeEach(() => aTimeout(300));
853
+ beforeEach(updateComplete);
854
+ it('should open the listbox when focused', function () {
855
+ expect(element.expanded).to.be.true;
856
+ });
857
+ it('only shows options that start with "1"', async function () {
858
+ expect(getVisibleOptionValues(element)).to.deep.equal([
859
+ '11',
860
+ '12',
861
+ '13',
862
+ ]);
863
+ });
864
+ describe('click outside the element', function () {
865
+ // Click outside element
866
+ beforeEach(() => clickElementAtCenter(outsideElement));
867
+ beforeEach(() => aTimeout(300));
868
+ beforeEach(updateComplete);
869
+ it('should close the listbox when clicking outside', async function () {
870
+ expect(element.expanded).to.be.false;
871
+ });
872
+ it('should keep the entered value after outside click', async function () {
873
+ const input = element.shadowRoot?.querySelector('input');
874
+ expect(input?.value).to.equal('1');
875
+ });
876
+ });
877
+ });
878
+ });
879
+ });
880
+ describe('on focus-out behavior', function () {
881
+ let element;
882
+ const updateComplete = () => element.updateComplete;
883
+ const focus = () => element.focus();
884
+ beforeEach(async function () {
885
+ element = await createFixture(html `
886
+ <pf-search-input>
887
+ <pf-option value="11">11</pf-option>
888
+ <pf-option value="12">12</pf-option>
889
+ <pf-option value="13">13</pf-option>
890
+ <pf-option value="21">21</pf-option>
891
+ <pf-option value="22">22</pf-option>
892
+ <pf-option value="23">23</pf-option>
893
+ </pf-search-input>
894
+ `);
895
+ beforeEach(updateComplete);
896
+ });
897
+ describe('focus()', function () {
898
+ beforeEach(focus);
899
+ beforeEach(() => aTimeout(300));
900
+ beforeEach(updateComplete);
901
+ describe('"1"', function () {
902
+ beforeEach(press('1'));
903
+ beforeEach(() => aTimeout(300));
904
+ beforeEach(updateComplete);
905
+ it('should open the listbox when focused', function () {
906
+ expect(element.expanded).to.be.true;
907
+ });
908
+ it('only shows options that start with "1"', async function () {
909
+ expect(getVisibleOptionValues(element)).to.deep.equal([
910
+ '11',
911
+ '12',
912
+ '13',
913
+ ]);
914
+ });
915
+ describe('move the focus out of the element', function () {
916
+ beforeEach(press('Tab'));
917
+ beforeEach(() => aTimeout(300));
918
+ beforeEach(updateComplete);
919
+ beforeEach(press('Tab'));
920
+ beforeEach(() => aTimeout(300));
921
+ beforeEach(updateComplete);
922
+ it('should close the listbox when focused out', async function () {
923
+ expect(element.expanded).to.be.false;
924
+ });
925
+ it('should keep the entered value after focus out', async function () {
926
+ const input = element.shadowRoot?.querySelector('input');
927
+ expect(input?.value).to.equal('1');
928
+ });
929
+ });
930
+ });
931
+ });
932
+ });
933
+ describe('form submission with pf-search-input', function () {
934
+ let form;
935
+ let searchInput;
936
+ const updateComplete = () => searchInput.updateComplete;
937
+ const focus = () => searchInput.focus();
938
+ let submittedData;
939
+ beforeEach(async function () {
940
+ form = await createFixture(html `
941
+ <form>
942
+ <pf-search-input name="search">
943
+ <pf-option value="Alabama">Alabama</pf-option>
944
+ <pf-option value="New York">New York</pf-option>
945
+ <pf-option value="New Jersey">New Jersey</pf-option>
946
+ </pf-search-input>
947
+ <button type="submit">Submit</button>
948
+ </form>
949
+ `);
950
+ searchInput = form.querySelector('pf-search-input');
951
+ beforeEach(updateComplete);
952
+ form.addEventListener('submit', e => {
953
+ e.preventDefault();
954
+ submittedData = new FormData(form);
955
+ });
956
+ });
957
+ describe('when a user types and selects an option', function () {
958
+ describe('focus', function () {
959
+ beforeEach(focus);
960
+ beforeEach(() => aTimeout(300));
961
+ beforeEach(updateComplete);
962
+ describe('press `New`', function () {
963
+ beforeEach(updateComplete);
964
+ beforeEach(() => aTimeout(300));
965
+ beforeEach(press('N'));
966
+ beforeEach(() => aTimeout(300));
967
+ beforeEach(press('e'));
968
+ beforeEach(() => aTimeout(300));
969
+ beforeEach(press('w'));
970
+ describe('select the first option starting with `New` and submit the form', function () {
971
+ beforeEach(updateComplete);
972
+ beforeEach(() => aTimeout(300));
973
+ beforeEach(press('ArrowDown'));
974
+ beforeEach(() => aTimeout(300));
975
+ beforeEach(press('Enter'));
976
+ beforeEach(updateComplete);
977
+ it('should select the option', function () {
978
+ expect(searchInput.value).to.equal('New York');
979
+ });
980
+ it('should close the dropdown after selection', function () {
981
+ expect(searchInput.expanded).to.be.false;
982
+ });
983
+ it('should keep selected value in input after submission', function () {
984
+ const input = searchInput.shadowRoot?.querySelector('input');
985
+ expect(input?.value).to.equal('New York');
986
+ });
987
+ describe('on form submit event', function () {
988
+ it('should submit the selected value from pf-search-input', async function () {
989
+ const event = new SubmitEvent('submit', {
990
+ bubbles: true,
991
+ cancelable: true,
992
+ });
993
+ form.dispatchEvent(event);
994
+ expect(event.defaultPrevented).to.be.true;
995
+ expect(submittedData).to.not.be.null;
996
+ expect(submittedData?.get('search')).to.equal('New York');
997
+ });
998
+ });
999
+ describe('on submit button click', function () {
1000
+ it('should submit the selected value', async function () {
1001
+ form.querySelector('button')?.click();
1002
+ beforeEach(() => aTimeout(300));
1003
+ expect(submittedData).to.not.be.null;
1004
+ expect(submittedData?.get('search')).to.equal('New York');
1005
+ });
1006
+ });
1007
+ describe('form submit on clicking `enter` key', function () {
1008
+ beforeEach(press('Enter'));
1009
+ beforeEach(updateComplete);
1010
+ it('should submit the selected value', function () {
1011
+ expect(submittedData).to.not.be.null;
1012
+ expect(submittedData?.get('search')).to.equal('New York');
1013
+ });
1014
+ });
1015
+ });
1016
+ });
1017
+ });
1018
+ });
1019
+ });
1020
+ });
1021
+ //# sourceMappingURL=pf-search-input.spec.js.map