详解关于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 相关文章推荐
js中的window.open返回object的错误的解决方法
Aug 15 Javascript
JQuery开发的数独游戏代码
Oct 29 Javascript
JavaScript词法作用域与调用对象深入理解
Nov 29 Javascript
jquery 选择器引擎sizzle浅析
Feb 06 Javascript
jquery ajax跨域解决方法(json方式)
Feb 04 Javascript
JS的参数传递示例介绍
Feb 08 Javascript
基于Javascript实现的不重复ID的生成器
Dec 25 Javascript
字太多用...代替的方法(两种)
Mar 15 Javascript
JS实现的数组去除重复数据算法小结
Nov 17 Javascript
webpack中的热刷新与热加载的区别
Apr 09 Javascript
VUE实现图片验证码功能
Nov 18 Javascript
解决vue+webpack项目接口跨域出现的问题
Aug 10 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
THINKPHP+JS实现缩放图片式截图的实现
2010/03/07 PHP
php数组相加 array(“a”)+array(“b”)结果还是array(“a”)
2012/09/19 PHP
PHP按行读取文件时删除换行符的3种方法
2014/05/04 PHP
PHP错误Warning: Cannot modify header information - headers already sent by解决方法
2014/09/27 PHP
PHP中soap的用法实例
2014/10/24 PHP
PHP读取配置文件类实例(可读取ini,yaml,xml等)
2015/07/28 PHP
完美解决phpdoc导出文档中@package的warning及Error的错误
2016/05/17 PHP
Javascript 更新 JavaScript 数组的 uniq 方法
2008/01/23 Javascript
jquery 操作单选框,复选框,下拉列表实现代码
2009/10/27 Javascript
window.open打开页面居中显示的示例代码
2013/12/27 Javascript
jquery调整表格行tr上下顺序实例讲解
2016/01/09 Javascript
解决微信浏览器Javascript无法使用window.location.reload()刷新页面
2016/06/21 Javascript
AngularJs 国际化(I18n/L10n)详解
2016/09/01 Javascript
Node.js + Redis Sorted Set实现任务队列
2016/09/19 Javascript
JS实现给对象动态添加属性的方法
2017/01/05 Javascript
Angular.Js中过滤器filter与自定义过滤器filter实例详解
2017/05/08 Javascript
js判断用户是输入的地址请求的路径(实例讲解)
2017/07/18 Javascript
DVA框架统一处理所有页面的loading状态
2017/08/25 Javascript
详解javascript中的变量提升和函数提升
2018/05/24 Javascript
基于Vue实现图片在指定区域内移动的思路详解
2018/11/11 Javascript
小程序自定义模板实现吸顶功能
2020/01/08 Javascript
js常用方法、检查是否有特殊字符串、倒序截取字符串操作完整示例
2020/01/26 Javascript
在vue中使用inheritAttrs实现组件的扩展性介绍
2020/12/07 Vue.js
[05:08]DOTA2-DPC中国联赛3月6日Recap集锦
2021/03/11 DOTA
python操作MySQL数据库的方法分享
2012/05/29 Python
Python匹配中文的正则表达式
2016/05/11 Python
对python sklearn one-hot编码详解
2018/07/10 Python
python RC4加密操作示例【测试可用】
2019/09/26 Python
表达自我的市场:Society6
2018/08/01 全球购物
《美丽的彩虹》教学反思
2014/02/25 职场文书
标准单位租车协议书
2014/09/23 职场文书
2016年九九重阳节活动总结
2016/04/01 职场文书
关于感恩老师的古诗句
2019/08/20 职场文书
Python实战之实现康威生命游戏
2021/04/26 Python
JavaScript实例 ODO List分析
2022/01/22 Javascript
python使用shell脚本创建kafka连接器
2022/04/29 Python