無駄と文化

実用的ブログ

Vitest を使って wasm のテストを書く

wasm-bindgen で生成したコードに対してテストを書くときの話題です。

Rust からコンパイルした wasm に対してテストを書くとき wasm-bindgen-test がおすすめされがちです。
wasm-bindgen-test は Rust でテストを書き wasm にコンパイルして実行します。ただテストコード自体を wasm にコンパイルする方法だとコンパイル過程に問題があったときにわかりづらそうで少し嫌です。

JavaScript から呼び出す想定の wasm なら JavaScript でテストコードを書くのがわかりやすいと思います。
というわけで Vitest を使って wasm のテストを書いてみましょう。

 

3行まとめ

  • デフォルトでは Vitest は wasm を読み込めない
  • vite-plugin-wasm と vite-plugin-top-level-await を使おう

 

サンプルコード一式を下記のリポジトリに置いています。

github.com

 

ディレクトリ構成

下記のディレクトリ構成を想定します。

. -- pkg/                        // wasm-bindgen で生成したファイル一式
  |  |- index_bg.js
  |  |- index_bg.wasm
  |  |- index_bg.wasm.d.ts
  |  |- index.d.ts
  |  `- index.js
  |- src/
  |  `- lib.rs                   // コンパイル元の Rust コード
  |- target/
  |  `- wasm32-unknown-unknown/
  |     `- debug/
  |        `- PROJECT_NAME.wasm  // cargo build で生成した wasm
  |- tests/
  |  `- index.test.ts            // テストコード
  |- Cargo.toml
  |- package.json
  `- vitest.config.ts

コンパイル元になる Rust コードには簡単な足し算をする関数だけ書いておきました。

// src/lib.rs

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn add(x: i32, y: i32) -> i32 {
    x + y
}

これをコンパイルしたファイル一式が pkg/ ディレクトリに入っています。
なかでも大事なのは JavaScript から import して使うことになる pkg/index.js と、その型情報である pkg/index.d.ts です。

ちなみに型情報を覗いてみると、

// pkg/index.d.ts

export function add(x: number, y: number): number;

となっていて Rust で書いたコードに対応する型情報が生成されているのがわかります。

テストコードは test/index.test.ts に配置することにします。

 

Vitest のセットアップ

npm install -D vitest で Vitest をインストールして、package.json にテスト実行のコマンドを書いておきます。

// package.json

{
  "dependencies": {
    "vitest": "^2.1.4"
  },
  "scripts": {
    "test": "vitest run tests/"
  }
}

これで npm test コマンドでテストが実行されるようになりました。

 

まずは普通にテストを書いてみます。

// tests/index.test.ts

import { test, expect } from "vitest";
import { add } from "../pkg/index";

test("add", () => {
    expect(add(1, 2)).toBe(3);
});

実行してみると、

FAIL tests/index.test.ts [ tests/index.test.ts ]
Error: "ESM integration proposal for Wasm" is not supported currently.

とエラーになります。

エラーの様子

どうやら Vitest はデフォルトでは wasm の読み込みに対応していないようです。

 

vite-plugin-wasm

Vitest で wasm を読み込むために vite-plugin-wasm プラグインを導入します。
あわせて vite-plugin-top-level-await も必要になるので2つをインストールします。

$ npm install -D vite-plugin-wasm vite-plugin-top-level-await

Vitest の設定のために vitest.config.ts をプロジェクトルートに作成します。
中身はこんな感じ、

// vitest.config.ts 

import { defineConfig } from "vite";
import wasm from "vite-plugin-wasm";
import topLevelAwait from "vite-plugin-top-level-await";

export default defineConfig({
    plugins: [wasm(), topLevelAwait()],
});

 

ふたたび npm test コマンドでテスト実行すると、今度は正しくテストが走るようになっています。

テスト実行できた

 

The CJS build of Vite's Node API is deprecated.

ここまででテストは実行できるようになりました。
ですがテスト実行時に The CJS build of Vite's Node API is deprecated. という WARNING が表示されています。(2024年11月現在)

Node は .js ファイルをデフォルトで CommonJS として扱うのでこのような警告が出るんですね。
package.json に "type": "module" を追記することで .js ファイルが ES Modules として扱われるようになります。

// package.json

{
+ "type": "module",
  "dependencies": {
    "vite-plugin-top-level-await": "^1.4.4",
    "vite-plugin-wasm": "^3.3.0",
    "vitest": "^2.1.4"
  },
  "scripts": {
    "test": "vitest run tests/"
  }
}

これにて WARNING がとまります。Yatta!!

 

まとめ

というわけで Vitest で wasm を読み込んでテストするためのセットアップでした。

 

 

私からは以上です。