摘要:但是,我還是覺得這是一個(gè)非常不錯(cuò)的話題測(cè)試代碼生成。,用于創(chuàng)建虛擬樹的。,用于修改的內(nèi)容。而第二個(gè)則是文本的變化從變成了。我們所要做的測(cè)試生成便是標(biāo)記這些變化,并記錄之。其他源碼見原文基于與的測(cè)試代碼生成
盡管是在年末,并且也還沒把書翻譯完,也還沒寫完書的第一稿。但是,我還是覺得這是一個(gè)非常不錯(cuò)的話題——測(cè)試代碼生成。
當(dāng)我們?cè)趯懸恍︰I測(cè)試的時(shí)候,我們總需要到瀏覽器去看一下一些DOM的變化。比如,我們點(diǎn)擊了某個(gè)下拉菜單,會(huì)有另外一個(gè)聯(lián)動(dòng)的下拉菜單發(fā)生了變化。而如果這個(gè)事件更復(fù)雜的時(shí)候,有時(shí)我們可能就很難觀察出來他們之間的變化。
Virtual DOM盡管這里的例子是以Jasmine作為例子,但是我想對(duì)于React也會(huì)有同樣的方法。
一個(gè)Jasmine jQuery測(cè)試如下是一個(gè)簡(jiǎn)單的Jamine jQuery的測(cè)試示例:
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的時(shí)候,我們?cè)O(shè)定了固定的DOM進(jìn)去,按照用戶的行為做一些相應(yīng)的操作。接著依據(jù)這個(gè)DOM中的元素變化 ,來作一些斷言。
那么,即使我們已經(jīng)有一個(gè)固定的DOM,想要監(jiān)聽這個(gè)DOM的變化就是一件容易的事。在我們斷言之前,我們就會(huì)有一個(gè)新的DOM。我們只需要Diff一下這兩個(gè)DOM的變化,就可以生成這部分測(cè)試代碼。
virtual-dom與HyperScript在尋覓中發(fā)現(xiàn)了virtual-dom這個(gè)庫,一個(gè)可以支持創(chuàng)建元素、diff計(jì)算以及patch操作的庫,并且它效率好像還不錯(cuò)。
virtual-dom可以說由下面幾部分組成的:
createElement,用于創(chuàng)建virtual Node。
diff,顧名思義,diff算法。
h,用于創(chuàng)建虛擬樹的DSL——HyperScript。HyperScript是一個(gè)JavaScript的HyperText。
patch,用于patch修改的內(nèi)容。
舉例來說,我們有下面一個(gè)生成Virtual DOM的函數(shù):
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函數(shù)用于生成一個(gè)Virtual Node。在這里,我們可以將我們的變量傳進(jìn)去,如1。就會(huì)生成如下圖所示的節(jié)點(diǎn):
{ "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" }
其中包含中相對(duì)應(yīng)的屬性等等。而我們只要調(diào)用createElement就可以創(chuàng)建出這個(gè)DOM。
如果我們修改了這個(gè)節(jié)點(diǎn)的一些元素,或者我們r(jià)ender了一個(gè)count=2的值時(shí),我們就可以diff兩個(gè)DOM。如:
virtualDom.diff(render(2), render(1))
根據(jù)兩個(gè)值的變化就會(huì)生成如下的一個(gè)對(duì)象:
{ "0": { "patch": { "style": { "height": "101px", "lineHeight": "101px", "width": "101px" } }, "type": 4, "vNode": { ... } }, "1": { "patch": { "text": "1" }, "type": 1, "vNode": { "text": "2" } }, ... }
第一個(gè)對(duì)象,即0中包含了一些屬性的變化。而第二個(gè)則是文本的變化——從2變成了1。我們所要做的測(cè)試生成便是標(biāo)記這些變化,并記錄之。
標(biāo)記DOM變化由于virtual-dom依賴于虛擬節(jié)點(diǎn)vNode,我們需要將fixtures轉(zhuǎn)換為hyperscript。這里我們就需要一個(gè)名為html2hyperscript的插件,來解析html。接著,我們就可以diff轉(zhuǎn)換完后的DOM:
var leftNode = "", rightNode = ""; var fixtures = ""; var change = "Hello World
"; parser(fixtures, function (err, hscript) { leftNode = eval(hscript); }); parser(change, function (err, hscript) { rightNode = eval(hscript); }); var patches = diff(leftNode, rightNode);Hello World
fs
接著,我們需要調(diào)用patch函數(shù)來做一些相應(yīng)的改變。
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); } } }
根據(jù)不同的類型,作一些對(duì)應(yīng)的輸出處理,如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來標(biāo)記修改的部分,及添加的部分。
最后,我們似乎就可以生成相應(yīng)的測(cè)試代碼了。。。
源碼見:https://github.com/phodal/luffa
原文:基于Virtual DOM與Diff DOM的測(cè)試代碼生成
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/78347.html
摘要:現(xiàn)在流行的前端框架都支持自定義組件,組件化開發(fā)已經(jīng)成為提高前端開發(fā)效率的銀彈。二對(duì)自定義組件的支持要想正確的渲染組件,第一步就是要告訴某個(gè)標(biāo)簽是自定義組件。下面的例子里,就是一個(gè)自定義組件。解決了識(shí)別自定義標(biāo)簽的問題,下一步就是定義標(biāo)簽了。 歡迎關(guān)注我的公眾號(hào)睿Talk,獲取我最新的文章:showImg(https://segmentfault.com/img/bVbmYjo); 一、...
摘要:前言的基本概念組件的構(gòu)建方法以及高級(jí)用法這背后的一切如何運(yùn)轉(zhuǎn)深入內(nèi)部的實(shí)現(xiàn)機(jī)制和原理初探源碼代碼組織結(jié)構(gòu)包含一系列的工具方法插件包含一系列同構(gòu)方法包含一些公用或常用方法如等包含一些測(cè)試方法等包含一些邊界錯(cuò)誤的測(cè)試用例是代碼的核心部分它包含了 前言 React的基本概念,API,組件的構(gòu)建方法以及高級(jí)用法,這背后的一切如何運(yùn)轉(zhuǎn),深入Virtual DOM內(nèi)部的實(shí)現(xiàn)機(jī)制和原理. 初探Rea...
摘要:經(jīng)過這次優(yōu)化,計(jì)算的時(shí)間快了那么幾毫秒。基于當(dāng)前這個(gè)版本的代碼還能做怎樣的優(yōu)化呢,請(qǐng)看下一篇的內(nèi)容你不知道的四的作用。 歡迎關(guān)注我的公眾號(hào)睿Talk,獲取我最新的文章:showImg(https://segmentfault.com/img/bVbmYjo); 一、前言 目前最流行的兩大前端框架,React和Vue,都不約而同的借助Virtual DOM技術(shù)提高頁面的渲染效率。那么,什...
摘要:市面上竟然擁有多個(gè)虛擬庫。虛擬庫,就是出來后的一種新式庫,以虛擬與算法為核心,屏蔽操作,操作數(shù)據(jù)即操作視圖。及其他虛擬庫已經(jīng)將虛擬的生成交由與處理了,因此不同點(diǎn)是,虛擬的結(jié)構(gòu)與算法。因此虛擬庫是分為兩大派系算法派與擬態(tài)派。 去哪兒網(wǎng)迷你React是年初立項(xiàng)的新作品,在這前,去哪兒網(wǎng)已經(jīng)深耕多年,擁有QRN(react-native的公司制定版),HY(基于React的hybird方案)...
摘要:速度略有損失,但可讀性大大提高。與傳統(tǒng)對(duì)比傳統(tǒng)的算法通過循環(huán)遞歸每一個(gè)節(jié)點(diǎn),進(jìn)行對(duì)比,這樣的操作效率非常的低,復(fù)雜程度其中標(biāo)識(shí)樹的節(jié)點(diǎn)總數(shù)。 原文鏈接:Nealyang PersonalBlog 由于源碼中diff算法摻雜了太多別的功能模塊,并且dom diff相對(duì)于之前的代碼實(shí)現(xiàn)來說還是有些麻煩的,尤其是列表對(duì)比的算法,所以這里我們單獨(dú)拿出來說他實(shí)現(xiàn) 前言 眾所周知,React中最...
閱讀 1402·2021-10-14 09:43
閱讀 992·2021-09-10 10:51
閱讀 1443·2021-09-01 10:42
閱讀 2189·2019-08-30 15:55
閱讀 586·2019-08-30 15:55
閱讀 2339·2019-08-30 14:21
閱讀 1715·2019-08-30 13:04
閱讀 3467·2019-08-29 13:09