使用mocha測試TypeScript文件

如何在mocha中測試TypeScript文件

mocha是我比較喜歡的一款的單元測試框架。使用mocha直接測試TypeScript文件,須要結合babel,preset-env,preset-typescript以及babel-register。javascript

// linked-list.ts
export default class LinkedList(){

}
// ./test/linked-list.js
require('@babel/register')({
    presets: [
        ['@babel/preset-env', { modules: 'commonjs'}],
        ['@babel/preset-typescript']
    ],
    extensions: ['.ts']
})

const LinkedList = require('./src/linked-list.ts')

describe('#test', function(){
    it('#1', function(){
        let linkedList = new LinkedList()
        ...
    })
})

須要注意的是java

  • babel-register 會將參數中的配置和bablerc中的配置共同起做用
  • preset-typescript 不使用tsconfig.json中的編譯選項
  • 使用preset-typescript的時候,大多數的編譯選項能夠經過babel來實現

而後在命令行中執行git

mocha ./test/linked-list.js

發現報以下錯誤
LinkedList is not a constructores6

排查以後發現,在測試文件./test/linked-list.js 中github

const LinkedList = require('./src/linked-list.ts')

導入的LinkedList真實爲typescript

{ default: function LinkedList(){}, __esModule: true }

因此我應該在測試文件中加上npm

const LinkedList = require('./src/linked-list.ts').default

才能正確執行。json


可是上面的寫法很麻煩,並且很蠢。很顯然babel將個人ts文件從ES module 轉換爲 commonjs的時候,是將export default 的內容掛載module.exports.default上面,而不是我一開始指望的export default === module.exports = bash

babel v6以後ES module TO commonjs

在babel v6以後,export default 導出的內容再也不使用module.exports = 導出。babel

// es6.js
export default function sum(){}

// commonjs
exports.__module = true
exports['default'] = function sum(){}

exports.__module用來告訴打包工具(基本上這是全部打包工具的事實標準)當前模塊是從ES module 轉換過來的,徹底兼容ES module。因此當使用import 導入這樣一個commonjs模塊的時候,應該使用__importDefault helper來加載

var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
}
exports.__esModule = true;
var bar_1 = __importDefault(require("bar"));

這也是咱們前面必須加上.default的緣由。


可是這樣子很麻煩,並且很蠢。若是咱們還想保持es5 以前的模塊交互邏輯,也就是export default導出的內容使用commonjs module.exports = 默認導出。咱們可使用babel-plugin-add-module-exports

require('@babel/register')({
    presets: [
        ['@babel/preset-env', { modules: 'commonjs'}],
        ['@babel/preset-typescript']
    ],
    plugins: ['add-module-exports'],
    extensions: ['.ts']
})

該插件會在當你的模塊只有export default 默認導出的時候,轉換爲commonjs的默認導出。

// es6.js
export default function sum(){}

// commonjs
exports.__module = true
exports['default'] = function sum(){}
modules.exports = exports['default']

這樣子咱們就不須要加上麻煩的.default了。

是否使用默認導出

對因而否使用默認導出(export default / module.exports = ),好像愈來愈多的人開始持否認態度。就連javascript 的創造者Nicholas C. Zakas也表示不會再使用默認導出了。要知道npm上大多數的包或者模塊都是使用module.exports默認導出的。

那麼默認導出到底有什麼弊端呢?根據尼古拉斯的說法,默認導出最重要的一個弊端是會悄無聲息地轉移到其餘變量,沒法經過搜索代碼的方式來跟蹤。這給代碼閱讀,排查錯誤形成了很大的干擾。導出的最佳實踐應該是**只使用具名導出

舉個例子

// linked-list.js
export default class LinkedList{}

// a.js
import list from './linked-list'

在一開始,咱們知道list就是LinkedList類。可是隨着項目的迭代,咱們可能在多處使用了這個LinkedList類,可是咱們都想a.js同樣改變了這個類名,當咱們想經過LinkedList全局搜索何處引用的時候,咱們就已經沒法獲得正確的結果了。每次閱讀代碼的時候,咱們都須要拉到頭部看下這個list是從何處導入的,導入的是什麼,這會嚴重中斷咱們的開發進程。

PS: export default 也是一種具名導出(named export),只不過這個名字是default.

// a.js
export default function LinkedList(){}

// b.js
import { default } from './a.js'
import LinkedList from './a.js'

// default === LinkedList
相關文章
相關標籤/搜索