尽管是在年末,并且也还没把书翻译完,也还没写完书的第一稿。但是,我还是觉得这是一个非常不错的话题——测试代码生成。

当我们在写一些UI测试的时候,我们总需要到浏览器去看一下一些DOM的变化。比如,我们点击了某个下拉菜单,会有另外一个联动的下拉菜单发生了变化。而如果这个事件更复杂的时候,有时我们可能就很难观察出来他们之间的变化。

Virtual DOM

尽管这里的例子是以Jasmine作为例子,但是我想对于React也会有同样的方法。

一个Jasmine jQuery测试

如下是一个简单的Jamine jQuery的测试示例:

  describe("toHaveCss", function (){beforeEach(function (){setFixtures(sandbox())})it("should pass if the element has matching css", function (){$("#sandbox").css("display", "none")$("#sandbox").css("margin-left", "10px")expect($("#sandbox")).toHaveCss({display: "none", "margin-left": "10px"})})
});

在beforeEach的时候,我们设定了固定的DOM进去,按照用户的行为做一些相应的操作。接着依据这个DOM中的元素变化 ,来作一些断言。

那么,即使我们已经有一个固定的DOM,想要监听这个DOM的变化就是一件容易的事。在我们断言之前,我们就会有一个新的DOM。我们只需要Diff一下这两个DOM的变化,就可以生成这部分测试代码。

virtual-dom与HyperScript

在寻觅中发现了virtual-dom这个库,一个可以支持创建元素、diff计算以及patch操作的库,并且它效率好像还不错。

virtual-dom可以说由下面几部分组成的:

  1. createElement,用于创建virtual Node。

  2. diff,顾名思义,diff算法。

  3. h,用于创建虚拟树的DSL——HyperScript。HyperScript是一个JavaScript的HyperText。

  4. patch,用于patch修改的内容。

举例来说,我们有下面一个生成Virtual DOM的函数:

function render(count)  {return h('div', {style: {textAlign: 'center',lineHeight: (100 + count) + 'px',border: '1px solid red',width: (100 + count) + 'px',height: (100 + count) + 'px'}}, [String(count)]);
}

render函数用于生成一个Virtual Node。在这里,我们可以将我们的变量传进去,如1。就会生成如下图所示的节点:

{"children": [{"text": "1"}],"count": 1,"descendantHooks": false,"hasThunks": false,"hasWidgets": false,"namespace": null,"properties": {"style": {"border": "1px solid red","height": "101px","lineHeight": "101px","textAlign": "center","width": "101px"}},"tagName": "DIV"
}

其中包含中相对应的属性等等。而我们只要调用createElement就可以创建出这个DOM。

如果我们修改了这个节点的一些元素,或者我们render了一个count=2的值时,我们就可以diff两个DOM。如:

virtualDom.diff(render(2), render(1))

根据两个值的变化就会生成如下的一个对象:

{"0": {"patch": {"style": {"height": "101px","lineHeight": "101px","width": "101px"}},"type": 4,"vNode": {...}},"1": {"patch": {"text": "1"},"type": 1,"vNode": {"text": "2"}},...
}

第一个对象,即0中包含了一些属性的变化。而第二个则是文本的变化——从2变成了1。我们所要做的测试生成便是标记这些变化,并记录之。

标记DOM变化

由于virtual-dom依赖于虚拟节点vNode,我们需要将fixtures转换为hyperscript。这里我们就需要一个名为html2hyperscript的插件,来解析html。接着,我们就可以diff转换完后的DOM:

var leftNode = "", rightNode = "";
var fixtures = '<div id="example"><h1 class="hello">Hello World</h1></div>';
var change = '<div id="example"><h1 class="hello">Hello World</h1><h2>fs</h2></div>';
parser(fixtures, function (err, hscript) {leftNode = eval(hscript);
});parser(change, function (err, hscript) {rightNode = eval(hscript);
});var patches = diff(leftNode, rightNode);

接着,我们需要调用patch函数来做一些相应的改变。

luffa.patch(virtualDom.create(leftNode), patches)

并且,我们可以尝试在patch阶段做一些处理——输出修改:

function printChange(originRootNodeHTML, applyNode) {var patchType;for (var patchIndex = 0; patchIndex < applyNode.newNodes.length; patchIndex++) {patchType = applyNode.newNodes[patchIndex].method;switch (patchType) {case 'insert':printInsert(applyNode);break;case 'node':printNode(applyNode, originRootNodeHTML, patchIndex);break;case 'remove':printRemove(applyNode, originRootNodeHTML, patchIndex);break;case 'string':printString(applyNode, originRootNodeHTML, patchIndex);break;case 'prop':printProp(applyNode, originRootNodeHTML, patchIndex);break;default:printDefault(applyNode, originRootNodeHTML, patchIndex);}}
}

根据不同的类型,作一些对应的输出处理,如pringNode:

function printNode(applyNode, originRootNodeHTML, patchIndex) {var originNode = $(applyNode.newNodes[patchIndex].vNode).prop('outerHTML') || $(applyNode.newNodes[patchIndex].vNode).text();var newNode = $(applyNode.newNodes[patchIndex].newNode).prop('outerHTML');console.log('%c' + originRootNodeHTML.replace(originNode, '%c' + originNode + '%c') + ', %c' + newNode, luffa.ORIGIN_STYLE, luffa.CHANGE_STYLE, luffa.ORIGIN_STYLE, luffa.NEW_STYLE);
}

用Chrome的console来标记修改的部分,及添加的部分。

最后,我们似乎就可以生成相应的测试代码了。。。

其他

源码见:https://github.com/phodal/luffa
原文:基于Virtual DOM与Diff DOM的测试代码生成

基于Virtual DOM与Diff DOM的测试代码生成相关推荐

  1. 【Virtual DOM】虚拟 DOM 和 Snabbdom 库

    前言 笔记来源:拉勾教育 大前端高薪训练营 阅读建议:建议通过左侧导航栏进行阅读 Virtual DOM 基本介绍 什么是 Virtual DOM Virtual DOM(虚拟 DOM),是由普通的的 ...

  2. 探秘vue核心之虚拟DOM与diff算法

    探秘vue核心之虚拟DOM与diff 一.真实DOM和其解析流程 所有的浏览器渲染引擎工作流程大致分为5步: 创建 DOM 树 -> 创建 Style Rules -> 构建 Render ...

  3. 浏览器性能优化(2)React 虚拟 dom与diff算法

    随着前端技术快速发展,现在的mvvm几大框架遍布前端行业,那么它们对浏览器的性能到底影响多大?与传统的jq相比做了哪些优化呢? 文章目录: React中的虚拟DOM是什么? 虚拟DOM的简单实现(di ...

  4. virtual DOM和真实DOM的区别_让虚拟DOM和DOMdiff不再成为你的绊脚石

    来源 | https://juejin.im/post/5c8e5e4951882545c109ae9c Keep Moving 时至今日,前端对于知识的考量是越来越有水平了,逼格高大上了 各类框架大 ...

  5. 虚拟DOM和Diff算法 - 入门级

    什么是虚拟Dom 我们知道我们平时的页面都是有很多Dom组成,那虚拟Dom(virtual dom)到底是什么,简单来讲,就是将真实的dom节点用JavaScript来模拟出来,而Dom变化的对比,放 ...

  6. diff算法_Virtual Dom和Diff算法

    前言 这是一篇很长的文章!!!坚持看到最后有彩蛋哦!!! 文章开篇,我们先思考一个问题,大家都说 virtual dom 这,virtual dom 那的,那么 virtual dom 到底是啥? 首 ...

  7. 【总结】1135- 图解虚拟 DOM 之 DIff 算法

    原文: https://juejin.cn/post/7000266544181674014 1. 目录 1. 相关知识点: 2. 虚拟DOM(Virtual DOM) 2.1. 什么是虚拟DOM 2 ...

  8. vue--mixin混入以及虚拟DOM和diff算法

    mixin混入 使用它的好处: 将 options 中的配置项可以单独抽离出来,单独管理,这样方便维护 使用: 新建一个对象用来保存 options 中某一个配置项,比如: methods 接下来要将 ...

  9. 既然Vue通过数据劫持可以精准探测数据变化,为什么还需要虚拟DOM进行diff检测差异?

    既然Vue通过数据劫持可以精准探测数据变化,为什么还需要虚拟DOM进行diff检测差异? 考点: Vue的变化侦测原理 前置知识: 依赖收集.虚拟DOM.响应式系统 现代前端框架有两种方式侦测变化,一 ...

最新文章

  1. Windows 8部署系列PART6:准备模板计算机配置
  2. tensowflow 训练 远程提交_深度解析AutoML工具——NNI:带上超参一起训练
  3. 认识VC++类向导的使用
  4. 欢迎使用Markdown编辑器写博客
  5. Tarjan的求双连通分量算法
  6. Quartz简单实例
  7. java nio 系列教程 四_Java NIO系列教程(四) Scatter/Gather
  8. kubernetes英语怎么读_英语音标怎么读?如何从零基础英语音标入门英语口语学习...
  9. 想转行数据分析,看完这篇再做决定
  10. 如何实现大批量UKEY远程连接管控?
  11. ATmega128单片机](熔丝修改后无法烧录程序情况)
  12. 测试计划报告---5W1H
  13. c语言变量报存在bss段,浅谈c语言代码段 数据段 bss段
  14. SAP GOS cl_gos_manager 添加附件功能
  15. c语言计算输入20个有符号整数,统计正整数,零,负整数的个数.操作,输入20个有符号整数,统计正整数.零.负整数的个数.并分别计算之和...
  16. 流利阅读 2019.1.22 Top S. Korean animal rights group slammed for destroying dogs
  17. \n和endl的区别
  18. http 301 302 303 307 308 傻傻分不清
  19. 从目标检测到小目标检测
  20. 为什么要给网桥分配IP地址

热门文章

  1. Android之ListActivity(一):布局与数据绑定
  2. 2017-2018 ACM-ICPC German Collegiate Programming Contest (GCPC 2017)
  3. sql语句中having的作用是?
  4. shell脚本之 if,case,for的用法
  5. 谷歌邮箱上不了的情况下怎么登录谷歌邮箱
  6. QQ远程协助没动静?QQ版本有讲究
  7. OSPF-网络类型(ip ospf network ?)
  8. gprs发送信号对方如何接收_和接收缓冲区比较:Netty发送缓冲区是如何设计的,why?...
  9. 自学成才翁_作为一名自学成才的开发者从“我的旅程”中吸取的教训
  10. 什么是棉绒,它如何节省您的时间?