user-detail.spec.ts 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { getTestRouter } from '#tests/support/components/renderComponent.ts'
  3. import { visitView } from '#tests/support/components/visitView.ts'
  4. import {
  5. mockGraphQLApi,
  6. mockGraphQLSubscription,
  7. } from '#tests/support/mock-graphql-api.ts'
  8. import { setupView } from '#tests/support/mock-user.ts'
  9. import { waitUntil, waitUntilApisResolved } from '#tests/support/utils.ts'
  10. import { UserDocument } from '#shared/entities/user/graphql/queries/user.api.ts'
  11. import { UserUpdatesDocument } from '#shared/graphql/subscriptions/userUpdates.api.ts'
  12. import {
  13. defaultUser,
  14. mockUserDetailsApis,
  15. } from '#mobile/entities/user/__tests__/mocks/user-mocks.ts'
  16. describe('visiting user page', () => {
  17. test('view static content', async () => {
  18. const { mockUser, mockAttributes, user } = mockUserDetailsApis()
  19. const view = await visitView(`/users/${user.internalId}`)
  20. await waitUntilApisResolved(mockUser, mockAttributes)
  21. const organization = user.organization!
  22. expect(
  23. view.getByRole('img', { name: 'Avatar (John Doe)' }),
  24. ).toBeInTheDocument()
  25. const organizationLink = view.getByRole('link', {
  26. name: organization.name!,
  27. })
  28. expect(organizationLink).toBeInTheDocument()
  29. expect(organizationLink).toHaveAttribute(
  30. 'href',
  31. `/mobile/organizations/${organization.internalId}`,
  32. )
  33. expect(
  34. view.queryByRole('region', { name: 'First name' }),
  35. ).not.toBeInTheDocument()
  36. expect(
  37. view.queryByRole('region', { name: 'Last name' }),
  38. ).not.toBeInTheDocument()
  39. const ticketOpenLink = view.getByRole('link', { name: 'open 4' })
  40. const ticketClosedLink = view.getByRole('link', { name: 'closed 2' })
  41. expect(ticketOpenLink).toHaveAttribute(
  42. 'href',
  43. expect.stringContaining(`customer.id: ${user.internalId}`),
  44. )
  45. expect(ticketClosedLink).toHaveAttribute(
  46. 'href',
  47. expect.stringContaining(`customer.id: ${user.internalId}`),
  48. )
  49. expect(view.getByText('Secondary organizations')).toBeInTheDocument()
  50. expect(view.getByText('Dammaz')).toBeInTheDocument()
  51. })
  52. test('can toggle tickets count view', async () => {
  53. const { mockUser, mockAttributes, user } = mockUserDetailsApis()
  54. const view = await visitView(`/users/${user.internalId}`)
  55. await waitUntilApisResolved(mockUser, mockAttributes)
  56. const ticketOpenLink = view.getByRole('link', { name: 'open 4' })
  57. const ticketClosedLink = view.getByRole('link', { name: 'closed 2' })
  58. expect(ticketOpenLink).toBeInTheDocument()
  59. expect(ticketClosedLink).toBeInTheDocument()
  60. await view.events.click(
  61. view.getByRole('tab', { name: 'Organization tickets' }),
  62. )
  63. const organization = user.organization!
  64. const ticketOrganizationOpenLink = view.getByRole('link', {
  65. name: 'open 3',
  66. })
  67. const ticketOrganizationClosedLink = view.getByRole('link', {
  68. name: 'closed 1',
  69. })
  70. expect(ticketOrganizationOpenLink).toHaveAttribute(
  71. 'href',
  72. expect.stringContaining(`organization.id: ${organization.internalId}`),
  73. )
  74. expect(ticketOrganizationClosedLink).toHaveAttribute(
  75. 'href',
  76. expect.stringContaining(`organization.id: ${organization.internalId}`),
  77. )
  78. expect(
  79. view.getByRole('link', {
  80. name: 'Create new ticket for this organization',
  81. }),
  82. ).toBeInTheDocument()
  83. await view.events.click(view.getByRole('tab', { name: 'Their tickets' }))
  84. expect(view.getByRole('link', { name: 'open 4' })).toBeInTheDocument()
  85. expect(view.getByRole('link', { name: 'closed 2' })).toBeInTheDocument()
  86. expect(
  87. view.getByRole('link', { name: 'Create new ticket for this user' }),
  88. ).toBeInTheDocument()
  89. })
  90. test('view user without organization', async () => {
  91. const user = defaultUser()
  92. user.organization = null
  93. const { mockUser, mockAttributes } = mockUserDetailsApis(user)
  94. const view = await visitView(`/users/${user.internalId}`)
  95. await waitUntilApisResolved(mockUser, mockAttributes)
  96. expect(view.queryByTestId('organization-link')).not.toBeInTheDocument()
  97. expect(
  98. view.queryByRole('button', { name: 'Their tickets' }),
  99. ).not.toBeInTheDocument()
  100. expect(
  101. view.queryByRole('button', { name: 'Organization tickets' }),
  102. ).not.toBeInTheDocument()
  103. })
  104. test('view fully configured user', async () => {
  105. const userDefault = defaultUser()
  106. const [department, address] = userDefault.objectAttributeValues!
  107. const user = {
  108. ...userDefault,
  109. image: 'data:image/png;base64,1234567890',
  110. email: 'some-email@mail.com',
  111. web: 'https://some-web.com',
  112. vip: true,
  113. outOfOffice: false,
  114. outOfOfficeStartAt: null,
  115. outOfOfficeEndAt: null,
  116. phone: '80542243532',
  117. mobile: '2432332143',
  118. fax: 'fax.fax',
  119. note: 'This user is cool',
  120. objectAttributeValues: [
  121. {
  122. ...department,
  123. value: 'Department of Health and Safety',
  124. },
  125. {
  126. ...address,
  127. value: 'Berlin',
  128. },
  129. ],
  130. }
  131. const { mockUser, mockAttributes } = mockUserDetailsApis(user)
  132. const view = await visitView(`/users/${user.internalId}`)
  133. await waitUntilApisResolved(mockUser, mockAttributes)
  134. const getRegion = (name: string) => view.getByRole('region', { name })
  135. expect(view.getByIconName('crown'), 'vip has crown').toBeInTheDocument()
  136. expect(
  137. view.queryByRole('region', { name: 'First name' }),
  138. ).not.toBeInTheDocument()
  139. expect(
  140. view.queryByRole('region', { name: 'Last name' }),
  141. ).not.toBeInTheDocument()
  142. expect(getRegion('Email')).toHaveTextContent('some-email@mail.com')
  143. expect(getRegion('Web')).toHaveTextContent('https://some-web.com')
  144. expect(getRegion('Phone')).toHaveTextContent('80542243532')
  145. expect(getRegion('Mobile')).toHaveTextContent('2432332143')
  146. expect(getRegion('Fax')).toHaveTextContent('fax.fax')
  147. expect(getRegion('Note')).toHaveTextContent('This user is cool')
  148. expect(getRegion('Department')).toHaveTextContent(
  149. 'Department of Health and Safety',
  150. )
  151. expect(getRegion('Address')).toHaveTextContent('Berlin')
  152. })
  153. it('can edit user with required update policy', async () => {
  154. const { mockUser, mockAttributes, user } = mockUserDetailsApis()
  155. const view = await visitView(`/users/${user.internalId}`)
  156. await waitUntilApisResolved(mockUser, mockAttributes)
  157. expect(view.getByRole('button', { name: 'Edit' })).toBeInTheDocument()
  158. })
  159. it('cannot edit user without required update policy', async () => {
  160. const user = defaultUser()
  161. user.policy.update = false
  162. const { mockUser, mockAttributes } = mockUserDetailsApis(user)
  163. const view = await visitView(`/users/${user.internalId}`)
  164. await waitUntilApisResolved(mockUser, mockAttributes)
  165. expect(view.queryByRole('button', { name: 'Edit' })).not.toBeInTheDocument()
  166. })
  167. it('redirects to error page if user is not found', async () => {
  168. setupView('agent')
  169. const mockApi = mockGraphQLApi(UserDocument).willFailWithNotFoundError()
  170. mockGraphQLSubscription(UserUpdatesDocument)
  171. const view = await visitView('/users/123')
  172. await waitUntil(() => mockApi.calls.error)
  173. await expect(view.findByText('Not Found')).resolves.toBeInTheDocument()
  174. })
  175. it('redirects to error page if access to organization is forbidden', async () => {
  176. setupView('agent')
  177. const mockApi = mockGraphQLApi(UserDocument).willFailWithForbiddenError()
  178. mockGraphQLSubscription(UserUpdatesDocument)
  179. const view = await visitView('/users/123')
  180. await waitUntil(() => mockApi.calls.error)
  181. await expect(view.findByText('Forbidden')).resolves.toBeInTheDocument()
  182. })
  183. })
  184. test('correctly redirects from hash-based routes', async () => {
  185. setupView('agent')
  186. mockGraphQLSubscription(UserUpdatesDocument)
  187. await visitView('/#user/profile/1')
  188. const router = getTestRouter()
  189. const route = router.currentRoute.value
  190. expect(route.name).toBe('UserDetailView')
  191. expect(route.params).toEqual({ internalId: '1' })
  192. })