使用mocha测试TypeScript文件

空空道人
• 阅读 4914

如何在mocha中测试TypeScript文件

mocha是我比较喜欢的一款的单元测试框架。使用mocha直接测试TypeScript文件,需要结合babel,preset-env,preset-typescript以及babel-register。

// 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()
        ...
    })
})

需要注意的是

  • babel-register 会将参数中的配置和bablerc中的配置共同起作用
  • preset-typescript 不使用tsconfig.json中的编译选项
  • 使用preset-typescript的时候,大多数的编译选项可以通过babel来实现

然后在命令行中执行

mocha ./test/linked-list.js

发现报如下错误
LinkedList is not a constructor

排查之后发现,在测试文件./test/linked-list.js 中

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

导入的LinkedList真实为

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

所以我应该在测试文件中加上

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

才能正确执行。


但是上面的写法很麻烦,而且很蠢。很显然babel将我的ts文件从ES module 转换为 commonjs的时候,是将export default 的内容挂载module.exports.default上面,而不是我一开始期望的export default === module.exports =

babel v6之后ES module TO commonjs

在babel v6之后,export default 导出的内容不再使用module.exports = 导出。

// 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 
点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Jetbrains Idea 内 CoffeeScript 的 mocha 单元测试的配置
都9012年了,idea怎能还不更新呢~换上了idea2018版本,果然舒服很多,因为本人的jsnode项目都是用coffee写的,但是在跑单元测试的时候遇到了一点问题idea下的mocha单元测试配置方式在这里记录一下首先得要安装号mocha的idea插件打开idea顶部工具栏"RUN""EditConfigurations
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这