详解关于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 相关文章推荐
修复IE9&amp;safari 的sort方法
Oct 21 Javascript
JavaScript高级程序设计(第3版)学习笔记3 js简单数据类型
Oct 11 Javascript
Jquery的Tabs内容轮换效果实现代码,几行搞定
Feb 12 Javascript
javascript设计模式之对象工厂函数与构造函数详解
Jul 30 Javascript
jQuery实现图像旋转动画效果
May 29 Javascript
node.js学习之交互式解释器REPL详解
Dec 08 Javascript
jQuery实现radio第一次点击选中第二次点击取消功能
May 15 jQuery
基于jQuery的左滑出现删除按钮的示例
Aug 29 jQuery
Angular脚手架开发的实现步骤
Apr 09 Javascript
vue+elementUI实现表格关键字筛选高亮
Oct 26 Javascript
layer.alert自定义关闭回调事件的方法
Sep 27 Javascript
Node.js API详解之 net模块实例分析
May 18 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
PHP安全配置
2006/12/06 PHP
PHP 学习路线与时间表
2010/02/21 PHP
php基于闭包实现函数的自调用(递归)实例分析
2016/11/11 PHP
PHP防止图片盗用(盗链)的方法小结
2016/11/11 PHP
PHPstorm快捷键(分享)
2017/07/17 PHP
jQuery获取动态生成的元素示例
2014/06/15 Javascript
禁止iframe脚本弹出的窗口覆盖了父窗口的方法
2014/09/06 Javascript
node.js中的fs.statSync方法使用说明
2014/12/16 Javascript
JavaScript阻止事件冒泡示例分享
2014/12/28 Javascript
javascript中var的重要性分析
2015/02/11 Javascript
flash+jQuery实现可关闭及重复播放的压顶广告
2015/04/15 Javascript
jQuery解析json数据实例分析
2015/11/24 Javascript
JavaScript数组方法总结分析
2016/05/06 Javascript
javascript 单例模式详解及简单实例
2017/02/14 Javascript
NodeJs安装npm包一直失败的解决方法
2017/04/28 NodeJs
jQuery+Ajax请求本地数据加载商品列表页并跳转详情页的实现方法
2017/07/12 jQuery
JavaScript面向对象精要(下部)
2017/09/12 Javascript
angular.js4使用 RxJS 处理多个 Http 请求
2017/09/23 Javascript
在Vue项目中使用snapshot测试的具体使用
2019/04/16 Javascript
JS实现的碰撞检测与周期移动完整示例
2019/09/02 Javascript
[47:43]完美世界DOTA2联赛PWL S3 Magama vs GXR 第二场 12.19
2020/12/24 DOTA
Python中使用Tkinter模块创建GUI程序实例
2015/01/14 Python
python不换行之end=与逗号的意思及用途
2017/11/21 Python
django解决跨域请求的问题详解
2019/01/20 Python
python之yield和Generator深入解析
2019/09/18 Python
python对象销毁实例(垃圾回收)
2020/01/16 Python
html5 canvas简单封装一个echarts实现不了的饼图
2018/06/12 HTML / CSS
下列程序在32位linux或unix中的结果是什么
2015/01/26 面试题
施工安全协议书
2013/12/11 职场文书
毕业留言寄语大全
2014/04/10 职场文书
给老婆的保证书范文
2014/04/28 职场文书
手机被没收的检讨书
2014/10/04 职场文书
2014办公室年度工作总结
2014/12/09 职场文书
2016年元旦寄语
2015/08/17 职场文书
java实现对Hadoop的操作
2021/07/01 Java/Android
MySQL三种方式实现递归查询
2022/04/18 MySQL