Vue单元测试中常见问题有哪些细节容易踩坑?

2026-04-03 09:441阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计1322个文字,预计阅读时间需要6分钟。

Vue单元测试中常见问题有哪些细节容易踩坑?

一、前言本文将介绍如何使用Karma、Mocha、Chai、Sinon-Chai进行Vue实例属性的单元测试。我们将通过以下步骤实现:

二、全局组件的坑由于我的g-icon组件是全局注册的,所以在使用g-input组件时,g-icon是直接使用的。这导致在使用g-input组件时,g-icon是直接引用的,而非通过Vue实例。

三、解决方案为了解决这个问题,我们可以在单元测试中模拟全局组件,以便在测试时能够控制其行为。下面是一个简单的示例代码:

javascript// 引入Vue和组件import Vue from 'vue';import GIcon from '@/components/GIcon.vue';import GInput from '@/components/GInput.vue';

// 创建一个模拟的Vue实例const vm=new Vue({ render: h=> h(GInput)});

// 模拟全局组件Vue.component('g-icon', { template: 'Icon'});

// 使用vm.$mount()挂载组件vm.$mount();

// 执行测试describe('GInput组件', ()=> { it('should render g-icon correctly', ()=> { // 断言g-icon的文本内容 expect(vm.$el.querySelector('g-icon').textContent).toBe('Icon'); });});

以上代码中,我们首先创建了一个Vue实例,并在其中挂载了GInput组件。然后,我们模拟了全局组件g-icon,并使用Sinon-Chai进行断言。这样,我们就可以在单元测试中控制全局组件的行为,确保组件的正确性。

一、写在前面

这篇文章的代码使用karma,mocha,chai,sinon-chai配合Vue的实例属性进行单元测试

Vue单元测试中常见问题有哪些细节容易踩坑?

二、全局的组件的坑

由于我的g-icon是全局注册的,所以使用g-input组件时的时候g-icon是直接用的,所以测试时有关icon的代码永远是错的。

把g-icon局部注册的组件

三、在测试中触发点击事件

模拟我在app.vue里使用g-input组件

<g-input v-model="message"></g-input>

使用new event 和 dispatch 模拟事件在组件上触发,虽然这个事件和我们实际的事件不一样,但名字一样就够了,测试回调函数自带的参数

it("支持事件", () => { ["change", "input", "focus", "blur"].forEach(eventName => { vm = new Constructor({}).$mount(); const callback = sinon.fake(); vm.$on(eventName, callback); let event = new Event(eventName); Object.defineProperty(event, "target", { value: { value: "hi" }, enumerable: true }); let inputElement = vm.$el.querySelector("input"); inputElement.dispatchEvent(event); expect(callback).to.have.been.calledWith("hi"); }); });

测试这个组件事件触发时,回调的参数,由于自定义事件没有target,我们需要自己写上去

value: { value: "hi" }第一个value是defineProperty的

四、Vue的版本

坑来自于下面一段代码

it("接受gutter", function(done) { Vue.component("g-row", Row); Vue.component("g-col", Col); const div = document.createElement("div"); document.body.appendChild(div); div.innerHTML = ` <g-row gutter="20"> <g-col></g-col> <g-col></g-col> </g-row>`; const vm = new Vue({ el: div }); setTimeout(() => { const row = vm.$el.querySelector(".row"); expect(getComputedStyle(row).marginRight).to.eq("-10px"); expect(getComputedStyle(row).marginLeft).to.eq("-10px"); const cols = vm.$el.querySelectorAll(".col"); expect(getComputedStyle(cols[0]).paddingRight).to.eq("10px"); expect(getComputedStyle(cols[1]).paddingLeft).to.eq("10px"); done(); vm.$el.remove(); vm.$destroy(); }, 0); });

我使用直接在el上写入template代码,所以我默认的import Vue from "vue"(runtimeonly版本)无法编译这个代码,import Vue from "../node_modules/vue/dist/vue.esm.js"使用上面引入即可

在没有template选项是,el不替换

五、异步测试

还是这个代码,先看以下测试两个组件关系

it("接受gutter", function(done) { Vue.component("g-row", Row); Vue.component("g-col", Col); const div = document.createElement("div"); document.body.appendChild(div); div.innerHTML = ` <g-row gutter="20"> <g-col></g-col> <g-col></g-col> </g-row>`; const vm = new Vue({ el: div }); setTimeout(() => { const row = vm.$el.querySelector(".row"); expect(getComputedStyle(row).marginRight).to.eq("-10px"); expect(getComputedStyle(row).marginLeft).to.eq("-10px"); const cols = vm.$el.querySelectorAll(".col"); expect(getComputedStyle(cols[0]).paddingRight).to.eq("10px"); expect(getComputedStyle(cols[1]).paddingLeft).to.eq("10px"); done(); vm.$el.remove(); vm.$destroy(); }, 0); });

先说为什么需要seTimeout

从created和mounted钩子说起,createElement和appendChild在js代码是同步的,两个钩子分别在这两段代码后执行,钩子异步执行的。

由于我们在g-row组件中有mounted钩子,所以我们必须得进行异步检测,否则我们在new Vue之后立马进行测试,钩子还没执行完。

mocha异步测试

mocha默认不执行异步,加入done参数,调用done()就可以

六、垃圾回收

每一个测试完成之后,都要写下面两条代码

vm.$el.remove(); vm.$destroy();

有两个作用:

  • 销毁在页面中的数据
  • 销毁在内存的数据

虽然js是单线程,但是还有一个dom线程

var div = document. getElementById('xxx') div.onclick = function() { ///code } setTimeout(function(){ div. remove() }, 3000)

现在我们讨论,什么时候div上的函数被回收

函数被全局变量div上的onlick引用了

div.remove()只是在页面删掉了,没有被内存删掉

var div = document. getElementById('xxx') div.onclick = function() { ///code } setTimeout(function(){ div = mull }, 3000)

这个函数并没有被删除,函数是写在dom上的,div变量只是引用了dom对象

var div = document. getElementById('xxx') div.onclick = function() { ///code } setTimeout(function(){ var div2 = document. getElementById('xxx') }, 3000)

div= null和div.remove同时做就可以了,分别从内存和dom上删除了

ie有bug,即使这样都删不了,div.onlick = null 可以

到此这篇关于关于Vue单元测试的几个坑的文章就介绍到这了,更多相关 Vue单元测试 内容请搜索易盾网络以前的文章或继续浏览下面的相关文章希望大家以后多多支持易盾网络!

本文共计1322个文字,预计阅读时间需要6分钟。

Vue单元测试中常见问题有哪些细节容易踩坑?

一、前言本文将介绍如何使用Karma、Mocha、Chai、Sinon-Chai进行Vue实例属性的单元测试。我们将通过以下步骤实现:

二、全局组件的坑由于我的g-icon组件是全局注册的,所以在使用g-input组件时,g-icon是直接使用的。这导致在使用g-input组件时,g-icon是直接引用的,而非通过Vue实例。

三、解决方案为了解决这个问题,我们可以在单元测试中模拟全局组件,以便在测试时能够控制其行为。下面是一个简单的示例代码:

javascript// 引入Vue和组件import Vue from 'vue';import GIcon from '@/components/GIcon.vue';import GInput from '@/components/GInput.vue';

// 创建一个模拟的Vue实例const vm=new Vue({ render: h=> h(GInput)});

// 模拟全局组件Vue.component('g-icon', { template: 'Icon'});

// 使用vm.$mount()挂载组件vm.$mount();

// 执行测试describe('GInput组件', ()=> { it('should render g-icon correctly', ()=> { // 断言g-icon的文本内容 expect(vm.$el.querySelector('g-icon').textContent).toBe('Icon'); });});

以上代码中,我们首先创建了一个Vue实例,并在其中挂载了GInput组件。然后,我们模拟了全局组件g-icon,并使用Sinon-Chai进行断言。这样,我们就可以在单元测试中控制全局组件的行为,确保组件的正确性。

一、写在前面

这篇文章的代码使用karma,mocha,chai,sinon-chai配合Vue的实例属性进行单元测试

Vue单元测试中常见问题有哪些细节容易踩坑?

二、全局的组件的坑

由于我的g-icon是全局注册的,所以使用g-input组件时的时候g-icon是直接用的,所以测试时有关icon的代码永远是错的。

把g-icon局部注册的组件

三、在测试中触发点击事件

模拟我在app.vue里使用g-input组件

<g-input v-model="message"></g-input>

使用new event 和 dispatch 模拟事件在组件上触发,虽然这个事件和我们实际的事件不一样,但名字一样就够了,测试回调函数自带的参数

it("支持事件", () => { ["change", "input", "focus", "blur"].forEach(eventName => { vm = new Constructor({}).$mount(); const callback = sinon.fake(); vm.$on(eventName, callback); let event = new Event(eventName); Object.defineProperty(event, "target", { value: { value: "hi" }, enumerable: true }); let inputElement = vm.$el.querySelector("input"); inputElement.dispatchEvent(event); expect(callback).to.have.been.calledWith("hi"); }); });

测试这个组件事件触发时,回调的参数,由于自定义事件没有target,我们需要自己写上去

value: { value: "hi" }第一个value是defineProperty的

四、Vue的版本

坑来自于下面一段代码

it("接受gutter", function(done) { Vue.component("g-row", Row); Vue.component("g-col", Col); const div = document.createElement("div"); document.body.appendChild(div); div.innerHTML = ` <g-row gutter="20"> <g-col></g-col> <g-col></g-col> </g-row>`; const vm = new Vue({ el: div }); setTimeout(() => { const row = vm.$el.querySelector(".row"); expect(getComputedStyle(row).marginRight).to.eq("-10px"); expect(getComputedStyle(row).marginLeft).to.eq("-10px"); const cols = vm.$el.querySelectorAll(".col"); expect(getComputedStyle(cols[0]).paddingRight).to.eq("10px"); expect(getComputedStyle(cols[1]).paddingLeft).to.eq("10px"); done(); vm.$el.remove(); vm.$destroy(); }, 0); });

我使用直接在el上写入template代码,所以我默认的import Vue from "vue"(runtimeonly版本)无法编译这个代码,import Vue from "../node_modules/vue/dist/vue.esm.js"使用上面引入即可

在没有template选项是,el不替换

五、异步测试

还是这个代码,先看以下测试两个组件关系

it("接受gutter", function(done) { Vue.component("g-row", Row); Vue.component("g-col", Col); const div = document.createElement("div"); document.body.appendChild(div); div.innerHTML = ` <g-row gutter="20"> <g-col></g-col> <g-col></g-col> </g-row>`; const vm = new Vue({ el: div }); setTimeout(() => { const row = vm.$el.querySelector(".row"); expect(getComputedStyle(row).marginRight).to.eq("-10px"); expect(getComputedStyle(row).marginLeft).to.eq("-10px"); const cols = vm.$el.querySelectorAll(".col"); expect(getComputedStyle(cols[0]).paddingRight).to.eq("10px"); expect(getComputedStyle(cols[1]).paddingLeft).to.eq("10px"); done(); vm.$el.remove(); vm.$destroy(); }, 0); });

先说为什么需要seTimeout

从created和mounted钩子说起,createElement和appendChild在js代码是同步的,两个钩子分别在这两段代码后执行,钩子异步执行的。

由于我们在g-row组件中有mounted钩子,所以我们必须得进行异步检测,否则我们在new Vue之后立马进行测试,钩子还没执行完。

mocha异步测试

mocha默认不执行异步,加入done参数,调用done()就可以

六、垃圾回收

每一个测试完成之后,都要写下面两条代码

vm.$el.remove(); vm.$destroy();

有两个作用:

  • 销毁在页面中的数据
  • 销毁在内存的数据

虽然js是单线程,但是还有一个dom线程

var div = document. getElementById('xxx') div.onclick = function() { ///code } setTimeout(function(){ div. remove() }, 3000)

现在我们讨论,什么时候div上的函数被回收

函数被全局变量div上的onlick引用了

div.remove()只是在页面删掉了,没有被内存删掉

var div = document. getElementById('xxx') div.onclick = function() { ///code } setTimeout(function(){ div = mull }, 3000)

这个函数并没有被删除,函数是写在dom上的,div变量只是引用了dom对象

var div = document. getElementById('xxx') div.onclick = function() { ///code } setTimeout(function(){ var div2 = document. getElementById('xxx') }, 3000)

div= null和div.remove同时做就可以了,分别从内存和dom上删除了

ie有bug,即使这样都删不了,div.onlick = null 可以

到此这篇关于关于Vue单元测试的几个坑的文章就介绍到这了,更多相关 Vue单元测试 内容请搜索易盾网络以前的文章或继续浏览下面的相关文章希望大家以后多多支持易盾网络!