menu.spec.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import { haveClasses, beVisible, haveAttribute, haveText, html, notBeVisible, notExist, test, haveFocus, notHaveClasses, notHaveAttribute } from '../../../utils'
  2. test('it works',
  3. [html`
  4. <div x-data x-menu>
  5. <span>
  6. <button x-menu:button trigger>
  7. <span>Options</span>
  8. </button>
  9. </span>
  10. <div x-menu:items items>
  11. <div>
  12. <p>Signed in as</p>
  13. <p>tom@example.com</p>
  14. </div>
  15. <div>
  16. <a x-menu:item href="#account-settings">
  17. Account settings
  18. </a>
  19. <a x-menu:item href="#support">
  20. Support
  21. </a>
  22. <a x-menu:item disabled href="#new-feature">
  23. New feature (soon)
  24. </a>
  25. <a x-menu:item href="#license">
  26. License
  27. </a>
  28. </div>
  29. <div>
  30. <a x-menu:item href="#sign-out">
  31. Sign out
  32. </a>
  33. </div>
  34. </div>
  35. </div>`],
  36. ({ get }) => {
  37. get('[items]').should(notBeVisible())
  38. get('[trigger]').click()
  39. get('[items]').should(beVisible())
  40. },
  41. )
  42. test('keyboard controls',
  43. [html`
  44. <div x-data x-menu>
  45. <span>
  46. <button x-menu:button trigger>
  47. <span>Options</span>
  48. </button>
  49. </span>
  50. <div x-menu:items items>
  51. <div>
  52. <p>Signed in as</p>
  53. <p>tom@example.com</p>
  54. </div>
  55. <div>
  56. <a x-menu:item href="#account-settings" :class="$menuItem.isActive && 'active'">
  57. Account settings
  58. </a>
  59. <a x-menu:item href="#support" :class="$menuItem.isActive && 'active'">
  60. Support
  61. </a>
  62. <a x-menu:item disabled href="#new-feature" :class="$menuItem.isActive && 'active'">
  63. New feature (soon)
  64. </a>
  65. <a x-menu:item href="#license" :class="$menuItem.isActive && 'active'">
  66. License
  67. </a>
  68. </div>
  69. <div>
  70. <a x-menu:item href="#sign-out" :class="$menuItem.isActive && 'active'">
  71. Sign out
  72. </a>
  73. </div>
  74. </div>
  75. </div>`],
  76. ({ get }) => {
  77. get('.active').should(notExist())
  78. get('[trigger]').type(' ')
  79. get('[items]')
  80. .should(beVisible())
  81. .should(haveFocus())
  82. .type('{downarrow}')
  83. get('[href="#account-settings"]')
  84. .should(haveClasses(['active']))
  85. get('[items]')
  86. .type('{downarrow}')
  87. get('[href="#support"]')
  88. .should(haveClasses(['active']))
  89. get('[items]')
  90. .type('{uparrow}')
  91. get('[href="#account-settings"]')
  92. .should(haveClasses(['active']))
  93. get('[items]')
  94. .type('{home}')
  95. get('[href="#account-settings"]')
  96. .should(haveClasses(['active']))
  97. get('[items]')
  98. .type('{end}')
  99. get('[href="#sign-out"]')
  100. .should(haveClasses(['active']))
  101. get('[items]')
  102. .type('{pageUp}')
  103. get('[href="#account-settings"]')
  104. .should(haveClasses(['active']))
  105. get('[items]')
  106. .type('{pageDown}')
  107. get('[href="#sign-out"]')
  108. .should(haveClasses(['active']))
  109. get('[items]')
  110. .tab()
  111. .should(haveFocus())
  112. .should(beVisible())
  113. .tab({ shift: true})
  114. .should(haveFocus())
  115. .should(beVisible())
  116. .type('{esc}')
  117. .should(notBeVisible())
  118. },
  119. )
  120. test('has accessibility attributes',
  121. [html`
  122. <div x-data x-menu>
  123. <label x-menu:label>Options label</label>
  124. <span>
  125. <button x-menu:button trigger>
  126. <span>Options</span>
  127. </button>
  128. </span>
  129. <div x-menu:items items>
  130. <div>
  131. <p>Signed in as</p>
  132. <p>tom@example.com</p>
  133. </div>
  134. <div>
  135. <a x-menu:item href="#account-settings" :class="$menuItem.isActive && 'active'">
  136. Account settings
  137. </a>
  138. <a x-menu:item href="#support" :class="$menuItem.isActive && 'active'">
  139. Support
  140. </a>
  141. <a x-menu:item disabled href="#new-feature" :class="$menuItem.isActive && 'active'">
  142. New feature (soon)
  143. </a>
  144. <a x-menu:item href="#license" :class="$menuItem.isActive && 'active'">
  145. License
  146. </a>
  147. </div>
  148. <div>
  149. <a x-menu:item href="#sign-out" :class="$menuItem.isActive && 'active'">
  150. Sign out
  151. </a>
  152. </div>
  153. </div>
  154. </div>`],
  155. ({ get }) => {
  156. get('[trigger]')
  157. .should(haveAttribute('aria-haspopup', 'true'))
  158. .should(haveAttribute('aria-labelledby', 'alpine-menu-label-1'))
  159. .should(haveAttribute('aria-expanded', 'false'))
  160. .should(notHaveAttribute('aria-controls'))
  161. .should(haveAttribute('id', 'alpine-menu-button-1'))
  162. .click()
  163. .should(haveAttribute('aria-expanded', 'true'))
  164. .should(haveAttribute('aria-controls', 'alpine-menu-items-1'))
  165. get('[items]')
  166. .should(haveAttribute('aria-orientation', 'vertical'))
  167. .should(haveAttribute('role', 'menu'))
  168. .should(haveAttribute('id', 'alpine-menu-items-1'))
  169. .should(haveAttribute('aria-labelledby', 'alpine-menu-button-1'))
  170. .should(notHaveAttribute('aria-activedescendant'))
  171. .should(haveAttribute('tabindex', '0'))
  172. .type('{downarrow}')
  173. .should(haveAttribute('aria-activedescendant', 'alpine-menu-item-1'))
  174. get('[href="#account-settings"]')
  175. .should(haveAttribute('role', 'menuitem'))
  176. .should(haveAttribute('id', 'alpine-menu-item-1'))
  177. .should(haveAttribute('tabindex', '-1'))
  178. get('[href="#support"]')
  179. .should(haveAttribute('role', 'menuitem'))
  180. .should(haveAttribute('id', 'alpine-menu-item-2'))
  181. .should(haveAttribute('tabindex', '-1'))
  182. get('[items]')
  183. .type('{downarrow}')
  184. .should(haveAttribute('aria-activedescendant', 'alpine-menu-item-2'))
  185. },
  186. )