前些天接手了一个旧项目。幸好不是在原来的基础上做些修修改改的工作,可以算是开发新版的。
  把前面同事留下来的代码 down 下来,看了一下。总体还是挺好的。还有 macha + chai 的测试目录。
  我也是近一段时间开始接触测试。很久之前看了阮大神写的 mocha 教程,不过也看看,写写简单的 demo。
  前同事留下的测试,是基于浏览器的,主要还是功能测试。这里不详细说怎么在浏览器端使用 mocha 测试了。因为涉及到交互的反馈、追踪,所以采用的方式是,先用 iframe 加载待测页面,然后用 contentWindow 的方式拿到 iframe 的环境,再做一些操作。手动触发一些功能,然后再去判断相应的变化有没有发生。
  本地启动了一个 server,浏览器里跑了几遍测试。后发现的问题是,有一个点击测试怎么都过不了。于是又开启了阅读代码的过程。
  后发现了问题所在,页面使用的是自己封装的 tap 事件,整个事件系统也是对原生 Element 原型的拓展。可是怎么触发 tap 呢?前同事用了 touchend 。可是并没有用啊, tap 事件的触发可是结合了从 touchstart 开启一系列事件参数的判断的。
  后来我想,浏览器端功能测试,能不能也拿到命令行上面来呢?
  从 mocha 转到 ava
  正在此时,我想起了 jsdom 这个大神级作品。
  一开始打算用 mocha + jsdom 跑一把。折腾了几次发现,mocha 这家伙不好适应异步的工作,这事情很难搞啊。
  可能要交代下我做了什么,嗯,我加载了一个 jquery 脚本,这样得外部文件,于是有异步场景了。试了好多遍,mocha 还是没能实现我的期望。(你也可以拿 mocha 试试看,多试几次,如果单纯靠那个 done 你能成功,那么请私信我哟。)
  又想想白天乱逛 github 的时候,在一些个项目中看到了 ava 这个测试工具。搜索一番,似乎是 tj 大神的作品(?),据说正适用于异步场景。
  好,那来试试看呗。前因交代清楚了,下面开始正式进入教程阶段。
  开始讲 demo
  我将自己的 demo 放到了 github 上,地址是 https://github.com/AngusFu/jsdom-ava-demo 。你可以直接克隆项目,然后在本地跑起来。
  因为是 demo,项目内容很简单,两个 js,一个用于测试 html 文件。
  测试场景
  先说测试场景:页面上有一个红色背景的 div,通过原生的 addEventListener 绑定了 click 事件。点击之后,将背景色变换为绿色。酱简单?对,主要这个,一方面我是想测试下 jsdom 对事件系统和 css 解析的支持(手动触发事件,css 解析和值变化),一方面是想试试这种异步场景下怎么更好地测试。
  那些对测试脚本运行速度有非常严格要求的同学请想好了再往后看。因为根据我的经验,jsdom + ava 这俩组合起来,速度确实慢得不行。我还没仔细探究原因,但想来无非以下几点:
  测试脚本要经过 babel 6 编译一遍,有耗时;
  jsdom 系统比较庞大,解析起来费劲;
  我使用了 jsdom 的 jQueryify 方法从外部加载了 jQuery 文件(但这方法确实给力);
  ava 本身其他方面的问题;
  暂且忍着点。
  核心 html 如下:
  <style>
  div {width: 500px; height: 500px; background-color: red;}
  </style>
  <div id="div"></div>
  <script>
  document.getElementById("div").onclick = function (){
  this.style.backgroundColor = 'green';
  };
  </script>
  测试工具安装
  下面来谈工具的安装。
  首先安装 jsdom,这倒是很简单:
  $ npm install --save jsdom
  接着安装 ava,好先全局安装一遍:
  $ npm install -g ava
  $ npm install --save ava
  然后为了方便使用 npm test 命令,执行下面的命令:
  $ ava --init
  这一行的目的是将 ava 命令放到你的 package.json 中的 scripts 字段中,方便之后使用 npm test 直接开启跑测试。当然你也可以不管这一步,我比较喜欢自己敲 ava xx.js 这样子。
  编写测试
  好了,环境安装完毕。下面来看脚本。
  import fs from 'fs';
  import { jsdom } from 'jsdom';
  import test from 'ava';
  ava 在运行时会通过 babel 6 对测试脚本进行编译,因此完全可以自由发挥,generator、async & await 什么的都尽情地用吧。而且作者也是建议和支持这样做的,简单明了的测试脚本,重要性有时候可能和测试本身一样重要。
  引入 fs 是为了读取我们的 html 文件。
  关于 jsdom 的用法,更多的可以参考 https://github.com/tmpvar/jsdom ,看项目的文档。这里我使用的是简单易懂的 require('jsdom').jsdom 形式,便于以同步的形式解析生成我们需要的 window 对象,如下:
  var window = jsdom(fs.readFileSync('./test.html')).defaultView;
  一个挺好用的方法是 jsdom.jQueryify ,能向页面注入 jQuery。不过这是个异步的方法(废话),所以这里我使用了 Promise,也是为了方便之后使用 async & await 语法。
  function jsdomTest(){
  return new Promise(function (resolve, reject){
  jsdom.jQueryify(window, "http://apps.bdimg.com/libs/jquery/2.1.4/jquery.js", function (){
  resolve(window.jQuery);
  });
  });
  }
  ava 的测试用例写起来也挺简单,来看代码:
  test('点击测试', async t => {
  var $ = await jsdomTest();
  var $div = $('#div');
  var colorBeforeClick, colorAfterClick;
  console.log(colorBeforeClick = $div.css('background-color'));
  $div.trigger('click');
  console.log(colorAfterClick = $div.css('background-color'));
  t.not(colorBeforeClick, colorAfterClick, 'bgColor changed');
  });