content.test.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. import { nextTick } from 'vue'
  2. import { mount } from '@vue/test-utils'
  3. import {
  4. afterAll,
  5. afterEach,
  6. beforeAll,
  7. beforeEach,
  8. describe,
  9. expect,
  10. it,
  11. } from 'vitest'
  12. import { usePopperContainer } from '@element-plus/hooks'
  13. import { TOOLTIP_INJECTION_KEY } from '@element-plus/components/tooltip'
  14. import { genTooltipProvides } from '../test-helper/provides'
  15. import ElTooltipContent from '../src/content.vue'
  16. import type { VueWrapper } from '@vue/test-utils'
  17. const AXIOM = 'rem is the best girl'
  18. describe('<ElTooltipContent />', () => {
  19. const {
  20. controlled,
  21. id,
  22. open,
  23. trigger,
  24. onOpen,
  25. onClose,
  26. onToggle,
  27. onShow,
  28. onHide,
  29. onBeforeShow,
  30. onBeforeHide,
  31. } = genTooltipProvides()
  32. const defaultProvide = {
  33. [TOOLTIP_INJECTION_KEY as symbol]: {
  34. controlled,
  35. id,
  36. open,
  37. trigger,
  38. onOpen,
  39. onClose,
  40. onToggle,
  41. onShow,
  42. onHide,
  43. onBeforeShow,
  44. onBeforeHide,
  45. },
  46. }
  47. let unmount: () => void
  48. const createComponent = (props = {}, provides = {}) => {
  49. const wrapper = mount(
  50. {
  51. setup() {
  52. usePopperContainer()
  53. return () => <ElTooltipContent {...props}>{AXIOM}</ElTooltipContent>
  54. },
  55. },
  56. {
  57. global: {
  58. provide: {
  59. ...defaultProvide,
  60. ...provides,
  61. },
  62. stubs: ['ElPopperContent'],
  63. },
  64. attachTo: document.body,
  65. }
  66. )
  67. unmount = () => wrapper.unmount()
  68. return wrapper.findComponent(ElTooltipContent)
  69. }
  70. let wrapper: VueWrapper<any>
  71. const OLD_ENV = process.env.NODE_ENV
  72. beforeAll(() => {
  73. process.env['NODE_ENV'] = 'test'
  74. })
  75. afterAll(() => {
  76. process.env['NODE_ENV'] = OLD_ENV
  77. })
  78. afterEach(() => {
  79. open.value = false
  80. controlled.value = false
  81. trigger.value = 'hover'
  82. unmount?.()
  83. document.body.innerHTML = ''
  84. })
  85. describe('rendering', () => {
  86. it('should render nothing initially when not controlled', async () => {
  87. wrapper = createComponent()
  88. await nextTick()
  89. expect(wrapper.text()).toBe('')
  90. })
  91. describe('persistent content', () => {
  92. it('should be able to inherit style', async () => {
  93. const customStyle = {
  94. position: 'absolute',
  95. }
  96. wrapper = createComponent({
  97. style: customStyle,
  98. })
  99. await nextTick()
  100. expect(wrapper.vm.contentStyle).toEqual(customStyle)
  101. })
  102. })
  103. describe('content rendering', () => {
  104. it('should not show the content when disabled', async () => {
  105. wrapper = createComponent({
  106. disabled: true,
  107. })
  108. await nextTick()
  109. expect(wrapper.vm.shouldShow).toBe(false)
  110. })
  111. })
  112. describe('events', () => {
  113. beforeEach(async () => {
  114. wrapper = createComponent()
  115. await nextTick()
  116. open.value = true
  117. await nextTick()
  118. await nextTick()
  119. })
  120. it('should be able to enter trigger', async () => {
  121. const { vm } = wrapper
  122. expect(onOpen).not.toHaveBeenCalled()
  123. const enterEvent = new MouseEvent('mouseenter')
  124. vm.onContentEnter(enterEvent)
  125. expect(onOpen).toHaveBeenCalled()
  126. const leaveEvent = new MouseEvent('mouseleave')
  127. expect(onClose).not.toHaveBeenCalled()
  128. vm.onContentLeave(leaveEvent)
  129. expect(onClose).toHaveBeenCalled()
  130. })
  131. it('should not trigger close event when the trigger is not hover', async () => {
  132. const { vm } = wrapper
  133. trigger.value = 'click'
  134. await nextTick()
  135. const leaveEvent = new MouseEvent('mouseleave')
  136. expect(onClose).not.toHaveBeenCalled()
  137. vm.onContentLeave(leaveEvent)
  138. expect(onClose).not.toHaveBeenCalled()
  139. })
  140. it('should be able to stop triggering when controlled', async () => {
  141. controlled.value = true
  142. await nextTick()
  143. const { vm } = wrapper
  144. expect(onOpen).not.toHaveBeenCalled()
  145. const enterEvent = new MouseEvent('mouseenter')
  146. vm.onContentEnter(enterEvent)
  147. expect(onOpen).not.toHaveBeenCalled()
  148. const leaveEvent = new MouseEvent('mouseleave')
  149. expect(onClose).not.toHaveBeenCalled()
  150. vm.onContentLeave(leaveEvent)
  151. expect(onClose).not.toHaveBeenCalled()
  152. })
  153. describe('onCloseOutside', () => {
  154. beforeEach(() => {
  155. // Have to mock this ref because we are not going to render the content in this component
  156. wrapper.vm.contentRef = {
  157. popperContentRef: document.createElement('div'),
  158. }
  159. })
  160. it('should not close the content after click outside when trigger is hover', async () => {
  161. document.body.click()
  162. await nextTick()
  163. expect(onClose).not.toHaveBeenCalled()
  164. })
  165. it('should not close the content after click outside when controlled', async () => {
  166. controlled.value = true
  167. trigger.value = 'click'
  168. await nextTick()
  169. document.body.click()
  170. await nextTick()
  171. expect(onClose).not.toHaveBeenCalled()
  172. })
  173. it('should close component after click outside', async () => {
  174. trigger.value = 'click'
  175. wrapper.vm.onAfterShow()
  176. await nextTick()
  177. document.body.click()
  178. await nextTick()
  179. expect(onClose).toHaveBeenCalled()
  180. })
  181. })
  182. })
  183. it('should append to', async () => {
  184. const el = document.createElement('div')
  185. const id = 'test_id'
  186. el.id = id
  187. document.body.appendChild(el)
  188. wrapper = createComponent({
  189. appendTo: `#${id}`,
  190. })
  191. await nextTick()
  192. expect(el.children).toHaveLength(1)
  193. expect(el.querySelector('[aria-hidden="true"]')).not.toBeNull()
  194. })
  195. })
  196. })