Vitest Browser Mode を試す
はじめに
Vitest 2.0から に新しい E2E テスト機能として Browser Mode が追加されたので試してみました。
公式ドキュメントを見ても少し詰まった箇所があったので備忘録も兼ねてその導入手順を記事にしました。
Browser Mode は実験的機能ですので、今後の変更があるかもしれません。
本記事は vitest@2.0.5, pnpm, TypeScript, React, Playwight (Chromium)を使ったテストを前提に書いています。最後にVueのテストも記載しています。
インストール
Vitest やその他セットアップが完了している前提で進めます。
@vitest/browser
をインストールします。
pnpm add -D @vitest/browser
Vitest は E2E プロバイダーに依存しないためローカルで動かす場合は依存はこれだけですが、CI の対応も兼ねてここでは playwright
を使います。
pnpm add -D playwright
Vitest では Playwright と WebdriverIO がサポートされています。
コンフィグを設定
vitest.config.ts
に設定を追加します。エイリアスなどの設定も環境に合わせて追加しています。
name
にはブラウザ名を指定します。プロバイダー毎にサポートしているブラウザが異なります。詳細は公式ドキュメントを参照してください。
ここではchromium
を利用します。
import { defineConfig } from "vitest/config";
export default defineConfig({
resolve: {
alias: {
"@": "/src",
},
},
test: {
browser: {
enabled: true,
name: "chromium",
provider: "playwright",
},
},
});
テストを書く
Vitest はレンダリング機能を提供していないため、@testing-library/react
などを使ってレンダリングするため、インストールします。
pnpm add -D @testing-library/react
*.spec.tsx
でテストを書きます。 CSS もテストファイルから読み込むことで、ブラウザテストにも反映されます。クリックなどのインタラクションのために API が用意されています。@vitest/browser/context
からuserEvent
をインポートして利用します。詳細は公式ドキュメントを参照してください。
import "../global.css";
import "@toshusai/cmpui/dist/index.css";
import "@toshusai/cmpui-css/dist/index.css";
import { userEvent } from "@vitest/browser/context";
import { render, screen } from "@testing-library/react";
import { expect, test } from "vitest";
import { AssetView } from "../components/AssetView";
import { state } from "@/state";
test("select an asset", async () => {
render(<AssetView />);
const el = screen.getByText("Honk");
await userEvent.click(el);
expect(Object.keys(state.selectedAssetIds).length).toBe(1);
expect(el).toHaveAttribute("aria-selected", "true");
});
toHaveAttribute
はjest-dom
のアサーション APIです。型を追加するために、typesRoots
に./node_modules
を追加し、types
に@vitest/browser/providers/playwright
を追加します。
こちらもプロバイダー毎に若干異なるようで、詳しくは公式ドキュメントを参照してください。
{
"compilerOptions": {
"typeRoots": ["./node_modules"],
"types": ["@vitest/browser/providers/playwright"]
}
}
テストを実行
vitestを実行すると、ブラウザや Chromium が起動してテストが実行されます。
{
"scripts": {
"test": "vitest"
}
}
ブラウザテスト以外のテストに関してもダッシュボード形式で表示されるため、ブラウザテスト以外の目的でも利用できそうです。
ドラッグのテスト
ドラッグ&ドロップではなく、pointerdown
を用いるドラッグについてはイベントが提供されていなかったため、自分で以下のように実装しました。あまり綺麗ではありませんが、これで一応は動作しているように見えます。
test("drag", async () => {
const pointerId = 1;
el?.dispatchEvent(
new PointerEvent("pointerdown", { bubbles: true, pointerId: pointerId })
);
for (let i = 1; i <= 30; i++) {
el?.dispatchEvent(
new PointerEvent("pointermove", { bubbles: true, clientX: i, pointerId })
);
}
el?.dispatchEvent(
new PointerEvent("pointerup", { bubbles: true, pointerId })
);
});
Vue での利用
Vue でも利用してみました。vitest.config.ts
に Vue プラグインを追加してください。
概ね React と同じですが、SFC での利用ではなく、defineComponent
を利用してテストコンポーネントを作成しました。
レンダリングが絡む部分はnextTick
などを利用するとテストが書きやすそうです。
import { render, screen } from "@testing-library/vue";
import { test, expect } from "vitest";
import CSelect from "./CSelect.vue";
import { defineComponent, h, nextTick, ref } from "vue";
import "@toshusai/cmpui-css/dist/index.css";
const waitNextTick = () => new Promise<void>((resolve) => nextTick(resolve));
test("select an item", async () => {
render(
defineComponent({
setup() {
const value = ref("bravo");
return () =>
h(CSelect, {
options: [
{ label: "Alfa", value: "alfa" },
{ label: "Bravo", value: "bravo" },
],
value: value.value,
onChange: (v: string) => {
value.value = v;
},
});
},
}),
);
const selectButtonElement = screen.getByText("Bravo");
const pointerId = 1;
selectButtonElement?.dispatchEvent(
new PointerEvent("pointerdown", { bubbles: true, pointerId: pointerId }),
);
for (let i = 1; i <= 16; i++) {
selectButtonElement?.dispatchEvent(
new PointerEvent("pointermove", {
bubbles: true,
movementY: 1,
clientY: i,
pointerId,
}),
);
}
await waitNextTick();
const targetItemElement = screen.getByText("Alfa");
targetItemElement?.dispatchEvent(
new PointerEvent("pointerup", { bubbles: true, pointerId }),
);
await waitNextTick();
expect(selectButtonElement.innerText).toBe("Alfa");
});
おわりに
Vitest Browser Mode は Vitest の延長で利用することができ、設定が少ないので簡単に利用できました。
複雑なGUIアプリケーションではマウスやキーボード操作をテストし、アプリやライブラリの品質を保ちたいため、このようなテストが簡単に行えるようになるのは非常に嬉しく思います。
まだ実験的な機能ですが導入も簡単で気に入りました。今後の発展が楽しみです。
今回は、趣味で作っているUIコンポーネントライブラリと動画編集ソフトのテストとして導入してみました。絶賛開発中ではありますが、もし興味がありましたら以下のリポジトリもご覧いただけたら幸いです。
追記
- [2024/09/08]: Vitest CLIのオプションは不要だっため、テストの実行に関する記載を修正しました。
Discussion