Open11

NestJS + @swc/jest を試す

odanodan

実行するとエラーになる

$ /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)
jest.config.swc.js
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',
};
odanodan

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)
odanodan

デコレータでエラーになっているので、.swcrc の設定をする

.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
  }
}
jest.config.swc.js
// 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 としてパースしているっぽい...?

odanodan

yarn add -D @swc/cli で CLI をインストールしてから、yarn swc src/app.controller.spec.ts --config-file .swcrc を実行しても同じエラーになるので、@swc/jest のせいではなさそう

odanodan

SWC Playground – SWC で TypeScript を選んで、config の json を見たら原因がわかった

parser.syntax の指定が必要だったらしい。

.swcrc
{
  "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)
odanodan

デコレータ周りの設定が足りてなかった

.swcrc
{
  "jsc": {
    "parser": {
      "syntax": "typescript",
      "tsx": false,
      "decorators": true
    },
    "target": "es2017",
    "keepClassNames": true,
    "transform": {
      "legacyDecorator": true,
      "decoratorMetadata": true
    }
  },
  "module": {
    "type": "commonjs",
    "noInterop": true
  }
}

これで、テストが通るようになった

odanodan

動いたのでベンチマークを取ってみた
js に対して jest を実行するより、jest with swc が速いのは誤差だと思うけど、ほぼパフォーマンスに差がないのはすごい。

time (sec)
jest 0.86
jest with ts-jest 3.42
jest with swc 0.79