use-model-toggle.test.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import { defineComponent, nextTick, reactive, ref } from 'vue'
  2. import { mount } from '@vue/test-utils'
  3. import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
  4. import { useModelToggle, useModelToggleProps } from '../use-model-toggle'
  5. import type { VueWrapper } from '@vue/test-utils'
  6. const AXIOM = 'Rem is the best girl'
  7. const onShow = vi.fn()
  8. const onHide = vi.fn()
  9. let flag = true
  10. const shouldProceed = () => flag
  11. const Comp = defineComponent({
  12. props: {
  13. ...useModelToggleProps,
  14. disabled: Boolean,
  15. },
  16. setup(props) {
  17. const indicator = ref(false)
  18. const { show, hide, toggle } = useModelToggle({
  19. indicator,
  20. onShow,
  21. onHide,
  22. shouldProceed,
  23. shouldHideWhenRouteChanges: ref(true),
  24. })
  25. return () => {
  26. return (
  27. <>
  28. <button class="show" onClick={show}>
  29. show
  30. </button>
  31. <button class="hide" onClick={hide}>
  32. hide
  33. </button>
  34. <button class="toggle" onClick={toggle}>
  35. toggle
  36. </button>
  37. {indicator.value || props.modelValue ? <div>{AXIOM}</div> : undefined}
  38. </>
  39. )
  40. }
  41. },
  42. })
  43. describe('use-model-toggle', () => {
  44. let wrapper: VueWrapper<any>
  45. beforeEach(() => {
  46. flag = true
  47. wrapper = mount(Comp)
  48. })
  49. afterEach(() => {
  50. wrapper.unmount()
  51. })
  52. it('should render correctly', async () => {
  53. expect(wrapper.text()).not.toContain(AXIOM)
  54. })
  55. it('should show and hide via API calls', async () => {
  56. expect(wrapper.text()).not.toContain(AXIOM)
  57. await wrapper.find('.show').trigger('click')
  58. expect(wrapper.text()).toContain(AXIOM)
  59. expect(onShow).toHaveBeenCalledTimes(1)
  60. await wrapper.find('.hide').trigger('click')
  61. expect(wrapper.text()).not.toContain(AXIOM)
  62. expect(onHide).toHaveBeenCalledTimes(1)
  63. })
  64. it('should call callbacks correctly', async () => {
  65. expect(wrapper.text()).not.toContain(AXIOM)
  66. await wrapper.find('.show').trigger('click')
  67. expect(wrapper.text()).toContain(AXIOM)
  68. expect(onShow).toHaveBeenCalledTimes(1)
  69. await wrapper.find('.show').trigger('click')
  70. expect(onShow).toHaveBeenCalledTimes(1)
  71. await wrapper.find('.hide').trigger('click')
  72. expect(wrapper.text()).not.toContain(AXIOM)
  73. expect(onHide).toHaveBeenCalledTimes(1)
  74. await wrapper.find('.hide').trigger('click')
  75. expect(onHide).toHaveBeenCalledTimes(1)
  76. })
  77. it('should toggle show and hide via API calls', async () => {
  78. expect(wrapper.text()).not.toContain(AXIOM)
  79. await wrapper.find('.toggle').trigger('click')
  80. expect(wrapper.text()).toContain(AXIOM)
  81. expect(onShow).toHaveBeenCalledTimes(1)
  82. await wrapper.find('.toggle').trigger('click')
  83. expect(wrapper.text()).not.toContain(AXIOM)
  84. expect(onHide).toHaveBeenCalledTimes(1)
  85. })
  86. it('should not proceed when the should proceed returns false', async () => {
  87. flag = false
  88. expect(wrapper.text()).not.toContain(AXIOM)
  89. await wrapper.find('.show').trigger('click')
  90. expect(wrapper.text()).not.toContain(AXIOM)
  91. expect(onShow).not.toHaveBeenCalled()
  92. await wrapper.find('.toggle').trigger('click')
  93. expect(wrapper.text()).not.toContain(AXIOM)
  94. expect(onShow).not.toHaveBeenCalled()
  95. })
  96. it('should bind with modelValue', async () => {
  97. wrapper.unmount()
  98. const model = ref(false)
  99. const disabled = ref(false)
  100. wrapper = mount({
  101. setup: () => () =>
  102. <Comp v-model={model.value} disabled={disabled.value} />,
  103. })
  104. expect(wrapper.findComponent(Comp).text()).not.toContain(AXIOM)
  105. await wrapper.find('.show').trigger('click')
  106. expect(model.value).toBe(true)
  107. expect(wrapper.findComponent(Comp).text()).toContain(AXIOM)
  108. await wrapper.find('.hide').trigger('click')
  109. expect(onHide).toHaveBeenCalledTimes(1)
  110. expect(model.value).toBe(false)
  111. expect(wrapper.findComponent(Comp).text()).not.toContain(AXIOM)
  112. model.value = true
  113. disabled.value = true
  114. await nextTick()
  115. // when disabled emits false that modifies the model
  116. expect(model.value).toBe(false)
  117. // should not hide when disabled
  118. await wrapper.find('.hide').trigger('click')
  119. expect(onHide).toHaveBeenCalledTimes(1)
  120. })
  121. it('should hide when route changes', async () => {
  122. wrapper.unmount()
  123. const router = reactive({
  124. test: '/',
  125. })
  126. wrapper = mount(Comp, {
  127. global: {
  128. config: {
  129. globalProperties: {
  130. $route: router,
  131. },
  132. },
  133. },
  134. })
  135. expect(wrapper.text()).not.toContain(AXIOM)
  136. await wrapper.find('.show').trigger('click')
  137. expect(wrapper.text()).toContain(AXIOM)
  138. expect(onHide).toHaveBeenCalledTimes(0)
  139. router.test = '/test/changed'
  140. await nextTick()
  141. expect(onHide).toHaveBeenCalledTimes(1)
  142. })
  143. })