NestJS + @swc/jest を試す
テストを爆速にしたいので @swc/jest
を試したい
esbuild を使わないのは、esbuild がデコレータに対応していないため
リポジトリ
一旦無視して https://github.com/nestjs/typescript-starter をベースに試してみる
https://github.com/swc-project/jest をインストールして jest の transform を書き換える
実行するとエラーになる
$ /Users/odan/source/github.com/odan-sandbox/nestjs-swc-jest-sandbox/node_modules/.bin/jest --config jest.config.swc.js
FAIL src/app.controller.spec.ts
● Test suite failed to run
Cannot find module 'regenerator-runtime' from 'app.controller.spec.ts'
1 | import { Test, TestingModule } from '@nestjs/testing';
> 2 | import { AppController } from './app.controller';
| ^
3 | import { AppService } from './app.service';
4 |
5 | describe('AppController', () => {
at Resolver.resolveModule (../node_modules/jest-resolve/build/resolver.js:324:11)
at Object.<anonymous> (app.controller.spec.ts:2:50)
module.exports = {
moduleFileExtensions: ['js', 'json', 'ts'],
rootDir: 'src',
testRegex: '.*\\.spec\\.ts$',
transform: {
'^.+\\.(t|j)s$': '@swc/jest',
},
collectCoverageFrom: ['**/*.(t|j)s'],
coverageDirectory: '../coverage',
testEnvironment: 'node',
};
https://github.com/swc-project/jest/issues/4#issuecomment-725995836 に従って regenerator-runtime
を入れる
別のエラーになる
$ /Users/odan/source/github.com/odan-sandbox/nestjs-swc-jest-sandbox/node_modules/.bin/jest --config jest.config.swc.js
FAIL src/app.controller.spec.ts
● Test suite failed to run
error: Unexpected token `@`. Expected this, import, async, function, [ for array literal, { for object literal, @ for decorator, function, class, null, true, false, number, bigint, string, regexp, ` for template literal, (, or an identifier
|
4 | @Controller()
| ^
Caused by:
0: failed to process js file
1: Syntax Error
at Compiler.transformSync (../node_modules/@swc/core/index.js:135:25)
デコレータでエラーになっているので、.swcrc
の設定をする
{
"jsc": {
"parser": {
"syntax": "ecmascript",
"jsx": false,
"dynamicImport": false,
"privateMethod": false,
"functionBind": false,
"exportDefaultFrom": false,
"exportNamespaceFrom": false,
"decorators": true,
"decoratorsBeforeExport": false,
"topLevelAwait": false,
"importMeta": false
},
"transform": null,
"target": "es5",
"loose": false,
"externalHelpers": false,
"keepClassNames": false
}
}
// eslint-disable-next-line @typescript-eslint/no-var-requires
const fs = require('fs');
const config = JSON.parse(fs.readFileSync(`${__dirname}/.swcrc`, 'utf-8'));
module.exports = {
moduleFileExtensions: ['js', 'json', 'ts'],
rootDir: 'src',
testRegex: '.*\\.spec\\.ts$',
transform: {
'^.+\\.(t|j)s$': ['@swc/jest', { ...config }],
},
collectCoverageFrom: ['**/*.(t|j)s'],
coverageDirectory: '../coverage',
testEnvironment: 'node',
};
これによって別のエラーが発生するようになった
$ /Users/odan/source/github.com/odan-sandbox/nestjs-swc-jest-sandbox/node_modules/.bin/jest --config jest.config.swc.js
FAIL src/app.controller.spec.ts
● Test suite failed to run
error: Expected a semicolon
|
6 | let app: TestingModule;
| ^
Caused by:
0: failed to process js file
1: error was recoverable, but proceeding would result in wrong codegen
2: Syntax Error
at Compiler.transformSync (../node_modules/@swc/core/index.js:135:25)
エラー的に TS ファイルを JS としてパースしているっぽい...?
yarn add -D @swc/cli
で CLI をインストールしてから、yarn swc src/app.controller.spec.ts --config-file .swcrc
を実行しても同じエラーになるので、@swc/jest
のせいではなさそう
SWC Playground – SWC で TypeScript を選んで、config の json を見たら原因がわかった
parser.syntax
の指定が必要だったらしい。
{
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": false,
"decorators": true
},
"keepClassNames": false
}
}
テストを実行すると、実行時にエラーになる
$ /Users/odan/source/github.com/odan-sandbox/nestjs-swc-jest-sandbox/node_modules/.bin/jest --config jest.config.swc.js
FAIL src/app.controller.spec.ts
AppController
getHello
✕ should return "Hello World!" (1 ms)
● AppController › getHello › should return "Hello World!"
TypeError: Cannot read property 'getHello' of undefined
at AppController.getHello (app.controller.ts:62:40)
at Object.<anonymous> (app.controller.spec.ts:66:34)
デコレータ周りの設定が足りてなかった
{
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": false,
"decorators": true
},
"target": "es2017",
"keepClassNames": true,
"transform": {
"legacyDecorator": true,
"decoratorMetadata": true
}
},
"module": {
"type": "commonjs",
"noInterop": true
}
}
これで、テストが通るようになった
動いたのでベンチマークを取ってみた
js に対して jest を実行するより、jest with swc が速いのは誤差だと思うけど、ほぼパフォーマンスに差がないのはすごい。
time (sec) | |
---|---|
jest | 0.86 |
jest with ts-jest | 3.42 |
jest with swc | 0.79 |
esbuild もいつの間にかデコレータに対応していた