はじめに
TypeScriptでJestを使ってテストをする時、テストの実行速度が遅いことに不満を感じていました。
なんとなくTypeScript→JavaScriptへのビルドに時間がかかっているのだろうなと想像はついていたので、最近は es-build
とかもあるため、テストの実行速度を上げることはできるのではないか?と考えました。
テストの実行速度を上げる方法を調べてみる
ありました。
TypeScript→JavaScriptへのビルドにts-jest
を使うのではなく、 esbuild-jest
を使う方法です。
ですが、 esbuild-jest
はPRの多くがマージされずに開発が途中で停止している様子です。(2022/09 時点)
これは困ったな。。。と、他の方法はないか調べてみると。。。。ありました。
今度は、ts-jest
を使うのではなく、 @swc/jest
を使う方法です。
SWCは、Speedy Web Compilerの略で、Rustで作られた次世代のコンパイラだそうです。
swc-project
があり、その1つに jest
が含まれている感じですね。
SWCは実績もあり、Next.js、Parcel、Deno などのツールや、Vercel、ByteDance、Tencent、Shopify などの企業で使用されているとのこと。
これは期待できる。。。ということで、早速使ってみることにしました。
@swc/jest
をインストール、Configファイルを用意する
とりあえずインストール。
yarn add -dev jest @types/jest @swc/core @swc/jest
jest.config.json
では、向き先を ts-jest
ではなく、 @swc/jest
に。。。
- jest.config.json
{
"transform": {
"^.+\\.(t|j)sx?$": ["@swc/jest"]
},
"testEnvironment": "node"
}
@swc/jest
は、別途 .swcrc
というConfigファイルを作ります。
- .swcrc
{
"$schema": "https://json.schemastore.org/swcrc",
"jsc": {
"parser": {
"syntax": "typescript",
"dynamicImport": false,
"decorators": false
},
"target": "es2022",
"loose": false,
"externalHelpers": false
},
"minify": false
}
各々の設定内容は以下に記載してあります。
.swcrc
を作って、 target
を指定していることから、 tsconfig.json
の内容は見ていないのでしょうね。
tsconfig.json
を見ていないことで、何か大きな問題があるかというと。。。。微妙な気がします。
大抵は困らない気がする。。。
さておき、動かしてみましょう。
テストする
- AWS S3のBucketからファイルを取得するコードのサンプル。
import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
export async function main() {
try {
const s3 = new S3Client({ region: 'ap-northeast-1' });
const obj = await s3.send(
new GetObjectCommand({
Bucket: 'dummyBucket',
Key: 'dummyKey',
})
);
if (
obj.$metadata.httpStatusCode !== undefined &&
obj.$metadata.httpStatusCode >= 400
) {
return 'NG';
}
return 'OK';
} catch (error) {
return error as Error;
}
}
- 上記コードのサンプルのテストコード。
import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
import { mockClient } from 'aws-sdk-client-mock';
import * as fs from 'fs';
import * as path from 'path';
import { main } from './main';
// main.tsのテスト
const s3Mock = mockClient(S3Client);
beforeEach(() => {
s3Mock.reset();
});
describe('S3のオブジェクトを取得できる', () => {
it('成功', async () => {
s3Mock
.on(GetObjectCommand, {
Bucket: 'dummyBucket',
Key: 'dummyKey',
})
.resolves({
$metadata: {
httpStatusCode: 200,
},
Body: fs.createReadStream(
path.resolve(__dirname, './main.test.s3read.txt')
),
});
expect(await main()).toBe('OK');
});
it('失敗', async () => {
s3Mock
.on(GetObjectCommand, {
Bucket: 'dummyBucket',
Key: 'dummyKey',
})
.resolves({
$metadata: {
httpStatusCode: 400,
},
Body: fs.createReadStream(
path.resolve(__dirname, './main.test.s3read.txt')
),
});
expect(await main()).toBe('NG');
});
});
describe('S3のオブジェクトを取得できない', () => {
it('成功', async () => {
const error = new Error('S3のオブジェクトを取得できない');
s3Mock
.on(GetObjectCommand, {
Bucket: 'dummyBucket',
Key: 'dummyKey',
})
.rejects(error);
expect(await main()).toEqual(error);
});
});
- テスト実行結果。
## @swc/jest
$ jest --coverage
PASS src/main.spec.ts
S3のオブジェクトを取得できる
✓ 成功 (31 ms)
✓ 失敗 (3 ms)
S3のオブジェクトを取得できない
✓ 成功 (3 ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
main.ts | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 1.324 s
Ran all test suites.
✨ Done in 2.53s.
## ts-jest
$ jest --coverage
PASS src/main.spec.ts (5.189 s)
S3のオブジェクトを取得できる
✓ 成功 (28 ms)
✓ 失敗 (4 ms)
S3のオブジェクトを取得できない
✓ 成功 (3 ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
main.ts | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 5.498 s
Ran all test suites.
✨ Done in 6.71s.
結果
@swc/jest
は、「2.53s」。 ts-jest
は、「6.71s」という結果になりました。
ts-jest
と比べて、倍以上早くなりましたね。
@swc/jest
を使って困ることがあるかどうか現段階では見えていませんが、まずは使ってみて様子を見てみようと思います。