搭建現代的 Karma 測試環境

也能夠在這裏看:https://leozdgao.me/modern-karma/前端

以前寫過的測試都是針對簡單的工具方法,用的 mocha + chai 寫,最近在研究前端路由,想寫寫測試代碼,遇到 window.location,忽然意識到先後端的差別問題,須要一個瀏覽器環境,因而想到以前用過的 Karma + phamtonjs 環境,搭的過程當中遇到一些坑,由於涉及到了 Babel 和 commonjs 模塊系統,因而這裏記錄分享下。node

開始搭環境

因爲 Karma 只是一個 Test Runner,我們的測試框架和斷言庫仍是須要的,因而先裝這些東西:webpack

> npm install --save-dev karma karma-mocha karma-chai

對於 npm 版本 >=3.0 的話,這幾個 peerDependencies:web

> npm install --save-dev mocha chai

這些裝完後,利用 karma-cli 來初始化一份配置文件:shell

> ./node_modules/.bin/karma init

按照提示填寫配置便可,完成後生成一份 karma.config.js,把裏面 singleRun 設成 false,結束。npm

接下來給 Karma 準備 Browsers 了,我這裏選擇 PhantomJS(在上面初始化 Karma 配置的時候就能夠選了),不過這東西的安裝過程是真的糾結:後端

> npm install --save-dev karma-phantomjs-launcher phantomjs-prebuilt

在安裝的過程當中,發現 PhantomJS 須要從 https://bitbucket.org/ariya/phantomjs/downloads/ 下載,速度很是慢,反正我是沒有成功下載下來過。好在有淘寶鏡像,哈哈,太棒了!cnode 帖子的連接在這裏瀏覽器

> PHANTOMJS_CDNURL=https://npm.taobao.org/dist/phantomjs npm install phantomjs-prebuilt --registry=https://registry.npm.taobao.org --no-proxy

而後貼出一部分配置:babel

module.exports = function (config) {
  config.set({
    basePath: './',
    frameworks: [ 'mocha', 'chai' ],
    files: [
      'src/**/*.js',
      'test/**/*.js'
    ],
    plugins: [
      'karma-mocha',
      'karma-chai',
      'karma-mocha-reporter',
      'karma-phantomjs-launcher'
    ],
    reporters: [ 'mocha' ],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: false,
    browsers: [ 'PhantomJS' ],
    singleRun: true,
    concurrency: Infinity
  })
}

這些順利安裝完後,而且你的配置文件正確配置的狀況下,理應是能夠跑了,然而我如今的工做流已經深度依賴於 Babel + commonjs 模塊系統,因此若是你和我同樣的話,那麼咱們的環境還沒搭好。框架

Babel 加入

這邊我用的 Babel 版本是 v6.0+,根據 Babel 官網 說的:

> npm install --save-dev karma-babel-preprocessor

並在配置裏添加預處理配置:

plugins: [
  ...
  'karma-babel-preprocessor',
  ...
],
preprocessors: {
  "src/**/*.js": [ "babel" ],
  "test/**/*.js": [ "babel" ]
},

然而即使是這樣也仍是不行,考慮到 Babel 是將 ES6 的模塊系統轉換爲 commonjs 的模塊系統,而 Karma 是直接把匹配到的腳本放在瀏覽器環境裏跑的,瀏覽器環境裏確定沒有 requiremodule.exports 這種東西,因此在看了幾個例子以後,發現還須要 karma-commonjs 這個東西。

> npm install --save-dev karma-commonjs

完整的配置文件以下:

module.exports = function(config) {
  config.set({
    basePath: './',
    frameworks: [ 'mocha', 'chai', 'commonjs' ],
    files: [
      'src/**/*.js',
      'test/**/*.js'
    ],
    exclude: [
    ],
    preprocessors: {
      'src/**/*.js': [ 'babel', 'commonjs' ],
      'test/**/*.js': [ 'babel', 'commonjs' ]
    },
    plugins: [
      'karma-mocha',
      'karma-chai',
      'karma-mocha-reporter',
      'karma-commonjs',
      'karma-babel-preprocessor',
      'karma-phantomjs-launcher'
    ],
    reporters: [ 'mocha' ],
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: false,
    browsers: [ 'PhantomJS' ],
    singleRun: true,
    concurrency: Infinity
  })
}

好了,如今只須要在 npm scripts 里加上一條:

scripts: {
  test: 'karma start'
}

Webpack 加入

上面的 karma-commonjs 有個問題,它只能加載配置裏 files 選項匹配的模塊,這一點很不方便,因而想到 webpack 是否能夠和 karma 協同工做,果真是有的,因而找我最終使用了這個方式。

> npm install --save-dev karma-webpack

karma-webpack 提供了兩種方式加載測試文件,配置以下:

files: [
  'test/*_test.js',
  'test/**/*_test.js'
],
preprocessors: {
  'test/*_test.js': ['webpack'],
  'test/**/*_test.js': ['webpack']
},
webpack: {
  module: {
    loaders: [
      { test: /\.js$/, exclude: /node_modules/, loader: 'babel' }
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('test')
    })
  ]
}

此時,被加入 files 配置匹配的文件都被認爲是入口點(entry),並加上 webpack 的預處理配置便可(有了 webpack 結合 commonjs 的模塊系統,就不須要手動加入項目源碼了,僅引入測試代碼就行)。不過下面這種方式更加簡單,只須要一個文件:

// tests.webpack.js
// require all modules ending in ".spec.js" from the
// current directory and all subdirectories
var testsContext = require.context("./test", true, /\.spec\.js$/)
testsContext.keys().forEach(testsContext)

本質上就是把全部匹配到的文件都 require 一遍,好比我上面就把全部 test 文件夾下的 .spec.js 結尾的文件都跑了一遍,Karma 的配置也稍微精簡了點。

files: [
  'tests.webpack.js'
],
preprocessors: {
  'tests.webpack.js': [ 'webpack' ]
},
webpack: {
  module: {
    loaders: [
      { test: /\.js$/, exclude: /node_modules/, loader: 'babel' }
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('test')
    })
  ]
}

項目若是比較大,代碼量較多的時候,webpack 打包會比較慢(對於打開 watch 選項的同窗,可能會比較崩潰),你們本身取捨吧。

最後

大功告成,這裏推薦你們寫個 yo generator 來減小重複工做,以前寫過 一篇文章 來介紹。

好了,結束,水文一篇,不過仍是但願對你們有幫助。 :)

相關文章
相關標籤/搜索