はじめに
こんにちは。ニフティ株式会社の添野 隼矢です。
Vitestの Browser Modeが興味深いと聞き、実際に試してみようと思い、
本ブログ記事を書くことにしました。
以下、Vitestの公式ガイドの「Getting Started」に従って、Browser Modeを試していきます。
https://vitest.dev/guide/browser/
今回は、以下の項目でテスト環境を作成します。
- テスト言語:TypeScript
- ブラウザプロバイダ:Playwright
- ブラウザ:Chromium
- フレームワーク:Svelte
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
$ pnpx vitest init browser ◼ This utility will help you set up a browser testing environment. ? Choose a language for your tests › - Use arrow-keys. Return to submit. ❯ TypeScript - Use TypeScript. JavaScript ✔ Choose a language for your tests › TypeScript ? Choose a browser provider. Vitest will use its API to control the testing environment › - Use arrow-keys. Return to submit. ❯ playwright - Playwright relies on Chrome DevTools protocol. Read more: https://playwright.dev webdriverio preview ✔ Choose a browser › chromium ✔ Choose your framework › svelte ✔ Install Playwright browsers (can be done manually via 'pnpm exec playwright install')? … yes ◼ Installing packages... ◼ @vitest/browser, @testing-library/svelte, playwright, @sveltejs/vite-plugin-svelte Packages: +111 -3 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- Progress: resolved 208, reused 164, downloaded 7, added 111, done node_modules/.pnpm/msw@2.4.1/node_modules/msw: Running postinstall script, done in 1.5s devDependencies: + @sveltejs/vite-plugin-svelte 3.1.2 + @testing-library/svelte 5.2.1 + @vitest/browser 2.0.5 + playwright 1.46.1 Done in 5s ✔ Created a config file for browser tests vitest.config.ts ✔ Added "test:browser" script to your package.json. ◼ Installing Playwright dependencies with `pnpx playwright install --with-deps`... Packages: +3 +++ Progress: resolved 3, reused 3, downloaded 0, added 3, done Downloading Chromium 128.0.6613.18 (playwright build v1129) from https://playwright.azureedge.net/builds/chromium/1129/chromium-mac-arm64.zip 138.1 MiB [====================] 100% 0.0s Chromium 128.0.6613.18 (playwright build v1129) downloaded to /Users/Library/Caches/ms-playwright/chromium-1129 Downloading FFMPEG playwright build v1009 from https://playwright.azureedge.net/builds/ffmpeg/1009/ffmpeg-mac-arm64.zip 1 MiB [====================] 100% 0.0s FFMPEG playwright build v1009 downloaded to /Users/Library/Caches/ms-playwright/ffmpeg-1009 Downloading Firefox 128.0 (playwright build v1458) from https://playwright.azureedge.net/builds/firefox/1458/firefox-mac-arm64.zip 79.6 MiB [====================] 100% 0.0s Firefox 128.0 (playwright build v1458) downloaded to /Users/Library/Caches/ms-playwright/firefox-1458 Downloading Webkit 18.0 (playwright build v2051) from https://playwright.azureedge.net/builds/webkit/2051/webkit-mac-13-arm64.zip 68.3 MiB [====================] 100% 0.0s Webkit 18.0 (playwright build v2051) downloaded to /Users/Library/Caches/ms-playwright/webkit-2051 ◼ Add "@vitest/browser/providers/playwright" to your tsconfig.json "compilerOptions.types" field to have better intellisense support. ✔ Created example test file in vitest-example/HelloWorld.test.ts You can safely delete this file once you have written your own tests. ◼ All done! Run your tests with pnpm test:browser |
pnpm run test:browser
を実行すると、@sveltejs/vite-plugin-svelte
パッケージがES module (ESM)であるのに対し、
CommonJSのコンテキストでインポートしようとしているとエラーが出ます。
そのため、package.jsonに以下を追加します。
1 |
"type": "module" |
package.jsonの修正後、再度実行すると新たなエラーが発生します。
表示されたエラーは、Svelteコンポーネント内でTypeScriptを使用しているにも関わらず、
TypeScriptのプリプロセッサが設定されていないというものになります。
そのため、以下の内容のsvelte.config.jsを追加します。
1 2 3 4 5 6 7 8 |
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; const config = { preprocess: vitePreprocess(), }; export default config; |
svelte.config.jsを追加後、再度pnpm run test:browser
を実行したところ、新たなエラーが発生しました。
表示されたエラーは、プロジェクトにSvelteパッケージが導入されていないことを示しています。
そのため、Svelteを追加します。
1 |
$ pnpm add svelte |
再度実行すると、ブラウザが正常に立ち上がり、テストが正常に実行されていることを確認できました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ pnpm run test:browser RERUN x1 ✓ vitest-example/HelloWorld.test.ts (1) ✓ renders name Test Files 1 passed (1) Tests 1 passed (1) Start at 17:20:25 Duration 13ms PASS Waiting for file changes... press h to show help, press q to quit |
次に、Vitestの動作をより深く理解するために、initで自動生成されたコードを以下のように修正してみます。
- 最初は何も表示されていない画面を表示し、1秒後に “Hello Vitest!” というテキストが表示されるような処理に変更
1 2 3 4 5 6 7 |
HelloWorld.svelte <script lang="ts"> export let name: string </script> <h1>Hello {name}!</h1> |
1 2 3 4 5 6 7 8 9 10 11 12 |
HelloWorld.test.ts import { expect, test } from 'vitest' import { render } from '@testing-library/svelte' import HelloWorld from './HelloWorld.svelte' test('renders name', () => { const { getByText } = render(HelloWorld, { props: { name: 'Vitest' }, }) const element = getByText('Hello Vitest!') expect(element).toBeInTheDocument() }) |
修正後のコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
HelloWorld.svelte <script lang="ts"> import { fade } from 'svelte/transition'; export let name: string; let visible = false; setTimeout(() => { visible = true; }, 1000); </script> {#if visible} <h1 transition:fade>Hello {name}!</h1> {/if} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
HelloWorld.test.ts import { expect, test } from 'vitest' import { render } from '@testing-library/svelte' import HelloWorld from './HelloWorld.svelte' test('shows greeting after delay', async () => { const { getByText } = render(HelloWorld, { props: { name: 'Vitest' } }) // 最初はHello Vitest!が表示されていないことを確認 expect(() => getByText('Hello Vitest!')).toThrow() // 遅延後にHello Vitest!が表示されることを確認 await new Promise(resolve => setTimeout(resolve, 1100)) expect(getByText('Hello Vitest!')).toBeVisible() }) |
テストを実行した結果、以下の動作が確認できました。
1. テスト開始直後:画面上に何も表示されない。
2. 1秒経過後:画面に “Hello Vitest!” というテキストが表示される。
上記より、以下の点が確認できました。
1. Vitestが1秒の遅延を正確に処理し、その後の状態変化を適切にテストできていること。
2. 実際のブラウザに近い環境でコンポーネントが正しくレンダリングされ、DOMの更新が適切に行われていること。
3. 意図した動作(最初は何も表示せず、1秒後に特定のテキストを表示する)が正確にテストされ、期待通りの結果が得られること。
この結果から、Vitestの Browser Modeが非同期処理を含むUIコンポーネントのテストに効果的であることが分かりました。
特に、時間に依存する動作や状態変化を伴うコンポーネントのテストにおいて、Vitestが優れた能力を発揮することが確認できました。
VitestのBrowser Modeの機能を試していく過程で、Playwrightでよく使用していたスクリーンショット機能を試してみました。
1 |
await page.screenshot({ path: 'screenshot.png' }) |
しかし、上記をテストコードに追加して実行したところ、page
オブジェクトでエラーが発生しました。
上記のエラーより、Vitestの環境ではPlaywrightのpage
オブジェクトが直接利用可能ではないことが分かりました。
まとめ
VitestのBrowser Modeは、公式には執筆時点ではExperimentalの機能になります。
上記のスクリーンショットの件などもあり、Playwrightの直接的な代わりにはならなさそうですが、単純なコンポーネントテストであれば、Browser Modeも考慮にいれてよいかもしれません。