Vue如何测试带有插槽和插槽属性的组件

13

我想测试这个FooComponent

<div>
  <slot :fn="internalFn" />
</div>

它的使用方式如下(例如在 ParentComponent 中):

<FooComponent>
  <template slot-scope="slotProps">
    <BarComponent @some-event="slotProps.fn" />
  </template>
</FooComponent>

因此,我希望测试一下我的组件在从插槽属性调用这个“fn”时的反应。我认为最简单的方法是取出方法本身并调用它,像这样:

cosnt wrapper = shallowMount(FooComponent, /* ... */)
wrapper.vm.methods.internalFn(/* test payload */)
expect(wrapper.emitted()).toBe(/* some expectation */)

但是,这被广泛认为是有关测试内部实现的反模式。因此,我希望通过传递到插槽中的 fn 属性来测试它,因为它也是一种组件接口,就像组件自身的 props 一样。

但是如何测试通过插槽传递的 props 呢?我可以想象只有在测试类似于 ParentComponent 的东西时才能起作用:

const wrapper = shallowMount(ParentComponent, /* ... */)
const foo = wrapper.find(FooComponent)
wrapper.find(BarComponent).vm.$emit('some-event', /*...*/)
/* write expectations against foo */

但是这感觉像是在ParentComponent的测试中对FooComponent进行测试。

也许有更好的方法吗?

2个回答

4

我有点晚来到这个聚会,但我也遇到了同样的问题。我从 Vue 的实际测试中获取了一些线索,虽然它们比我们测试的内容更抽象一些,但确实有所帮助。

以下是我的解决方案:

import { shallowMount } from '@vue/test-utils';
import Component from 'xyz/Component';

let wrapperSlotted;

describe('xyz/Component.vue', () => {
  beforeAll(() => {
    wrapperSlotted = shallowMount(Component, {
      data() {
        return { myProp: 'small' }
      },
      scopedSlots: {
        default: function (props) {
          return this.$createElement('div', [props.myProp]);
        }
      },
    });
  });

  it('slot prop passed to a scoped slot', () => {
    let text = wrapperSlotted.find('div').text();
    expect(text).toBe('small'); // the value of `myProp`, which has been set as the text node in the slotted <div />
  });
});

因此,主要是我使用了scopedSlots的渲染函数。

希望这能对某个人有所帮助 :)


测试原则之一是,如果它所测试的功能没有改变,测试不应该出现错误。使用“toBe”匹配器来检查组件的所有渲染文本违反了这个原则。toBe匹配器将检查组件中的所有文本是否严格等于预期值。例如,如果您决定将“small”更改为“tiny”,则测试会失败。 - Victor

1
UPD: 下面是我几年前给出的原始答案。今天我会说其中一种方法就足够了:
  1. 不要测试 slot 方法,而是测试依赖它的用户界面功能。首先尝试手动测试,注意你是如何进行测试的,然后尝试编写类似的测试。例如使用 testing-library/vue

  2. 如果第一种方法太难实施,可以考虑想出一些虚假的测试组件。这个想法与我在问题中描述的非常相似。

但感觉像是在 ParentComponent 的测试中为 FooComponent 进行测试

但是,不要使用 ParentComponent,只需在您的 FooComponent.spec.js 文件中创建一个非常简单的内联组件,该组件使用具有插槽的组件即可。


2020年给出的原始答案:

由于没有答案,所以我分享一下我的解决方案。

我决定测试内部方法。虽然不太酷,但至少因为我使用typescript,我有一个类型安全的测试,如果我重命名或修改我要测试的方法,它将失败并显示明确的类型错误。看起来像这样:

import Foo from '@/components/foo/Foo.ts'
import FooComponent from '@/components/foo/Foo.vue'

/*...*/

cosnt wrapper = <Foo>shallowMount(FooComponent, /* ... */)

// notice that because I passed `Foo` which is a class-component, 
// I have autocomplete and type checks for vm.*
wrapper.vm.internalFn(/* test payload */)

expect(wrapper.emitted()).toBe(/* some expectation */)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接