recent-searches.spec.ts 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. // Copyright (C) 2012-2025 Zammad Foundation, https://zammad-foundation.org/
  2. import { getByText, getAllByRole } from '@testing-library/vue'
  3. import { visitView } from '#tests/support/components/visitView.ts'
  4. import { clearMockClient } from '#tests/support/mock-apollo-client.ts'
  5. import type { MockGraphQLInstance } from '#tests/support/mock-graphql-api.ts'
  6. import { mockPermissions } from '#tests/support/mock-permissions.ts'
  7. import { mockUserCurrent } from '#tests/support/mock-userCurrent.ts'
  8. import { nullableMock, waitUntil } from '#tests/support/utils.ts'
  9. import { convertToGraphQLId } from '#shared/graphql/utils.ts'
  10. import { mockSearchOverview } from '../graphql/mocks/mockSearchOverview.ts'
  11. describe('testing recent searches block', () => {
  12. let mockSearchApi: MockGraphQLInstance
  13. beforeEach(() => {
  14. mockPermissions(['ticket.agent'])
  15. mockSearchApi = mockSearchOverview({ totalCount: 0, items: [] })
  16. })
  17. it('recent searches', async () => {
  18. localStorage.clear()
  19. const view = await visitView('/search/user')
  20. const getByTextInLastSearch = (text: string) => {
  21. return getByText(view.getByTestId('recentSearches'), text)
  22. }
  23. const typeInSearch = async (text: string) => {
  24. await view.events.debounced(() =>
  25. view.events.type(view.getByPlaceholderText('Search…'), text),
  26. )
  27. await waitUntil(() => mockSearchApi.calls.resolve)
  28. }
  29. const clearSearch = () => {
  30. return view.events.debounced(() =>
  31. view.events.clear(view.getByPlaceholderText('Search…')),
  32. )
  33. }
  34. expect(getByTextInLastSearch('No recent searches')).toBeInTheDocument()
  35. await typeInSearch('search')
  36. expect(getByTextInLastSearch('search')).toBeInTheDocument()
  37. await typeInSearch('123')
  38. expect(getByTextInLastSearch('search123')).toBeInTheDocument()
  39. await clearSearch()
  40. await typeInSearch('search')
  41. let items = getAllByRole(view.getByTestId('recentSearches'), 'listitem')
  42. expect(items).toHaveLength(2)
  43. expect(items[0]).toHaveTextContent(/^search$/)
  44. expect(items[1]).toHaveTextContent(/^search123$/)
  45. await clearSearch()
  46. await typeInSearch('test 1')
  47. await clearSearch()
  48. await typeInSearch('test 2')
  49. await clearSearch()
  50. await typeInSearch('test 3')
  51. items = getAllByRole(view.getByTestId('recentSearches'), 'listitem')
  52. expect(items).toHaveLength(5)
  53. expect(items[0]).toHaveTextContent(/^test 3$/)
  54. expect(items[1]).toHaveTextContent(/^test 2$/)
  55. expect(items[2]).toHaveTextContent(/^test 1$/)
  56. expect(items[3]).toHaveTextContent(/^search$/)
  57. expect(items[4]).toHaveTextContent(/^search123$/)
  58. await clearSearch()
  59. await typeInSearch('test 4')
  60. items = getAllByRole(view.getByTestId('recentSearches'), 'listitem')
  61. expect(items).toHaveLength(5)
  62. expect(items[0]).toHaveTextContent(/^test 4$/)
  63. expect(items[4]).toHaveTextContent(/^search$/)
  64. await clearSearch()
  65. await typeInSearch('search')
  66. items = getAllByRole(view.getByTestId('recentSearches'), 'listitem')
  67. expect(items).toHaveLength(5)
  68. expect(items[0]).toHaveTextContent(/^search$/)
  69. })
  70. it('clicking previous searches calls api', async () => {
  71. localStorage.clear()
  72. const view = await visitView('/search/user')
  73. const input = view.getByPlaceholderText('Search…')
  74. await view.events.debounced(() => view.events.type(input, 'search'))
  75. await view.events.debounced(() => view.events.type(input, '123'))
  76. await waitUntil(() => mockSearchApi.calls.resolve)
  77. const items = view.getAllByRole('listitem')
  78. expect(items).toHaveLength(2)
  79. expect(items[0]).toHaveTextContent('search123')
  80. expect(items[1]).toHaveTextContent('search')
  81. await view.events.debounced(() => view.events.click(items[1]))
  82. expect(mockSearchApi.spies.resolve).toHaveBeenNthCalledWith(1, {
  83. onlyIn: 'User',
  84. search: 'search',
  85. limit: 30,
  86. })
  87. expect(mockSearchApi.spies.resolve).toHaveBeenNthCalledWith(2, {
  88. onlyIn: 'User',
  89. search: 'search123',
  90. limit: 30,
  91. })
  92. })
  93. it('emptying out search shows recent searches', async () => {
  94. localStorage.clear()
  95. clearMockClient()
  96. mockSearchApi.willResolve({
  97. search: nullableMock({
  98. totalCount: 1,
  99. items: [
  100. nullableMock({
  101. __typename: 'User',
  102. id: '1sdsada',
  103. internalId: 1,
  104. updatedAt: new Date().toISOString(),
  105. firstname: 'Max',
  106. lastname: 'Mustermann',
  107. }),
  108. ],
  109. }),
  110. })
  111. const view = await visitView('/search/user')
  112. const input = view.getByPlaceholderText('Search…')
  113. await view.events.debounced(() => view.events.type(input, 'search'))
  114. await view.events.debounced(() => view.events.type(input, '123'))
  115. await waitUntil(() => mockSearchApi.calls.resolve)
  116. expect(view.container).toHaveTextContent('Max Mustermann')
  117. await view.events.debounced(() => view.events.clear(input))
  118. expect(view.container).not.toHaveTextContent('Max Mustermann')
  119. expect(view.getByTestId('recentSearches')).toBeInTheDocument()
  120. })
  121. it('shows recent searches, when opening page', async () => {
  122. const id = convertToGraphQLId('User', 1)
  123. mockUserCurrent({
  124. id,
  125. })
  126. localStorage.clear()
  127. localStorage.setItem(
  128. `${id}-recentSearches`,
  129. JSON.stringify(['search', 'search123']),
  130. )
  131. const view = await visitView('/search/user')
  132. expect(view.getByRole('button', { name: 'search' })).toBeInTheDocument()
  133. expect(view.getByRole('button', { name: 'search123' })).toBeInTheDocument()
  134. const input = view.getByPlaceholderText('Search…')
  135. await view.events.debounced(() => view.events.type(input, 'search55'), 100)
  136. await view.events.clear(input)
  137. expect(
  138. view.queryByRole('button', { name: 'search55' }),
  139. ).not.toBeInTheDocument()
  140. })
  141. })