react的元件結構和jsx文法,不适用傳統的測試工具,必須有新的測試方法和工具。
本文總結目前react測試的基本做法和最佳實踐,手把手教你如何寫react測試。

然後,打開 http://127.0.0.1:8080/,你會看到一個 todo 應用。
接下來,我們就要測試這個應用,一共有5個測試點。
應用标題應為"todos" todo項的初始狀态("未完成"或"已完成")應該正确 點選一個todo項,它就反轉狀态("未完成"變為"已完成",反之亦然) 點選删除按鈕,該todo項就被删除 點選添加按鈕,會新增一個todo項
這就是說,同樣的測試用例至少有兩種寫法,本文都将介紹。
官方測試工具庫的寫法 enzyme的寫法
我們知道,一個react元件有兩種存在形式:虛拟dom對象(即<code>react.component</code>的執行個體)和真實dom節點。官方測試工具庫對這兩種形式,都提供測試解決方案。
shallow rendering:測試虛拟dom的方法 dom rendering: 測試真實dom的方法
shallow rendering (淺渲染)指的是,将一個元件渲染成虛拟dom對象,但是隻渲染第一層,不渲染所有子元件,是以處理速度非常快。它不需要dom環境,因為根本沒有加載進dom。
首先,在測試腳本之中,引入官方測試工具庫。
然後,寫一個 shallow rendering 函數,該函數傳回的就是一個淺渲染的虛拟dom對象。
上面代碼中,<code>const app = shallowrender(app)</code>表示對<code>app</code>元件進行"淺渲染",然後<code>app.props.children[0].props.children</code>就是元件的标題。
你大概會覺得,這個屬性的寫法太古怪了,但實際上是有規律的。每一個虛拟dom對象都有<code>props.children</code>屬性,它包含一個數組,裡面是所有的子元件。<code>app.props.children[0]</code>就是第一個子元件,在我們的例子中就是<code>h1</code>元素,它的<code>props.children</code>屬性就是<code>h1</code>的文本。
首先,需要修改<code>shallowrender</code>函數,讓它接受第二個參數。
下面就是測試用例。
官方測試工具庫的第二種測試方法,是将元件渲染成真實的dom節點,再進行測試。這時就需要調用<code>renderintodocument</code> 方法。
現在,每次運作<code>npm test</code>,<code>setup.js</code> 就會包含在測試腳本之中一起執行。
上面代碼中,第一步是将<code>app</code>渲染成真實的dom節點,然後使用<code>scryrendereddomcomponentswithtag</code>方法找出<code>app</code>裡面所有的<code>li</code>元素。然後,取出第一個<code>li</code>元素裡面的<code>button</code>元素,使用<code>testutils.simulate.click</code>方法在該元素上模拟使用者點選。最後,判斷剩下的<code>li</code>元素應該少了一個。
這種測試方法的基本思路,就是找到目标節點,然後觸發某種動作。官方測試工具庫提供多種方法,幫助使用者找到所需的dom節點。
可以看到,上面這些方法很難拼寫,好在還有另一種找到dom節點的替代方法。
如果一個元件已經加載進入dom,<code>react-dom</code>子產品的<code>finddomnode</code>方法會傳回該元件所對應的dom節點。
上面代碼中,<code>finddomnode</code>方法傳回<code>app</code>所在的dom節點,然後找出第一個<code>li</code>節點,在它上面模拟使用者點選。最後,判斷<code>classlist</code>屬性裡面的<code>todo-done</code>,是否出現或消失。
第五個測試用例,是添加新的todo項。
上面代碼中,先找到<code>input</code>輸入框,添加一個值。然後,找到<code>add todo</code>按鈕,在它上面模拟使用者點選。最後,判斷新的todo項是否出現在todo清單之中。
<code>finddomnode</code>方法的最大優點,就是支援複雜的css選擇器。這是<code>testutils</code>本身不提供的。
它提供三種測試方法。
<code>shallow</code> <code>render</code> <code>mount</code>
上面代碼中,<code>shallow</code>方法傳回<code>app</code>的淺渲染,然後<code>app.find</code>方法找出<code>h1</code>元素,<code>text</code>方法取出該元素的文本。
關于<code>find</code>方法,有一個注意點,就是它隻支援簡單選擇器,稍微複雜的一點的css選擇器都不支援。
在上面代碼中,你可以看到,<code>render</code>方法與<code>shallow</code>方法的api基本是一緻的。 enzyme的設計就是,讓不同的底層處理引擎,都具有同樣的api(比如<code>find</code>方法)。
上面代碼中,<code>find</code>方法傳回一個對象,包含了所有符合條件的子元件。在它的基礎上,<code>at</code>方法傳回指定位置的子元件,<code>simulate</code>方法就在這個元件上觸發某種行為。
下面是enzyme的一部分api,你可以從中了解它的大概用法。
<code>.get(index)</code>:傳回指定位置的子元件的dom節點 <code>.at(index)</code>:傳回指定位置的子元件 <code>.first()</code>:傳回第一個子元件 <code>.last()</code>:傳回最後一個子元件 <code>.type()</code>:傳回目前元件的類型 <code>.text()</code>:傳回目前元件的文本内容 <code>.html()</code>:傳回目前元件的html代碼形式 <code>.props()</code>:傳回根元件的所有屬性 <code>.prop(key)</code>:傳回根元件的指定屬性 <code>.state([key])</code>:傳回根元件的狀态 <code>.setstate(nextstate)</code>:設定根元件的狀态 <code>.setprops(nextprops)</code>:設定根元件的屬性
(完)