簡單的 JavaScript 自動單元測試

前幾天弄完 JSLint.vim 後,就對 server side JavaScript 產生了一些興趣,還抓了 v8 引擎 來用,於是就想到之前想弄很久的自動單元測試,想說要跑 QUnit ,不過 QUnit 雖然獨立於 jQuery 了,但還是要在瀏覽器環境下才能執行,純 JavaScript engine 還少了 DOM BOM,就是說它需要 document, window 這些物件,找了一下發現 John Resig 有弄 env.js 這個專案,就是要在 js shell 裡面做出瀏覽器的環境,不過問題是目前只能跑在 Rhino 下,因為他是 java based ,可以在 JavaScript 裡面寫 Java ,所以可以做很多壞事,但是其他的 js shell 沒辦法這樣跑, John Resig 好像有想要 port 成 python + v8 的版本,不過不知道有沒有成功,因為也 沒放出

剛好最近有點紅的 node.js ,似乎可以拿來做一樣的事情(要做 http request、開檔案、DOM),於是也調查了一下,結果缺少了重要的 DOM ,這樣也跑不起 Qunit,傷心難過之餘只好把方向改成尋找簡單的 JavaScript Unit Test Framework,希望能找到不會存取到 BOM DOM 的版本,結果找到 這個 ,雖然沒完全符合需求,不過裡面要改的地方很少,所以改了一下就拿來用了(還不知道授權所以不敢丟出來),把幾個要用到 jQuery, DOM 的地方註解掉,還有 log 改成有錯誤才輸出,然後 ~/.vimrc 加上:

function Jsunit ()
    let ut = 'unit.test.js'
    let fn = expand('<afile>:t')
    if fn != ut
        let cwd = expand('<afile>:p:h')
        if filereadable(cwd.'/unit.test.js')
            let has_error = 0
            let cmd = 'js '. ut
            let output = system(cmd)
            for error in split(output, "\n")
                let has_error = 1
                caddexpr expand("%") . fn . ":0:0:" . error
            endfor
            if has_error == 1
                copen
            else
                echo 'Unit  : All OK.'
            endif
        endif
    endif
endfunction

autocmd FileWritePost,BufWritePost *.js :call Jsunit()

存檔的時候會自動找 unit.test.js ,如果存在的話就會執行它,unit.test.js 裡面長得像這樣:

load('testrunner.js');
load('lib.js');

test('all', function () {
    ok(libFunc(true) == 530, 'send true');
    isObj(libFunc(false), {a:'1'}, 'send false');
});

不過這個 testrunner 不能做任何和 html 文件、瀏覽器有關的測試,只能做很核心部份的測試。