Typescript and Jest

最近在折腾 typescript,把很多项目改成了 ts 的。有一个老项目,改的过程中感觉各种不踏实,打算还是先写点测试用例,就折腾了一下 jest。各种坑。。。

首先需要加一个 tsconfig.json

{
  "compilerOptions": {
    "target": "es2015",
    "module": "es2015",
    "lib": [
      "es2015"
    ],
    "outDir": "./lib",
    "declaration": true,

    "noEmit": true,
    "moduleResolution": "node",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,

    /* Strict Type-checking */
    "strict": true,
    "strictNullChecks": true,
    "noImplicitAny": true,
    "noImplicitThis": true,
    "alwaysStrict": true,

    /* Additional Checks */
    "noUnusedLocals": true,                /* Report errors on unused locals. */
    "noUnusedParameters": true,            /* Report errors on unused parameters. */
    "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. */
    "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. */
  },
  "include": [
     "*.ts"
  ],
  "exclude": [
    "node_modules",
    "__tests__"
  ]
}

然后安装一个 typescript 就可以通过 yarn tsc 命令编译了,生成的 js 在 lib 下面。

测试如果是用 js 写,那么直接装 jest 就可以了。但是我们既然项目都改成 ts 了,那么还是希望用 ts 写。那就需要用到 ts-jest 。这货的配置可以写到 package.json 里面。

{
 "name": 'test-projct',
 "version": "0.0.1",
 ........
 "jest": {
    "preset": "ts-jest",
    "testEnvironment": "node",
    "testMatch": [ "**/__tests__/*-test.ts" ],
    "globals": {
      "ts-jest": {
        "babelConfig": true,
        "isolatedModules": true
      }
    }
  }
}

isolatedModules 表示说测试的时候先不做 type 检查。我这情况是,要改那些文件比较大一时都弄不好,可能 type 只改了部分,但是这个时候改到某个方法的时候,需要先加测试,以免改前改后不一致,所以这个时候只能忽略掉 type 检查了。

这样配置之后,就可以用 ts 写 test 了。test 文件放到 __tests__ 目录里面,用 *-test.ts 命名。这样这目录也可以放一些非测试用文件了,比如测试用例用到的一些 mock 文件之类。

这样看着一切美好。直到我遇到了一个问题,我的那些需要测试的方法,有些是私有的,又不想因为这个改成 public 的,那么是不是有办法可以测试?这样就找到了 rewire ,这个可以把你的模块的内容随意替换组合,方便你做 mock。我要做的也覆盖了。这样完美了。

但是发现,rewire 不支持 typescript。在 ts 文件里面 rewire 一个模块之后,并没有多出来那些 __get____set__ 方法。没仔细去研究代码,找到了 babel-plugin-rewire ,给 package.json 增加配置如下。

  "babel": {
    "presets": [
      "env"
    ],
    "env": {
      "test": {
        "plugins": [
          "babel-plugin-rewire"
        ]
      }
    }
  }

发现还是不行,并没有什么效果。查了之后发现,是因为 ts-test 根本不会去调用 babel 的缘故,所以上面的那个 babelConfig 就是这个用途,让 ts-test 去使用 babel。

目前还有一个问题是怎么让这个 package 在别人安装使用的时候自动编译为 js,这样让 js 用户也可以用。尝试过在 package.json 里面增加 build 发现不行。

 "scripts": {
    "build": "tsc",
    "postinstall": "[ -f ../../node_modules/.bin/tsc ] && ../../node_modules/.bin/tsc || echo 'no typescript found, skip build'",
    "test": "jest"
  },

安装这个模块之后在 ./node_modules/test-module/ 下面执行 tsc 并不会产出 lib 目录的编译文件。