CommonSectionPopup.spec.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { flushPromises } from '@vue/test-utils'
  3. import { ref } from 'vue'
  4. import { renderComponent } from '#tests/support/components/index.ts'
  5. import CommonSectionPopup from '../CommonSectionPopup.vue'
  6. import type { PopupItemDescriptor } from '../types.ts'
  7. const html = String.raw
  8. describe('popup behaviour', () => {
  9. it('renders list', async () => {
  10. const onAction = vi.fn()
  11. const messages: PopupItemDescriptor[] = [
  12. {
  13. type: 'link',
  14. label: 'Link',
  15. link: '/',
  16. },
  17. {
  18. type: 'button',
  19. label: 'Action',
  20. onAction,
  21. },
  22. ]
  23. const view = renderComponent(CommonSectionPopup, {
  24. props: {
  25. messages,
  26. },
  27. router: true,
  28. vModel: {
  29. state: true,
  30. },
  31. })
  32. const [linkItem, actionItem] = messages
  33. const link = view.getByText(linkItem.label)
  34. const action = view.getByText(actionItem.label)
  35. expect(link).toBeInTheDocument()
  36. expect(action).toBeInTheDocument()
  37. expect(view.getLinkFromElement(link)).toHaveAttribute('href', '/mobile/')
  38. await view.events.click(action)
  39. expect(onAction).toHaveBeenCalledOnce()
  40. })
  41. it('can close list', async () => {
  42. const state = ref(true)
  43. const view = renderComponent(CommonSectionPopup, {
  44. props: {
  45. messages: [],
  46. },
  47. vModel: {
  48. state,
  49. },
  50. })
  51. await view.events.click(view.getByText('Cancel'))
  52. expect(view.queryByTestId('popupWindow')).not.toBeInTheDocument()
  53. state.value = true
  54. await flushPromises()
  55. expect(view.queryByTestId('popupWindow')).toBeInTheDocument()
  56. await view.events.click(document.body)
  57. expect(view.queryByTestId('popupWindow')).not.toBeInTheDocument()
  58. })
  59. it('autofocuses fist element and traps focus inside', async () => {
  60. const externalForm = document.createElement('form')
  61. externalForm.innerHTML = html`
  62. <input data-test-id="form_input" type="text" />
  63. <select data-test-id="form_select" type="text" />
  64. `
  65. document.body.appendChild(externalForm)
  66. const messages: PopupItemDescriptor[] = [
  67. {
  68. type: 'link',
  69. label: 'Link',
  70. link: '/',
  71. },
  72. {
  73. type: 'button',
  74. label: 'Action',
  75. onAction: vi.fn(),
  76. },
  77. ]
  78. const view = renderComponent(CommonSectionPopup, {
  79. props: {
  80. messages,
  81. },
  82. router: true,
  83. vModel: {
  84. state: true,
  85. },
  86. })
  87. await flushPromises()
  88. // auto focused on first item
  89. expect(view.getByText('Link')).toHaveFocus()
  90. await view.events.keyboard('{Tab}')
  91. expect(view.getByRole('button', { name: 'Action' })).toHaveFocus()
  92. await view.events.keyboard('{Tab}')
  93. expect(view.getByRole('button', { name: 'Cancel' })).toHaveFocus()
  94. await view.events.keyboard('{Tab}')
  95. expect(view.getByText('Link')).toHaveFocus()
  96. })
  97. it('refocuses on the last element that opened popup', async () => {
  98. const button = document.createElement('button')
  99. button.setAttribute('data-test-id', 'button')
  100. document.body.appendChild(button)
  101. button.focus()
  102. expect(button).toHaveFocus()
  103. const view = renderComponent(CommonSectionPopup, {
  104. props: {
  105. messages: [],
  106. },
  107. router: true,
  108. vModel: {
  109. state: true,
  110. },
  111. })
  112. await flushPromises()
  113. expect(button).not.toHaveFocus()
  114. await view.events.keyboard('{Escape}')
  115. expect(button).toHaveFocus()
  116. })
  117. it("doesn't refocuses on the last element that opened popup, when specified", async () => {
  118. const button = document.createElement('button')
  119. button.setAttribute('data-test-id', 'button')
  120. document.body.appendChild(button)
  121. button.focus()
  122. expect(button).toHaveFocus()
  123. const view = renderComponent(CommonSectionPopup, {
  124. props: {
  125. messages: [],
  126. noRefocus: true,
  127. },
  128. router: true,
  129. vModel: {
  130. state: true,
  131. },
  132. })
  133. await flushPromises()
  134. expect(button).not.toHaveFocus()
  135. await view.events.keyboard('{Escape}')
  136. expect(button).not.toHaveFocus()
  137. })
  138. it('closes list after clicking', async () => {
  139. const messages: PopupItemDescriptor[] = [
  140. {
  141. type: 'button',
  142. label: 'Hide Popup',
  143. },
  144. {
  145. type: 'button',
  146. label: 'Keep Popup',
  147. noHideOnSelect: true,
  148. },
  149. ]
  150. const view = renderComponent(CommonSectionPopup, {
  151. props: {
  152. messages,
  153. },
  154. router: true,
  155. vModel: {
  156. state: true,
  157. },
  158. })
  159. const [hideItem, keepItem] = messages
  160. await view.events.click(view.getByText(keepItem.label))
  161. expect(view.queryByTestId('popupWindow')).toBeInTheDocument()
  162. await view.events.click(view.getByText(hideItem.label))
  163. expect(view.queryByTestId('popupWindow')).not.toBeInTheDocument()
  164. })
  165. it('renders text message', async () => {
  166. const messages: PopupItemDescriptor[] = [
  167. {
  168. type: 'text',
  169. label: 'Some kind of text',
  170. },
  171. ]
  172. const view = renderComponent(CommonSectionPopup, {
  173. props: {
  174. messages,
  175. },
  176. router: true,
  177. vModel: {
  178. state: true,
  179. },
  180. })
  181. expect(view.getByText('Some kind of text')).toBeInTheDocument()
  182. await view.events.click(view.getByText('Some kind of text'))
  183. expect(view.queryByTestId('popupWindow')).toBeInTheDocument()
  184. })
  185. })