Skip to content

Bun のテストランナーは、React Testing Library や happy-dom を含む、既存のコンポーネントおよび DOM テストライブラリと適切に動作します。

happy-dom

フロントエンドコードとコンポーネントのヘッドレステストを書くために、happy-dom を推奨します。Happy DOM は、ブラウザ環境を高精度でシミュレートできるように、プレーンな JavaScript で HTML および DOM API の完全なセットを実装しています。

開始するには、@happy-dom/global-registrator パッケージを dev 依存関係としてインストールします。

bash
bun add -d @happy-dom/global-registrator

テストを実行する前に happy-dom グローバルを登録するために、Bun のプリロード機能を使用します。このステップにより、document などのブラウザ API がグローバルスコープで利用可能になります。プロジェクトのルートに happydom.ts というファイルを作成し、次のコードを追加します。

ts
import { GlobalRegistrator } from "@happy-dom/global-registrator";

GlobalRegistrator.register();

bun test を実行する前にこのファイルをプリロードするには、bunfig.toml ファイルを開くか作成して、次の行を追加します。

toml
[test]
preload = ["./happydom.ts"]

これにより、bun test を実行するときに happydom.ts が実行されます。これで、documentwindow などのブラウザ API を使用するテストを記述できます。

ts
import { test, expect } from "bun:test";

test("dom テスト", () => {
  document.body.innerHTML = `<button>My button</button>`;
  const button = document.querySelector("button");
  expect(button?.innerText).toEqual("My button");
});

TypeScript サポート

tsconfig.json の設定によっては、上記のコードで "Cannot find name 'document'" という型エラーが表示される可能性があります。document や他のブラウザ API の型を「注入」するには、テストファイルの先頭に次のトリプルスラッシュディレクティブを追加します。

ts
/// <reference lib="dom" />

import { test, expect } from "bun:test";

test("dom テスト", () => {
  document.body.innerHTML = `<button>My button</button>`;
  const button = document.querySelector("button");
  expect(button?.innerText).toEqual("My button");
});

bun test でこのテストを実行してみましょう。

bash
bun test
bun test v1.3.3

dom.test.ts:
✓ dom test [0.82ms]

 1 pass
 0 fail
 1 expect() calls
Ran 1 tests across 1 files. 1 total [125.00ms]

React Testing Library

Bun は React コンポーネントのテストに React Testing Library とシームレスに連携します。上記のように happy-dom をセットアップした後、React Testing Library を通常どおりインストールして使用できます。

bash
bun add -d @testing-library/react @testing-library/jest-dom
ts
/// <reference lib="dom" />

import { test, expect } from 'bun:test';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';

function Button({ children }: { children: React.ReactNode }) {
  return <button>{children}</button>;
}

test('ボタンをレンダリング', () => {
  render(<Button>Click me</Button>);
  expect(screen.getByRole('button')).toHaveTextContent('Click me');
});

高度な DOM テスト

カスタム要素

同じセットアップを使用して、カスタム要素と Web コンポーネントをテストできます。

ts
/// <reference lib="dom" />

import { test, expect } from "bun:test";

test("カスタム要素", () => {
  // カスタム要素を定義
  class MyElement extends HTMLElement {
    constructor() {
      super();
      this.innerHTML = "<p>カスタム要素のコンテンツ</p>";
    }
  }

  customElements.define("my-element", MyElement);

  // テストで使用
  document.body.innerHTML = "<my-element></my-element>";
  const element = document.querySelector("my-element");
  expect(element?.innerHTML).toBe("<p>カスタム要素のコンテンツ</p>");
});

イベントテスト

DOM イベントとユーザーインタラクションをテストします。

ts
/// <reference lib="dom" />

import { test, expect } from "bun:test";

test("ボタンクリックイベント", () => {
  let clicked = false;

  document.body.innerHTML = '<button id="test-btn">Click me</button>';
  const button = document.getElementById("test-btn");

  button?.addEventListener("click", () => {
    clicked = true;
  });

  button?.click();
  expect(clicked).toBe(true);
});

設定のヒント

グローバルセットアップ

より複雑な DOM テストセットアップのために、より包括的なプリロードファイルを作成できます。

ts
import { GlobalRegistrator } from "@happy-dom/global-registrator";
import "@testing-library/jest-dom";

// happy-dom グローバルを登録
GlobalRegistrator.register();

// ここにグローバルテスト設定を追加
global.ResizeObserver = class ResizeObserver {
  observe() {}
  unobserve() {}
  disconnect() {}
};

// 必要に応じて他の API をモック
Object.defineProperty(window, "matchMedia", {
  writable: true,
  value: jest.fn().mockImplementation(query => ({
    matches: false,
    media: query,
    onchange: null,
    addListener: jest.fn(),
    removeListener: jest.fn(),
    addEventListener: jest.fn(),
    removeEventListener: jest.fn(),
    dispatchEvent: jest.fn(),
  })),
});

そして bunfig.toml を更新します。

toml
[test]
preload = ["./test-setup.ts"]

トラブルシューティング

一般的な問題

DOM API の TypeScript エラー: テストファイルの先頭に /// <reference lib="dom" /> ディレクティブを含めることを確認してください。

グローバルの欠落: @happy-dom/global-registrator がプリロードファイルで正しくインポートおよび登録されていることを確認してください。

React コンポーネントのレンダリング問題: @testing-library/react をインストールし、happy-dom が正しくセットアップされていることを確認してください。

パフォーマンスの考慮事項

happy-dom は高速ですが、非常に大規模なテストスイートでは、以下を検討してください。

  • テスト間で DOM 状態をリセットするために beforeEach を使用する
  • 単一のテストで多数の DOM 要素を作成しない
  • テストライブラリの cleanup 関数の使用を検討する
ts
import { afterEach } from "bun:test";
import { cleanup } from "@testing-library/react";

afterEach(() => {
  cleanup();
  document.body.innerHTML = "";
});

Bun by www.bunjs.com.cn 編集