详解关于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下4个跨浏览器必备的函数
Mar 07 Javascript
javascript开发技术大全-第1章javascript概述
Jul 03 Javascript
不用锚点也可以平滑滚动到页面的指定位置实现代码
May 08 Javascript
JavaScript字符串对象toLowerCase方法入门实例(用于把字母转换为小写)
Oct 17 Javascript
jQuery遍历json的方法(推荐)
Jun 12 Javascript
微信小程序前端源码逻辑和工作流
Sep 25 Javascript
使用jquery如何获取时间
Oct 13 Javascript
JavaScript实现点击按钮复制指定区域文本(推荐)
Nov 25 Javascript
AngularJS 文件上传控件 ng-file-upload详解
Jan 13 Javascript
简单实现AngularJS轮播图效果
Apr 10 Javascript
详解vue-cli 脚手架项目-package.json
Jul 04 Javascript
Bootstrap与Angularjs的模态框实例代码
Aug 03 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 CURL模拟登录新浪微博抓取页面内容 基于EaglePHP框架开发
2012/01/16 PHP
ThinkPHP3.2.2的插件控制器功能
2015/03/05 PHP
php随机获取金山词霸每日一句的方法
2015/07/09 PHP
Yii2实现自定义独立验证器的方法
2017/05/05 PHP
php使用pthreads v3多线程实现抓取新浪新闻信息操作示例
2020/02/21 PHP
犀利的js 函数集合
2009/06/11 Javascript
javascript中最常用的继承模式 组合继承
2010/08/12 Javascript
基于jquery的图片幻灯展示源码
2012/07/15 Javascript
使用js正则控制input标签只允许输入的值
2013/07/29 Javascript
js或jquery实现页面打印可局部打印
2014/03/27 Javascript
JavaScript实现的石头剪刀布游戏源码分享
2014/08/22 Javascript
js实现在同一窗口浏览图片
2014/09/17 Javascript
Jquery easyui开启行编辑模式增删改操作
2016/01/14 Javascript
JS中的hasOwnProperty()、propertyIsEnumerable()和isPrototypeOf()
2016/08/11 Javascript
thinkjs之页面跳转同步异步操作
2017/02/05 Javascript
JavaScript中 DOM操作方法小结
2017/04/25 Javascript
微信小程序滚动Tab实现左右可滑动切换
2017/08/17 Javascript
AngularJS对动态增加的DOM实现ng-keyup事件示例
2018/03/12 Javascript
axios全局注册,设置token,以及全局设置url请求网段的方法
2018/09/25 Javascript
Webpack设置环境变量的一些误区详解
2019/12/19 Javascript
JS实现transform实现扇子效果
2020/01/17 Javascript
python两种遍历字典(dict)的方法比较
2014/05/29 Python
使用Django Form解决表单数据无法动态刷新的两种方法
2017/07/14 Python
Python对象中__del__方法起作用的条件详解
2018/11/01 Python
python实现微信每日一句自动发送给喜欢的人
2019/04/29 Python
python 两个一样的字符串用==结果为false问题的解决
2020/03/12 Python
html5指南-1.html5全局属性(html5 global attributes)深入理解
2013/01/07 HTML / CSS
Giglio俄罗斯奢侈品购物网:男士、女士、儿童高级时装
2018/07/27 全球购物
Fossil加拿大官网:化石手表、手袋、首饰及配饰
2019/04/23 全球购物
戴尔马来西亚官网:Dell Malaysia
2020/05/02 全球购物
第二层交换机和路由器的区别?第三层交换机和路由器的区别?
2013/05/23 面试题
中文系学生自荐信范文
2013/11/13 职场文书
儿媳婚宴答谢词
2014/01/14 职场文书
党风廉政建设个人总结
2015/03/06 职场文书
2015初中团支部工作总结
2015/07/21 职场文书
Python绘画好看的星空图
2022/03/17 Python