user-detail.spec.ts 7.7 KB

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