详解关于Vue单元测试的几个坑


Posted in Javascript onApril 26, 2020

一、写在前面

这篇文章的代码使用karma,mocha,chai,sinon-chai配合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单元测试 内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
Javascript-Mozilla和IE中的一个函数直接量的问题
Jan 09 Javascript
jQuery 打造动态下滑菜单实现说明
Apr 15 Javascript
javascript奇异的arguments分析
Oct 20 Javascript
js获取对象为null的解决方法
Nov 21 Javascript
浅谈js中字符和数组一些基本算法题
Aug 15 Javascript
js图片上传前预览功能(兼容所有浏览器)
Aug 24 Javascript
Bootstrap图片轮播效果详解
Oct 17 Javascript
如何开发出更好的JavaScript模块
Dec 22 Javascript
JS实现的文件拖拽上传功能示例
May 21 Javascript
vue中使用axios post上传头像/图片并实时显示到页面的方法
Sep 27 Javascript
LayUI switch 开关监听 获取属性值、更改状态的方法
Sep 21 Javascript
viewer.js实现图片预览功能
Jun 24 Javascript
es6函数之箭头函数用法实例详解
Apr 25 #Javascript
es6数组之扩展运算符操作实例分析
Apr 25 #Javascript
es6函数之尾调用优化实例分析
Apr 25 #Javascript
es6函数之尾递归用法实例分析
Apr 25 #Javascript
javascript 易错知识点实例小结
Apr 25 #Javascript
javascript执行上下文、变量对象实例分析
Apr 25 #Javascript
JavaScript ECMA-262-3 深入解析(二):变量对象实例详解
Apr 25 #Javascript
You might like
深入掌握include_once与require_once的区别
2013/06/17 PHP
ThinkPHP模板引擎之导入资源文件方法详解
2014/06/18 PHP
php制作文本式留言板
2015/03/18 PHP
支持中文的PHP按字符串长度分割成数组代码
2015/05/17 PHP
Javascript 错误处理的几种方法
2009/06/13 Javascript
解决火狐浏览器下JS setTimeout函数不兼容失效不执行的方法
2012/11/14 Javascript
extjs3 combobox取value和text案例详解
2013/02/06 Javascript
Nodejs sublime text 3安装与配置
2014/06/19 NodeJs
JavaScript中的Web worker多线程API研究
2014/12/06 Javascript
BootstrapTable与KnockoutJS相结合实现增删改查功能【二】
2016/05/10 Javascript
Ionic快速安装教程
2016/06/03 Javascript
javascript简单实现等比例缩小图片的方法
2016/07/27 Javascript
无阻塞加载js,防止因js加载不了影响页面显示的问题
2016/12/18 Javascript
微信小程序 动态的设置图片的高度和宽度详解及实例代码
2017/02/24 Javascript
react学习笔记之state以及setState的使用
2017/12/07 Javascript
JavaScript运行原理分析
2018/02/09 Javascript
JavaScript 中的 this 工作原理
2018/06/20 Javascript
jquery实现联想词搜索框和搜索结果分页的示例
2018/10/10 jQuery
微信小程序如何修改radio和checkbox的默认样式和图标
2019/07/24 Javascript
Ant Design Pro 下实现文件下载的实现代码
2019/12/03 Javascript
小程序跨页面交互的作用与方法详解
2020/01/07 Javascript
RxJS在TypeScript中的简单使用详解
2020/04/13 Javascript
jenkins自动构建发布vue项目的方法步骤
2021/01/04 Vue.js
[46:55]完美世界DOTA2联赛决赛 FTD vs Phoenix 第三场 11.08
2020/11/11 DOTA
Python3 XML 获取雅虎天气的实现方法
2018/02/01 Python
python判断计算机是否有网络连接的实例
2018/12/15 Python
python logging通过json文件配置的步骤
2020/04/27 Python
python使用多线程查询数据库的实现示例
2020/08/17 Python
财务副总经理工作职责
2013/11/25 职场文书
铁路工务反思材料
2014/02/07 职场文书
仓库文员岗位职责
2014/04/06 职场文书
老乡会致辞
2015/07/28 职场文书
2016感恩母亲节校园广播稿
2015/12/17 职场文书
给原生html中添加水印遮罩层的实现示例
2021/04/02 Javascript
使用Nginx的访问日志统计PV与UV
2022/05/06 Servers
一文了解Java动态代理的原理及实现
2022/07/07 Java/Android