详解关于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在IE和Firefox(火狐)的不兼容问题解决方法小结
Apr 13 Javascript
jQuery easyui datagrid动态查询数据实例讲解
Feb 26 Javascript
JS简单实现文件上传实例代码(无需插件)
Nov 15 Javascript
js判断滚动条是否已到页面最底部或顶部实例
Nov 20 Javascript
JavaScript中的toDateString()方法使用详解
Jun 12 Javascript
jQuery基础知识点总结(必看)
May 31 Javascript
AngularJS中的拦截器实例详解
Apr 07 Javascript
关于使用js算总价的问题
Jun 23 Javascript
浅谈Node Inspector 代理实现
Oct 19 Javascript
react 创建单例组件的方法
Apr 26 Javascript
Node.js连接Sql Server 2008及数据层封装详解
Aug 27 Javascript
mpvue性能优化实战技巧(小结)
Apr 17 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实现让页面只能被百度gogole蜘蛛访问的方法
2009/12/29 PHP
php三维数组去重(示例代码)
2013/11/26 PHP
PHP Reflection API详解
2015/05/12 PHP
PHP生成plist数据的方法
2015/06/16 PHP
PHP排序算法之简单选择排序(Simple Selection Sort)实例分析
2018/04/20 PHP
遍历jquery对象的代码分享
2011/11/02 Javascript
Prototype源码浅析 Enumerable部分之each方法
2012/01/16 Javascript
Jquery为单选框checkbox绑定单击click事件
2012/12/18 Javascript
jquery制作弹窗提示窗口代码分享
2014/03/02 Javascript
jQuery固定浮动侧边栏实现思路及代码
2014/09/28 Javascript
Javascript编写俄罗斯方块思路及实例
2015/07/07 Javascript
js淡入淡出焦点图幻灯片效果代码分享
2015/09/08 Javascript
D3.js实现雷达图的方法详解
2016/09/22 Javascript
JS简单实现自定义右键菜单实例
2017/05/31 Javascript
带你了解session和cookie作用原理区别和用法
2017/08/14 Javascript
深入浅析ES6 Class 中的 super 关键字
2017/10/20 Javascript
解决layer.open后laydate失效的问题
2019/09/06 Javascript
ES6中的Javascript解构的实现
2020/10/30 Javascript
vue 根据选择的月份动态展示日期对应的星期几
2021/02/06 Vue.js
[06:42]DOTA2每周TOP10 精彩击杀集锦vol.1
2014/06/25 DOTA
[02:30]联想杯DOTA2完美世界全国高校联赛—北京站现场
2015/11/16 DOTA
[04:04]DOTA2亚洲邀请赛比赛场馆&酒店全攻略
2017/03/23 DOTA
python端口扫描系统实现方法
2014/11/19 Python
python实现m3u8格式转换为mp4视频格式
2018/02/28 Python
Python将主机名转换为IP地址的方法
2019/08/14 Python
Python 多线程C段扫描、检测 Ping扫描脚本的实现
2020/09/03 Python
YOOX美国官方网站:全球著名的多品牌时尚网络概念店
2016/09/11 全球购物
简述进程的启动、终止的方式以及如何进行进程的查看
2014/02/20 面试题
编辑硕士自荐信范文
2013/11/27 职场文书
竞职演讲稿范文
2014/01/11 职场文书
运动会邀请函范文
2014/01/31 职场文书
你的创业计划书怎样才能打动风投
2014/02/06 职场文书
护士找工作求职信
2014/07/02 职场文书
浅谈MySQL 亿级数据分页的优化
2021/06/15 MySQL
Python使用海龟绘图实现贪吃蛇游戏
2021/06/18 Python
为什么RedisCluster设计成16384个槽
2021/09/25 Redis