useOverlayContainer.spec.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { flushPromises, mount } from '@vue/test-utils'
  3. import { useRoute, type RouteLocationNormalizedLoadedGeneric } from 'vue-router'
  4. import {
  5. destroyComponent,
  6. pushComponent,
  7. } from '#shared/components/DynamicInitializer/manage.ts'
  8. import {
  9. getOverlayContainerMeta,
  10. useOverlayContainer,
  11. } from '../useOverlayContainer.ts'
  12. vi.mock('#shared/components/DynamicInitializer/manage.ts', () => {
  13. return {
  14. destroyComponent: vi.fn(),
  15. pushComponent: vi.fn(),
  16. }
  17. })
  18. vi.mock('vue-router', () => ({
  19. useRoute: vi.fn(),
  20. }))
  21. const mockedUseRoute = vi.mocked(useRoute)
  22. const inContext = (
  23. fn: () => void,
  24. route: Partial<RouteLocationNormalizedLoadedGeneric>,
  25. ) => {
  26. mockedUseRoute.mockReturnValue(route as RouteLocationNormalizedLoadedGeneric)
  27. const component = {
  28. setup() {
  29. fn()
  30. return () => null
  31. },
  32. }
  33. return mount(component)
  34. }
  35. describe('use dialog usage', () => {
  36. beforeEach(() => {
  37. const { options } = getOverlayContainerMeta('dialog')
  38. options.clear()
  39. })
  40. test('name and component are required', () => {
  41. inContext(
  42. () => {
  43. // @ts-expect-error - component is required
  44. useOverlayContainer('dialog', { name: 'name' })
  45. },
  46. {
  47. path: '/example',
  48. },
  49. )
  50. inContext(
  51. () => {
  52. // @ts-expect-error - name is required
  53. useOverlayContainer('dialog', {
  54. component: vi.fn(),
  55. })
  56. },
  57. {
  58. path: '/example',
  59. },
  60. )
  61. inContext(
  62. () => {
  63. useOverlayContainer('dialog', {
  64. name: 'name',
  65. component: vi.fn(),
  66. })
  67. },
  68. {
  69. path: '/example',
  70. },
  71. )
  72. })
  73. test('adds and removes meta data', async () => {
  74. const vm = inContext(
  75. () => {
  76. useOverlayContainer('dialog', {
  77. name: 'name',
  78. component: vi.fn(),
  79. })
  80. },
  81. {
  82. path: '/example',
  83. },
  84. )
  85. const { options } = getOverlayContainerMeta('dialog')
  86. expect(options.size).toBe(1)
  87. expect(options.has('name_/example')).toBe(true)
  88. vm.unmount()
  89. await flushPromises()
  90. expect(options.size).toBe(0)
  91. expect(options.has('name_/example')).toBe(false)
  92. })
  93. test('opens and closes dialog', async () => {
  94. const component = vi.fn().mockResolvedValue({})
  95. let dialog!: ReturnType<typeof useOverlayContainer>
  96. inContext(
  97. () => {
  98. dialog = useOverlayContainer('dialog', {
  99. name: 'name',
  100. component,
  101. })
  102. },
  103. {
  104. path: '/example',
  105. },
  106. )
  107. await dialog.open()
  108. const { opened } = getOverlayContainerMeta('dialog')
  109. expect(dialog.isOpened.value).toBe(true)
  110. expect(component).toHaveBeenCalled()
  111. expect(opened.value.has('name_/example')).toBe(true)
  112. expect(pushComponent).toHaveBeenCalledWith(
  113. 'dialog',
  114. 'name_/example',
  115. expect.anything(),
  116. {},
  117. )
  118. await dialog.close()
  119. expect(dialog.isOpened.value).toBe(false)
  120. expect(opened.value.has('name_/example')).toBe(false)
  121. expect(destroyComponent).toHaveBeenCalledWith('dialog', 'name_/example')
  122. })
  123. test('prefetch starts loading', async () => {
  124. const component = vi.fn().mockResolvedValue({})
  125. let dialog!: ReturnType<typeof useOverlayContainer>
  126. inContext(
  127. () => {
  128. dialog = useOverlayContainer('dialog', {
  129. name: 'name',
  130. component,
  131. })
  132. },
  133. {
  134. path: '/example',
  135. },
  136. )
  137. await dialog.prefetch()
  138. expect(component).toHaveBeenCalled()
  139. })
  140. test('hooks are called', async () => {
  141. const component = vi.fn().mockResolvedValue({})
  142. const beforeOpen = vi.fn()
  143. const afterClose = vi.fn()
  144. let flyout!: ReturnType<typeof useOverlayContainer>
  145. inContext(
  146. () => {
  147. flyout = useOverlayContainer('flyout', {
  148. name: 'name',
  149. component,
  150. beforeOpen,
  151. afterClose,
  152. })
  153. },
  154. {
  155. path: '/example',
  156. },
  157. )
  158. await flyout.open()
  159. expect(beforeOpen).toHaveBeenCalled()
  160. expect(afterClose).not.toHaveBeenCalled()
  161. await flyout.close()
  162. expect(afterClose).toHaveBeenCalled()
  163. })
  164. })