如何在 Vue 3 测试工具中测试转换函数?

问题描述 投票:0回答:2

我在使用 jest 和 vue test utlis 测试转换函数时遇到问题。这是我的组件代码:

<div class="disclosure">
    <button
        class="label"
        type="button"
        @click="toggle"
    >
        <span class="label-text">
            <slot name="disclosure-title" />
        </span>
    </button>
    <Transition
        name="disclosure"
        @before-enter="transitionBaseState"
        @enter="transitionEndState"
        @before-leave="transitionEndState"
        @leave="transitionBaseState"
    >
        <div
            v-show="open"
            class="panel"
        >
            <div class="panel-content">
                <slot />
            </div>
        </div>
    </Transition>
</div>

我对转换函数有疑问:transitionBaseState 和transitionEndState。当我为组件运行 ejst spec 时,覆盖选项卡显示这些功能未被覆盖。您知道测试这些功能的最佳方法是什么吗?我对显示元素的测试是这样的:

it('can be changed to opened by clicking the panel', async () => {
    await wrapper.find(buttonSelector).trigger('click');
    expect(wrapper.find(panelSelector).isVisible()).toBe(true);
});

功能:

function transitionBaseState(el: HTMLElement): void {
    el.style.height = '0';
}
function transitionEndState(el: HTMLElement): void {
    el.style.height = `${el.scrollHeight}px`;
}
vue.js jestjs vuejs3 vue-test-utils
2个回答
3
投票

好的。这是最难的。 Vue 测试 utils 默认存根转换。并且文档中没有涵盖这种行为。您需要通过硬编码的

false
值来全局模拟它。

import { config, mount } from '@vue/test-utils'
...

// before Mount
config.global.stubs = {
  transition: false
}
jest.useFakeTimers() // to deal with durations
// mount
// trigger click

jest.advanceTimersByTime(duration + 1)
// expect whatever you need from before-enter, enter, after-enter callbacks
// trigger click

jest.advanceTimersByTime(duration + 1)
// expect whatever you need from before-leave, leave, after-leave callbacks

如您所见,我添加了使用假计时器的解决方法来处理过渡持续时间。

事实上,在大多数情况下,您不需要测试转换的作用。 vue 核心团队已经对此进行了测试,但也许在某些情况下应该对其进行测试。正如您所看到的,测试中的行数增加只是为了避免默认行为。它还使用未记录的模拟,您应该在每次更新 Vue/vue-test-utils 并进行一些重大更改后保持其正常工作。

无论如何,我已经测试了上面的代码。这是我的尝试

it('should call all the callbacks', async () => {
    expect.hasAssertions()
    const callbacks = {
      onBeforeEnter: jest.fn(),
      onEnter: jest.fn(),
      onAfterEnter: jest.fn(),
      onBeforeLeave: jest.fn(),
      onLeave: jest.fn(),
      onAfterLeave: jest.fn(),
    }

    const component = defineComponent({
      name: 'Component',
      data() {
        return {
          flag: false
        }
      },
      template: `<div>
        <transition
          @before-enter="onBeforeEnter"
          @enter="onEnter"
          @after-enter="onAfterEnter"
          @before-leave="onBeforeLeave"
          @leave="onLeave"
          @after-leave="onAfterLeave">
          <span v-if="flag"></span>
        </transition>
      </div>`,
      methods: {
        onBeforeEnter: callbacks.onBeforeEnter,
        onEnter(e: Event, done: Function) {
          callbacks.onEnter()
          done()
        },
        onAfterEnter() {
          callbacks.onAfterEnter()
        },
        onBeforeLeave() {
          callbacks.onBeforeLeave()
        },
        onLeave(e: Event, done: Function) {
          callbacks.onLeave();
          done()
        },
        onAfterLeave() {
          callbacks.onAfterLeave()
        }
      }
    })

    config.global.stubs = {
      transition: false
    }

    jest.useFakeTimers()
    const wrapper = mount(component)

    await wrapper.setData({ flag: true })

    expect(callbacks.onBeforeEnter).toHaveBeenCalled()
    expect(callbacks.onEnter).toHaveBeenCalled()
    expect(callbacks.onAfterEnter).toHaveBeenCalled()

    await wrapper.setData({ flag: false })

    jest.advanceTimersByTime(1)

    expect(callbacks.onBeforeLeave).toHaveBeenCalled()
    expect(callbacks.onLeave).toHaveBeenCalled()
    expect(callbacks.onAfterLeave).toHaveBeenCalled()
  })

0
投票

这是我的解决方案:

const FakeTranstion = defineComponent({
  emits: ['afterEnter'],
  template: '<div><slot /></div>',
  setup(_, { emit }) {
    return {
      emitAfterEnter() {
        emit('afterEnter')
      },
    }
  },
})

const subject = mount(YourComponent, {
  propsData: {
    modelValue,
  },
  global: {
    stubs: {
      transition: FakeTranstion,
    },
  },
 })

 subject.findComponent(FakeTranstion).vm.emitAfterEnter()
© www.soinside.com 2019 - 2024. All rights reserved.