はじめに
Jestがテストライブラリとしてはメジャーで多く利用されていると思うが、ES Moduleとの相性でいうとゼロコンフィグとはいかず歯がゆい感じもある。そこで私個人としてはVitestを利用してテストを実行することが多くなってきた。
ただ、jest-openapiという便利な機能は利用したいなと思った。今回はVitestのExtending Matchersの機能を利用してVitesにおいてjest-openapiのマッチャーを利用できるようにするライブラリを作成する事にした。
今回はその実装時に少しハマったことなどを備忘録として残す。
※ちなみに、JestにおけるESMサポートは実験的である
作成したライブラリについて
上記のライブラリ自体はかなり単純で、expect.extend()
を利用してjest-openapiのマッチャーをVitestでも利用可能にしたもの。
以降の章で、実装するあたっていくつかハマったポイントがあったので1つずつ取り上げたいと思う。
ハマったポイント
This expression is not callable.
TypeScriptでライブラリを実装した際に、以下のようなエラーが出てコンパイルエラーになった。
This expression is not callable.
Type 'typeof import("/home/study/workspace/vitest-openapi/node_modules/jest-openapi/dist/matchers/toSatisfyApiSpec")' has no call signatures.ts(2349)
このエラー自体は以前の記事で取り上げた内容と同じで、CommonJSのTypeScriptプロジェクトでdefault exportでモジュールをexportしているものを、ES ModuleのTypeScriptプロジェクトでimportしようとすると起こるエラー。このコンパイルエラーは"esModuleInterop": true
を利用しても解消できない。
詰んだか…と思ったが、冷静になってdefault exportしているライブラリの実装を確認してみると、以下のようにexports.default
になっていることが確認できる。
function default_1(received, openApiSpec) {
...
}
exports.default = default_1;
つまり、default
という名前で関数がexportされているだけなので、以下のように.default()
という実装をすればコンパイルエラーにはならなくなる(若干実装として気持ち悪い感じはするが)。
import jestToSatisfyApiSpec from 'jest-openapi/dist/matchers/toSatisfyApiSpec.js';
...
export default (filepathOrObject: string | OpenAPISpecObject): void => {
const openApiSpec = openapiValidator.makeApiSpec(filepathOrObject);
expect.extend({
toSatisfyApiSpec: (received: unknown) => jestToSatisfyApiSpec.default(received, openApiSpec)
});
};
VitestはCommonJSに対応していない
当初、ドュアルパッケージ(ES ModuleとCommonJSの両方で利用できるパッケージ)を開発しようと考えていたが、VitestはCommonJSには対応していないようなので中止した。理由は、Vitestのindex.cjs
は中身のない空ファイルになっており、const { expect } = require("vitest");
のようなことができない状態だったため。
どうしてこんな事になっているのか?の詳細は不明だが、どうやらTypeScriptに対応させる上での対応でこうなっているらしい。