隨着在工做學習中更多地接觸、使用測試工具,發現本身在本文中的一些記錄是不許確、不正確的。javascript
今天(九月三日)在家看了 NingJs 的直播,其中有一個分享是關於測試框架的,很是棒,以後有可能的話仍是找來視頻再學習下。css
是的,兩個月前的理解,是很初級很淺陋的。html
繼續學習,繼續鑽研吧。java
前些天接手了一箇舊項目。幸虧不是在原來的基礎上作些修修改改的工做,能夠算是開發新版的。jquery
把前面同事留下來的代碼 down 下來,看了一下。整體仍是挺好的。還有 macha + chai
的測試目錄。git
我也是最近一段時間開始接觸測試。好久以前看了阮大神寫的 mocha 教程,不過也就看看,寫寫簡單的 demo。github
前同事留下的測試,是基於瀏覽器的,主要仍是功能測試。這裏不詳細說怎麼在瀏覽器端使用 mocha 測試了。由於涉及到交互的反饋、追蹤,因此採用的方式是,先用 iframe 加載待測頁面,而後用 contentWindow
的方式拿到 iframe 的環境,再作一些操做。手動觸發一些功能,而後再去判斷相應的變化有沒有發生。npm
本地啓動了一個 server,瀏覽器裏跑了幾遍測試。最後發現的問題是,有一個點擊測試怎麼都過不了。因而又開啓了閱讀代碼的過程。json
最後發現了問題所在,頁面使用的是本身封裝的 tap 事件,整個事件系統也是對原生 Element 原型的拓展。但是怎麼觸發 tap 呢?前同事用了 touchend
。但是並無用啊, tap 事件的觸發但是結合了從 touchstart 開啓一系列事件參數的判斷的。瀏覽器
後來我就想,瀏覽器端功能測試,能不能也拿到命令行上面來呢?
正在此時,我想起了 jsdom
這個大神級做品。
一開始打算用 mocha + jsdom
跑一把。折騰了幾回發現,mocha 這傢伙很差適應異步的工做,這事情很難搞啊。
可能要交代下我作了什麼,嗯,我加載了一個 jquery 腳本,這樣就得外部文件,因而就有異步場景了。試了好多遍,mocha 仍是沒能實現個人指望。(你也能夠拿 mocha 試試看,多試幾回,若是單純靠那個 done
你就能成功,那麼請私信我喲。)
又想一想白天亂逛 github 的時候,在一些個項目中看到了 ava
這個測試工具。搜索一番,聽說正適用於異步場景。
好,那就來試試看唄。前因交代清楚了,下面開始正式進入教程階段。
我將本身的 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'); });
test
的第一個參數是測試用例的名稱,第二個參數是一個函數,該函數會注入 t
對象。咱們全部的斷言都是經過這個注入的 t
進行的。
友情提示:ava 的文檔地址,https://github.com/avajs/ava,也有中文版,可是沒更新同步,因此建議仍是看英文,不然用了一些過期的 API,之後升級以後追悔莫及。
來講上面的代碼。首先咱們使用的是 async & await 語法,整個看起來比回調函數嵌套要整潔許多,整個流程看起來也相對清楚。
第一步是先等待 jQuery 注入成功,拿到 $
。其實這一步無關緊要,我純粹是爲了測試 jsdom API,而且懶得手動寫 dispatch 事件的代碼才這麼幹的。
接下來就開始 DOM 查詢,而後先獲取 div 當前的背景色並打印出來。接着手動觸發 click 事件,而後再次獲取 div 的背景色並打印。最後將觸發點擊先後的兩個顏色值拿來對比。
依葫蘆畫瓢,差很少就這麼搞定了。
打開命令行,進入工做目錄,而後開始測試:
$ ava -v parallel.js
相信我,-v
參數可讓你的命令行界面顯得比較安靜一些。
若是你想要使用 npm test
這樣的命令來測試,請進一步閱讀文檔進行相關配置(將上面的 ava
換成 nom test
是沒用的哦)。這裏主要仍是爲了簡便。
友情提示第二波:會不會懷疑,觸發點擊事件以後,顏色立馬就變了?不存在延遲、異步麼?答案是 yes,真的不存在。假如你和我同樣在這裏猶豫了,那麼說明存在這樣兩種可能性:
js 基礎不夠牢,對相關機制的瞭解還不透徹
你被各類異步玩怕了(hybrid / RN 後遺症 )
當時爲了應對「潛在的異步」(啊我想到了迫害狂想症),我特地作了幾百毫秒的 setTimeout
延時。結果呢,斷言的謂詞(not、same、notSame等等)各類正向、反向都試了一遍,測試永遠經過。什麼鬼?說好的良好的異步支持呢?後來再去看文檔,發現人家寫得清清楚楚:
You must define all tests synchronously. They can't be defined inside setTimeout, setImmediate, etc.
全部測試必須同步定義。不能放在 setTimeout、setImmediate 等方法裏面。
因此,真的,認真讀文檔是頗有必要的。
真正遇到要延時的,怎麼辦?我想,Promise 會解救你的。
ava 聲稱是很高效的。一般狀況下,同一個文件裏測試都是並行的,並不必定按照順序執行。
還以上面的代碼爲例。爲了測試一下,我選擇了投機取巧。不是並行嗎?那我就檢測 jQuery 存不存在就不行了嗎?由於咱們的 test
中,是異步加載 jQuery 的。因此若是測試是並行的,那麼不必定可以檢測到 window.$
的存在。
因此就有了 parallel.js 這個文件。添加的測試用例以下:
test('串行測試', function (t) { console.log(window.$) t.true(!!window.$, '串行失敗'); });
但是,若是我就要串行呢?
還好做者也想到了這種狀況。將全部的 test
改爲 test.serial
便可(見 serial.js)。
須要說明的是,所謂的串行執行,只是在同一個測試文件中存在,同時測試多個文件的時候,就整體而言仍然是並行的。
ava 還有不少的用法和須要注意的地方。最好的辦法仍是看文檔,而後本身寫 demo,反覆領會,並應用在實際業務中。
上面提到的內容,可能有很多錯誤。但願懂行的大神們可以提出來。
忽然想到古人說,「苟日新,又日新,日日新」。
雖然通過今人考證,這也許只是相似甲骨文的祭祀記錄的誤讀。但幾千年來,這種「新」的精神始終在。
程序世界裏,變化更是無時不在。今天的工具,明天也許就會被淘汰。
其實說到底,可以解決需求,可以方便高效使用的,纔是最好的。
向作出這些工具的大神們致敬。
a
標籤的點擊事件用了事件代理,而後經過手動觸發無效。
經測試,在瀏覽器也有這種問題。
解決辦法是直接使用 $('a')[0].click()
,原生的 click
方法比較靠譜。
參考: http://stackoverflow.com/questions/773639/how-can-i-simulate-an-anchor-click-via-jquery