ticket-detail-view-time-accounting.spec.ts 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { getNode } from '@formkit/core'
  3. import { within } from '@testing-library/vue'
  4. import { expect } from 'vitest'
  5. import { visitView } from '#tests/support/components/visitView.ts'
  6. import { mockApplicationConfig } from '#tests/support/mock-applicationConfig.ts'
  7. import { mockPermissions } from '#tests/support/mock-permissions.ts'
  8. import { mockFormUpdaterQuery } from '#shared/components/Form/graphql/queries/formUpdater.mocks.ts'
  9. import {
  10. mockTicketUpdateMutation,
  11. waitForTicketUpdateMutationCalls,
  12. } from '#shared/entities/ticket/graphql/mutations/update.mocks.ts'
  13. import { mockTicketQuery } from '#shared/entities/ticket/graphql/queries/ticket.mocks.ts'
  14. import { createDummyTicket } from '#shared/entities/ticket-article/__tests__/mocks/ticket.ts'
  15. import { EnumUserErrorException } from '#shared/graphql/types.ts'
  16. import { convertToGraphQLId } from '#shared/graphql/utils.ts'
  17. describe('Ticket detail view', () => {
  18. beforeEach(() => {
  19. mockPermissions(['ticket.agent'])
  20. })
  21. describe('Time accounting', () => {
  22. it('opens time accounting flyout when the condition is met', async () => {
  23. mockApplicationConfig({
  24. ui_ticket_zoom_article_note_new_internal: true,
  25. time_accounting: true,
  26. time_accounting_unit: '',
  27. time_accounting_types: false,
  28. })
  29. const ticket = createDummyTicket({
  30. state: {
  31. id: convertToGraphQLId('Ticket::State', 2),
  32. name: 'open',
  33. stateType: {
  34. id: convertToGraphQLId('TicketStateType', 2),
  35. name: 'open',
  36. },
  37. },
  38. articleType: 'email',
  39. defaultPolicy: {
  40. update: true,
  41. agentReadAccess: true,
  42. },
  43. })
  44. mockTicketQuery({
  45. ticket,
  46. })
  47. mockFormUpdaterQuery({
  48. formUpdater: {
  49. fields: {
  50. group_id: {
  51. options: [
  52. {
  53. value: 1,
  54. label: 'Users',
  55. },
  56. {
  57. value: 2,
  58. label: 'test group',
  59. },
  60. ],
  61. },
  62. owner_id: {
  63. options: [
  64. {
  65. value: 3,
  66. label: 'Test Admin Agent',
  67. },
  68. ],
  69. },
  70. state_id: {
  71. options: [
  72. {
  73. value: 4,
  74. label: 'closed',
  75. },
  76. {
  77. value: 2,
  78. label: 'open',
  79. },
  80. {
  81. value: 6,
  82. label: 'pending close',
  83. },
  84. {
  85. value: 3,
  86. label: 'pending reminder',
  87. },
  88. ],
  89. },
  90. pending_time: {
  91. show: false,
  92. },
  93. priority_id: {
  94. options: [
  95. {
  96. value: 1,
  97. label: '1 low',
  98. },
  99. {
  100. value: 2,
  101. label: '2 normal',
  102. },
  103. {
  104. value: 3,
  105. label: '3 high',
  106. },
  107. ],
  108. },
  109. },
  110. flags: {
  111. newArticlePresent: false,
  112. },
  113. },
  114. })
  115. const view = await visitView('/tickets/1')
  116. await view.events.click(
  117. await view.findByRole('button', { name: 'Add internal note' }),
  118. )
  119. await view.events.type(
  120. await view.findByRole('textbox', { name: 'Text' }),
  121. 'Foo note',
  122. )
  123. mockTicketUpdateMutation({
  124. ticketUpdate: {
  125. ticket: null,
  126. errors: [
  127. {
  128. message: 'The ticket time accounting condition is met.',
  129. exception:
  130. EnumUserErrorException.ServiceTicketUpdateValidatorTimeAccountingError,
  131. },
  132. ],
  133. },
  134. })
  135. mockFormUpdaterQuery({
  136. formUpdater: {
  137. fields: {},
  138. },
  139. })
  140. await view.events.click(
  141. await view.findByRole('button', { name: 'Update' }),
  142. )
  143. await waitForTicketUpdateMutationCalls()
  144. const flyout = await view.findByRole('complementary', {
  145. name: 'Time Accounting',
  146. })
  147. expect(
  148. within(flyout).getByRole('heading', {
  149. level: 2,
  150. }),
  151. ).toHaveTextContent('Time Accounting')
  152. await view.events.type(
  153. await within(flyout).findByLabelText('Accounted Time'),
  154. '1',
  155. )
  156. await getNode('form-ticket-time-accounting')?.settled
  157. mockTicketUpdateMutation({
  158. ticketUpdate: {
  159. ticket,
  160. errors: null,
  161. },
  162. })
  163. await view.events.click(
  164. within(flyout).getByRole('button', {
  165. name: 'Account Time',
  166. }),
  167. )
  168. const calls = await waitForTicketUpdateMutationCalls()
  169. expect(calls.at(-1)?.variables).toEqual(
  170. expect.objectContaining({
  171. input: expect.objectContaining({
  172. article: expect.objectContaining({
  173. timeUnit: 1,
  174. }),
  175. }),
  176. }),
  177. )
  178. expect(
  179. view.queryByRole('complementary', {
  180. name: 'Time Accounting',
  181. }),
  182. ).not.toBeInTheDocument()
  183. })
  184. })
  185. })