message-manager.test.tsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. import { h, nextTick, ref } from 'vue'
  2. import { describe, expect, it, test, vi } from 'vitest'
  3. import { getStyle } from '@element-plus/utils'
  4. import { rAF } from '@element-plus/test-utils/tick'
  5. import { ElMessage } from '..'
  6. import Message from '../src/method'
  7. const selector = '.el-message'
  8. // TODO: testing the original transition with `nextTick`'
  9. describe('Message on command', () => {
  10. test('it should get component handle', async () => {
  11. const handle = Message()
  12. await rAF()
  13. expect(document.querySelector(selector)).toBeTruthy()
  14. handle.close()
  15. await rAF()
  16. await nextTick()
  17. expect(document.querySelector(selector)).toBeFalsy()
  18. })
  19. test('it should be able to manually close a message', async () => {
  20. const { close } = Message()
  21. await rAF()
  22. const element = document.querySelector(selector)
  23. expect(element).toBeTruthy()
  24. close()
  25. await rAF()
  26. await nextTick()
  27. expect(document.querySelector(selector)).toBeNull()
  28. })
  29. test('it should close all messages', async () => {
  30. const onClose = vi.fn()
  31. const instances = []
  32. for (let i = 0; i < 4; i++) {
  33. const instance = Message({
  34. duration: 0,
  35. onClose,
  36. })
  37. instances.push(instance)
  38. }
  39. await rAF()
  40. const elements = document.querySelectorAll(selector)
  41. expect(elements.length).toBe(4)
  42. Message.closeAll()
  43. await rAF()
  44. expect(onClose).toHaveBeenCalledTimes(4)
  45. expect(document.querySelectorAll(selector).length).toBe(0)
  46. })
  47. test('it should close all messages of the specified type', async () => {
  48. const onClose = vi.fn()
  49. const instances = []
  50. const success = 'success'
  51. for (let i = 0; i < 4; i++) {
  52. const instance = Message({
  53. type: success,
  54. duration: 0,
  55. onClose,
  56. })
  57. instances.push(instance)
  58. }
  59. for (let i = 0; i < 2; i++) {
  60. const instance = Message({
  61. duration: 0,
  62. onClose,
  63. })
  64. instances.push(instance)
  65. }
  66. await rAF()
  67. const elements = document.querySelectorAll(selector)
  68. const successElements = document.querySelectorAll(`${selector}--${success}`)
  69. expect(elements.length).toBe(6)
  70. expect(successElements.length).toBe(4)
  71. Message.closeAll(success)
  72. await rAF()
  73. expect(onClose).toHaveBeenCalledTimes(4)
  74. expect(document.querySelectorAll(selector).length).toBe(2)
  75. Message.closeAll()
  76. })
  77. test('it should stack messages', async () => {
  78. const messages = [Message(), Message(), Message()]
  79. await rAF()
  80. const elements = document.querySelectorAll(selector)
  81. expect(elements.length).toBe(3)
  82. const getTopValue = (elm: Element): number =>
  83. Number.parseInt(getStyle(elm as HTMLElement, 'top'), 10)
  84. const topValues: number[] = []
  85. elements.forEach((e) => {
  86. topValues.push(getTopValue(e))
  87. })
  88. for (let i = 1; i < topValues.length; i++) {
  89. expect(topValues[i - 1]).toBeLessThan(topValues[i])
  90. }
  91. messages.forEach((m) => m.close())
  92. })
  93. test('correct space when set offset', async () => {
  94. const offset = 100
  95. const space = 20
  96. const messages = [Message({ offset }), Message({ offset })]
  97. await rAF()
  98. const elements = document.querySelectorAll(selector)
  99. expect(elements.length).toBe(2)
  100. const getTopValue = (elm: Element): number =>
  101. Number.parseFloat(getStyle(elm as HTMLElement, 'top'))
  102. const firstElementTop = getTopValue(elements[0])
  103. const secondElementTop = getTopValue(elements[1])
  104. expect(firstElementTop).toBe(offset)
  105. expect(secondElementTop).toBe(offset + space)
  106. messages.forEach((m) => m.close())
  107. })
  108. test('it should have 4 other types of message', () => {
  109. expect(Message.success).toBeInstanceOf(Function)
  110. expect(Message.warning).toBeInstanceOf(Function)
  111. expect(Message.info).toBeInstanceOf(Function)
  112. expect(Message.error).toBeInstanceOf(Function)
  113. })
  114. test('it should appendTo specified HTMLElement', async () => {
  115. const htmlElement = document.createElement('div')
  116. const handle = Message({
  117. appendTo: htmlElement,
  118. })
  119. await rAF()
  120. expect(htmlElement.querySelector(selector)).toBeTruthy()
  121. handle.close()
  122. await rAF()
  123. await nextTick()
  124. expect(htmlElement.querySelector(selector)).toBeFalsy()
  125. })
  126. test('it should appendTo specified selector', async () => {
  127. const htmlElement = document.createElement('div')
  128. htmlElement.classList.add('message-manager')
  129. document.body.appendChild(htmlElement)
  130. const handle = Message({
  131. appendTo: '.message-manager',
  132. })
  133. await rAF()
  134. expect(htmlElement.querySelector(selector)).toBeTruthy()
  135. handle.close()
  136. await rAF()
  137. await nextTick()
  138. expect(htmlElement.querySelector(selector)).toBeFalsy()
  139. })
  140. test('it should render vnode function', async () => {
  141. const i = ref(0)
  142. Message({
  143. message: () => h('div', i.value),
  144. })
  145. await rAF()
  146. expect(document.querySelector(selector)?.textContent).toMatchInlineSnapshot(
  147. `"0"`
  148. )
  149. i.value++
  150. await rAF()
  151. expect(document.querySelector(selector)?.textContent).toMatchInlineSnapshot(
  152. `"1"`
  153. )
  154. })
  155. describe('context inheritance', () => {
  156. it('should globally inherit context correctly', () => {
  157. expect(ElMessage._context).toBe(null)
  158. const testContext = {
  159. config: {
  160. globalProperties: {},
  161. },
  162. _context: {},
  163. }
  164. ElMessage.install?.(testContext as any)
  165. expect(ElMessage._context).not.toBe(null)
  166. expect(ElMessage._context).toBe(testContext._context)
  167. // clean up
  168. ElMessage._context = null
  169. })
  170. })
  171. })