use-popper.test.tsx 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import { defineComponent, nextTick, ref } from 'vue'
  2. import { mount } from '@vue/test-utils'
  3. import { afterEach, beforeEach, describe, expect, it, vitest } from 'vitest'
  4. import { usePopper } from '../use-popper'
  5. import type { State } from '@popperjs/core'
  6. import type { PartialOptions } from '../use-popper'
  7. describe('usePopper', () => {
  8. const optionsRef = ref<PartialOptions>({} as PartialOptions)
  9. const popperRef = ref()
  10. const referenceRef = ref()
  11. const TestComponent = defineComponent({
  12. setup() {
  13. const usePopperReturns = usePopper(referenceRef, popperRef, optionsRef)
  14. return usePopperReturns
  15. },
  16. render() {
  17. return <div />
  18. },
  19. })
  20. let wrapper: ReturnType<typeof mount>
  21. const createComponent = async () => {
  22. wrapper = mount(TestComponent)
  23. await nextTick()
  24. referenceRef.value = document.createElement('div')
  25. popperRef.value = document.createElement('div')
  26. }
  27. const getExposed = (key: string) => wrapper.vm[key] as any
  28. beforeEach(async () => {
  29. await createComponent()
  30. })
  31. afterEach(() => {
  32. wrapper.unmount()
  33. referenceRef.value = undefined
  34. popperRef.value = undefined
  35. optionsRef.value = {} as PartialOptions
  36. })
  37. it('should render well', async () => {
  38. await createComponent()
  39. expect(getExposed('state')).toBeDefined()
  40. })
  41. describe('updates', () => {
  42. it('should not render popper instance when elements have not changed', async () => {
  43. const preservedInstance = getExposed('instanceRef')
  44. await wrapper.setProps({})
  45. expect(preservedInstance).toStrictEqual(getExposed('instanceRef'))
  46. })
  47. it('should render again after reference/popper element changed', async () => {
  48. let prevInstance = getExposed('instanceRef')
  49. referenceRef.value = document.createElement('div')
  50. await nextTick()
  51. expect(prevInstance).not.toStrictEqual(getExposed('instanceRef'))
  52. prevInstance = getExposed('instanceRef')
  53. popperRef.value = document.createElement('div')
  54. await nextTick()
  55. expect(prevInstance).not.toStrictEqual(getExposed('instanceRef'))
  56. })
  57. it('should not render twice if only options changed', async () => {
  58. const instance = getExposed('instanceRef')
  59. optionsRef.value = { placement: 'bottom' } as PartialOptions
  60. await nextTick()
  61. expect(getExposed('instanceRef')).toStrictEqual(instance)
  62. })
  63. it('update options', async () => {
  64. const instance = getExposed('instanceRef') as any
  65. const setOptionSpy = vitest.spyOn(instance, 'setOptions')
  66. optionsRef.value = { placement: 'bottom' } as PartialOptions
  67. await nextTick()
  68. expect(setOptionSpy).toHaveBeenCalled()
  69. })
  70. it('destroys popper instance when unmounted', async () => {
  71. const instance = getExposed('instanceRef') as any
  72. const destroySpy = vitest.spyOn(instance, 'destroy')
  73. wrapper.unmount()
  74. expect(destroySpy).toHaveBeenCalled()
  75. })
  76. it('with arrow element', async () => {
  77. const arrowEl = document.createElement('div')
  78. popperRef.value.appendChild(arrowEl)
  79. optionsRef.value = {
  80. modifiers: [{ name: 'arrow', options: { element: arrowEl } }],
  81. } as PartialOptions
  82. await nextTick()
  83. expect((getExposed('state').styles as State['styles']).arrow).toEqual(
  84. expect.objectContaining({
  85. position: 'absolute',
  86. transform: 'translate(0px, 0px)',
  87. })
  88. )
  89. })
  90. })
  91. })