1

我目前在测试我的 Vue 应用程序时遇到了一种行为(特别是在包含 vuetify 时)。我使用 Jest 作为测试运行程序,但使用 mocha 时遇到了相同的行为。

首先要注意的是,问题只发生在 @vue/test-utils 的 mount 而不是 shallowMount。此外,它仅在您使用 mount 两次时才会发生(我猜原因是 Vue 对象的污染,但稍后会更多)。

现在我的组件只是一个基本的v-data-table的包装器,其属性值绑定到它的项目和一些用于复选框而不是文本的自定义插槽。

现在的问题。首先,这是我的测试的第一个变体的样子(基本上是 vuetify 推荐的方式。看看这里。由于测试本身并不重要,我只希望 true 在这里是真的

import Vue from 'vue';
import Vuetify from 'vuetify';
import { mount, createLocalVue, shallowMount } from '@vue/test-utils';

import  PermissionTable from '@/components/PermissionTable.vue';
import { expect } from 'chai';

const localVue = createLocalVue();

// Vue.use is not in the example but leaving it will cause the error that 
// the data table is not registered
Vue.use(Vuetify);

describe('Permissiontable.vue', () => {
  let vuetify;
  let tableItems;

  beforeEach(() => {
    tableItems = [];
    vuetify = new Vuetify();
  });


  it('will test the first thing',() => {
    const wrapper = mount(PermissionTable, {
      localVue,
      vuetify,
      propsData: {
        value: tableItems
      }
    });

    expect(true).to.be(true);
  });


  it('will test the second thing',() => {
    const wrapper = mount(PermissionTable, {
      localVue,
      vuetify,
      propsData: {
        value: tableItems
      }
    });

    expect(true).to.be(true);
  });
});

现在,正如在不使用 Vue.use(Vuetify) 的情况下已经评论过的那样,我将收到组件 v-data-table 未注册的错误。有了它,我剩下以下行为

  1. 测试第一件事按预期运行并成功
  2. 第二件事失败了以下错误

类型错误:无法读取未定义的属性“$scopedSlots”

并在挂载(....)时失败。为了使行为更加怪异,如果我在此行进行调试并停止,请在调试控制台中手动运行挂载,它在第一次时也会失败并出现相同的错误。如果我再次运行它,它会起作用。例如,如果我执行这个测试 4 次,就会发生这种情况。第一次成功->第二次失败->第三次和第四次再次成功。

现在我确信如果函数获得相同的输入,它们的行为方式相同。所以挂载的输入必须在第一次调用时改变。我的猜测是 Vue 类会以某种方式受到污染。因此,如果我查看localVue的文档,这个实用程序是为了防止对全局 Vue 类的污染。所以我将代码更改为

import Vue from 'vue';
import Vuetify from 'vuetify';
import { mount, createLocalVue, shallowMount } from '@vue/test-utils';

import  PermissionTable from '@/components/PermissionTable.vue';
import { expect } from 'chai';

describe('Permissiontable.vue', () => {
  let vuetify;
  let tableItems;
  let localVue;

  beforeEach(() => {
    tableItems = [];
    localVue = createLocalVue();
    vuetify = new Vuetify();
    localVue.use(vuetify);
  });


  it('will test the first thing',() => {
    const wrapper = mount(PermissionTable, {
      localVue,
      vuetify,
      propsData: {
        value: tableItems
      }
    });

    expect(true).to.be(true);
  });


  it('will test the second thing',() => {
    const wrapper = mount(PermissionTable, {
      localVue,
      vuetify,
      propsData: {
        value: tableItems
      }
    });

    expect(true).to.be(true);
  });
});

因此,我为每个测试创建了一个新的 localVue 实例和 vuetify。并使 localVue 使用 vuetify。现在这让我回到了错误

[Vue 警告]:未知的自定义元素:- 您是否正确注册了组件?对于递归组件,请确保提供“名称”选项。

我还尝试了注入 vuetify(实例化)或 Vuetify 的各种更改。使用全局 Vue.use 等。最后,我总是留下这两种行为之一。

现在的解决方法似乎是将每个测试写在一个有效的文件中,但我认为这是非常糟糕的做法,我想了解这里到底发生了什么。

我现在还为 Vuetify 和 Vue-Test-Utils 创建了问题,因为我无法想象这是预期的行为,以及通过测试作为 Repo 制作了我的组件的精简版本

rm-test-mount-fails-on-second-exec

重现:

  1. 克隆回购
  2. npm 安装
  3. npm 运行测试:单元

版本:

Vue: 2.6.10
Vue-Test-Utils: 1.0.0-beta.29
Vuetify: 2.1.12

4

2 回答 2

1

坏消息

事实证明,目前这确实是vue-test-utils中的一个错误。在我打开问题后,我发现了另一个与我的问题非常相似的问题,我很确定其根本原因与我的情况相同。显然这是由于 v.beta.29 中的 vue utils 发生了变化

问题可以在这里找到#1130

好消息

有一种解决方法可以让您的测试再次运行,直到此错误得到解决。您需要使用选项sync: false进行安装,因此顶部示例中的安装看起来像

const wrapper = mount(PermissionTable, {
  localVue,
  vuetify,
  propsData: {
    value: tableItems
  },
  sync: false
});

我仍然认为这是一个严重的错误,因为无论设置如何,每次运行它们时相同的测试都应该以相同的方式运行。一旦有消息表明该问题已得到解决,我将立即更新此帖子。

于 2019-11-29T07:37:32.717 回答
0

在您的第一段代码中唯一看起来不合适的是您正在编写Vue.use(Vuetify)并且在进行挂载时还使用了 Vuetify 的实例。

我建议Vue.use(Vuetify)您像这样保留并安装您的组件:

const wrapper = mount(PermissionTable, {
   localVue,   // vuetify is removed from this object
   propsData: {
     value: tableItems
   }
});

另一方面,单元测试通常应该使用shallowMount. 我不知道您的用例,但如果可能,请使用它而不是mount

于 2019-11-28T16:28:49.043 回答