personal-setting-calendar.spec.ts 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { visitView } from '#tests/support/components/visitView.ts'
  3. import { mockPermissions } from '#tests/support/mock-permissions.ts'
  4. import { getCurrentUserUpdatesSubscriptionHandler } from '#shared/graphql/subscriptions/currentUserUpdates.mocks.ts'
  5. import { useSessionStore } from '#shared/stores/session.ts'
  6. import {
  7. mockUserCurrentCalendarSubscriptionUpdate,
  8. waitForUserCurrentCalendarSubscriptionUpdateCalls,
  9. } from '../graphql/mutations/userCurrentCalendarSubscriptionUpdate.mocks.ts'
  10. import { mockUserCurrentCalendarSubscriptionList } from '../graphql/queries/userCurrentCalendarSubscriptionList.mocks.ts'
  11. describe('personal calendar subscription settings', () => {
  12. beforeEach(() => {
  13. mockPermissions(['user_preferences.calendar+ticket.agent'])
  14. mockUserCurrentCalendarSubscriptionList({
  15. userCurrentCalendarSubscriptionList: {
  16. combinedUrl: 'https://zammad.example.com/ical/tickets',
  17. globalOptions: {
  18. alarm: false,
  19. },
  20. escalation: {
  21. url: 'https://zammad.example.com/ical/tickets/escalation',
  22. options: {
  23. own: true,
  24. notAssigned: false,
  25. },
  26. },
  27. newOpen: {
  28. url: 'https://zammad.example.com/ical/tickets/new_open',
  29. options: {
  30. own: false,
  31. notAssigned: true,
  32. },
  33. },
  34. pending: {
  35. url: 'https://zammad.example.com/ical/tickets/pending',
  36. options: {
  37. own: true,
  38. notAssigned: true,
  39. },
  40. },
  41. },
  42. })
  43. })
  44. it('renders view correctly', async () => {
  45. const view = await visitView('personal-setting/calendar-subscriptions')
  46. expect(view.getByLabelText('Combined subscription URL')).toHaveValue(
  47. 'https://zammad.example.com/ical/tickets',
  48. )
  49. expect(
  50. view.getByLabelText(
  51. 'Add alarm to pending reminder and escalated tickets',
  52. ),
  53. ).toBeInTheDocument()
  54. expect(
  55. view.getByRole('tab', { name: 'Escalated Tickets' }),
  56. ).toBeInTheDocument()
  57. expect(
  58. view.getByRole('tab', { name: 'New & Open Tickets' }),
  59. ).toBeInTheDocument()
  60. expect(
  61. view.getByRole('tab', { name: 'Pending Tickets' }),
  62. ).toBeInTheDocument()
  63. })
  64. it('switches tab panels correctly', async () => {
  65. const view = await visitView('personal-setting/calendar-subscriptions')
  66. const escalationTab = view.getByRole('tab', { name: 'Escalated Tickets' })
  67. expect(escalationTab).toHaveAttribute('aria-selected', 'true')
  68. expect(view.getByLabelText('Direct subscription URL')).toHaveValue(
  69. 'https://zammad.example.com/ical/tickets/escalation',
  70. )
  71. expect(view.getAllByLabelText('My tickets')[0]).toBeChecked()
  72. expect(view.getAllByLabelText('Not assigned')[0]).not.toBeChecked()
  73. const newOpenTab = view.getByRole('tab', { name: 'New & Open Tickets' })
  74. await view.events.click(newOpenTab)
  75. expect(escalationTab).toHaveAttribute('aria-selected', 'false')
  76. expect(newOpenTab).toHaveAttribute('aria-selected', 'true')
  77. expect(view.getByLabelText('Direct subscription URL')).toHaveValue(
  78. 'https://zammad.example.com/ical/tickets/new_open',
  79. )
  80. expect(view.getAllByLabelText('My tickets')[1]).not.toBeChecked()
  81. expect(view.getAllByLabelText('Not assigned')[1]).toBeChecked()
  82. const pendingTab = view.getByRole('tab', { name: 'Pending Tickets' })
  83. await view.events.click(pendingTab)
  84. expect(newOpenTab).toHaveAttribute('aria-selected', 'false')
  85. expect(pendingTab).toHaveAttribute('aria-selected', 'true')
  86. expect(view.getByLabelText('Direct subscription URL')).toHaveValue(
  87. 'https://zammad.example.com/ical/tickets/pending',
  88. )
  89. expect(view.getAllByLabelText('My tickets')[2]).toBeChecked()
  90. expect(view.getAllByLabelText('Not assigned')[2]).toBeChecked()
  91. })
  92. it('updates calendar subscription when alarm is toggled', async () => {
  93. const view = await visitView('personal-setting/calendar-subscriptions')
  94. mockUserCurrentCalendarSubscriptionUpdate({
  95. userCurrentCalendarSubscriptionUpdate: {
  96. success: true,
  97. errors: null,
  98. },
  99. })
  100. await view.events.click(
  101. view.getByLabelText(
  102. 'Add alarm to pending reminder and escalated tickets',
  103. ),
  104. )
  105. const calls = await waitForUserCurrentCalendarSubscriptionUpdateCalls()
  106. expect(calls.at(-1)?.variables).toEqual({
  107. input: expect.objectContaining({
  108. alarm: true,
  109. }),
  110. })
  111. })
  112. it('updates calendar subscription when form is changed', async () => {
  113. const view = await visitView('personal-setting/calendar-subscriptions')
  114. mockUserCurrentCalendarSubscriptionUpdate({
  115. userCurrentCalendarSubscriptionUpdate: {
  116. success: true,
  117. errors: null,
  118. },
  119. })
  120. await view.events.click(view.getAllByLabelText('My tickets')[0])
  121. const calls = await waitForUserCurrentCalendarSubscriptionUpdateCalls()
  122. expect(calls.at(-1)?.variables).toEqual({
  123. input: expect.objectContaining({
  124. escalation: expect.objectContaining({
  125. own: false,
  126. }),
  127. }),
  128. })
  129. })
  130. it('updates calendar subscription when different tab is changed', async () => {
  131. const view = await visitView('personal-setting/calendar-subscriptions')
  132. await view.events.click(
  133. view.getByRole('tab', { name: 'New & Open Tickets' }),
  134. )
  135. mockUserCurrentCalendarSubscriptionUpdate({
  136. userCurrentCalendarSubscriptionUpdate: {
  137. success: true,
  138. errors: null,
  139. },
  140. })
  141. await view.events.click(view.getAllByLabelText('My tickets')[1])
  142. const calls = await waitForUserCurrentCalendarSubscriptionUpdateCalls()
  143. expect(calls.at(-1)?.variables).toEqual({
  144. input: expect.objectContaining({
  145. escalation: expect.objectContaining({
  146. own: true,
  147. }),
  148. }),
  149. })
  150. })
  151. it('resets state when session store is updated', async () => {
  152. const view = await visitView('personal-setting/calendar-subscriptions')
  153. // Mock opposite states than what was loaded with the initial request.
  154. mockUserCurrentCalendarSubscriptionList({
  155. userCurrentCalendarSubscriptionList: {
  156. combinedUrl: 'https://zammad.example.com/ical/tickets',
  157. globalOptions: {
  158. alarm: true,
  159. },
  160. escalation: {
  161. url: 'https://zammad.example.com/ical/tickets/escalation',
  162. options: {
  163. own: false,
  164. notAssigned: true,
  165. },
  166. },
  167. newOpen: {
  168. url: 'https://zammad.example.com/ical/tickets/new_open',
  169. options: {
  170. own: true,
  171. notAssigned: false,
  172. },
  173. },
  174. pending: {
  175. url: 'https://zammad.example.com/ical/tickets/pending',
  176. options: {
  177. own: false,
  178. notAssigned: false,
  179. },
  180. },
  181. },
  182. })
  183. // Trigger the current user query, so the user updates subscription is put in place.
  184. // Normally, this is not needed in the test environment, but here we depend on the mechanism, so we can trigger
  185. // the subscription located in the session store and in turn form updates.
  186. const { getCurrentUser } = useSessionStore()
  187. const user = await getCurrentUser()
  188. // Just trigger the subscription with the same data, new state will come from its own query anyway.
  189. await getCurrentUserUpdatesSubscriptionHandler().trigger({
  190. userUpdates: {
  191. user,
  192. },
  193. })
  194. expect(
  195. view.getByLabelText(
  196. 'Add alarm to pending reminder and escalated tickets',
  197. ),
  198. ).toBeChecked()
  199. expect(view.getAllByLabelText('My tickets')[0]).not.toBeChecked()
  200. expect(view.getAllByLabelText('Not assigned')[0]).toBeChecked()
  201. expect(view.getAllByLabelText('My tickets')[1]).toBeChecked()
  202. expect(view.getAllByLabelText('Not assigned')[1]).not.toBeChecked()
  203. expect(view.getAllByLabelText('My tickets')[2]).not.toBeChecked()
  204. expect(view.getAllByLabelText('Not assigned')[2]).not.toBeChecked()
  205. })
  206. })