Skip to content

Buns Test-Runner funktioniert gut mit bestehenden Komponenten- und DOM-Testing-Bibliotheken, einschließlich React Testing Library und happy-dom.

happy-dom

Für das Schreiben von Headless-Tests für Ihren Frontend-Code und Komponenten empfehlen wir happy-dom. Happy DOM implementiert einen vollständigen Satz von HTML- und DOM-APIs in reinem JavaScript und ermöglicht es, eine Browserumgebung mit hoher Wiedergabetreue zu simulieren.

Um zu beginnen, installieren Sie das @happy-dom/global-registrator-Paket als dev-Abhängigkeit.

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

Wir verwenden Buns Preload-Funktionalität, um die happy-dom-Globals vor dem Ausführen unserer Tests zu registrieren. Dieser Schritt macht Browser-APIs wie document im globalen Geltungsbereich verfügbar. Erstellen Sie eine Datei namens happydom.ts im Root Ihres Projekts und fügen Sie den folgenden Code hinzu:

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

GlobalRegistrator.register();

Um diese Datei vor bun test zu preladen, öffnen oder erstellen Sie eine bunfig.toml-Datei und fügen Sie die folgenden Zeilen hinzu.

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

Dies führt happydom.ts aus, wenn Sie bun test ausführen. Jetzt können Sie Tests schreiben, die Browser-APIs wie document und window verwenden.

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

test("DOM-Test", () => {
  document.body.innerHTML = `<button>Mein Button</button>`;
  const button = document.querySelector("button");
  expect(button?.innerText).toEqual("Mein Button");
});

TypeScript-Unterstützung

Abhängig von Ihrer tsconfig.json-Einrichtung können Sie einen "Cannot find name 'document'"-Typfehler im obigen Code sehen. Um die Typen für document und andere Browser-APIs zu "injizieren", fügen Sie die folgende Triple-Slash-Direktive oben in jede Testdatei hinzu.

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

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

test("DOM-Test", () => {
  document.body.innerHTML = `<button>Mein Button</button>`;
  const button = document.querySelector("button");
  expect(button?.innerText).toEqual("Mein Button");
});

Lassen Sie uns diesen Test mit bun test ausführen:

bash
bun test
bun test v1.3.3

dom.test.ts:
✓ DOM-Test [0.82ms]

 1 bestanden
 0 fehlgeschlagen
 1 expect()-Aufrufe
1 Test über 1 Datei ausgeführt. 1 insgesamt [125.00ms]

React Testing Library

Bun funktioniert nahtlos mit React Testing Library zum Testen von React-Komponenten. Nach dem Einrichten von happy-dom wie oben gezeigt, können Sie React Testing Library normal installieren und verwenden.

bash
bun add -d @testing-library/react @testing-library/jest-dom
component.test.tsx
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('rendert Button', () => {
  render(<Button>Klick mich</Button>);
  expect(screen.getByRole('button')).toHaveTextContent('Klick mich');
});

Fortgeschrittenes DOM-Testing

Custom Elements

Sie können Custom Elements und Web Components mit demselben Setup testen:

custom-element.test.ts
ts
/// <reference lib="dom" />

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

test("Custom Element", () => {
  // Ein Custom Element definieren
  class MyElement extends HTMLElement {
    constructor() {
      super();
      this.innerHTML = "<p>Inhalt des Custom Elements</p>";
    }
  }

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

  // In Tests verwenden
  document.body.innerHTML = "<my-element></my-element>";
  const element = document.querySelector("my-element");
  expect(element?.innerHTML).toBe("<p>Inhalt des Custom Elements</p>");
});

Event-Testing

Testen Sie DOM-Events und Benutzerinteraktionen:

events.test.ts
ts
/// <reference lib="dom" />

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

test("Button-Klick-Event", () => {
  let geklickt = false;

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

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

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

Konfigurationstipps

Globales Setup

Für komplexere DOM-Testing-Setups können Sie eine umfassendere Preload-Datei erstellen:

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

// happy-dom globals registrieren
GlobalRegistrator.register();

// Fügen Sie hier globale Testkonfiguration hinzu
global.ResizeObserver = class ResizeObserver {
  observe() {}
  unobserve() {}
  disconnect() {}
};

// Andere APIs nach Bedarf mocken
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(),
  })),
});

Aktualisieren Sie dann Ihre bunfig.toml:

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

Fehlerbehebung

Häufige Probleme

TypeScript-Fehler für DOM-APIs: Stellen Sie sicher, dass Sie die /// <reference lib="dom" />-Direktive oben in Ihren Testdateien einfügen.

Fehlende Globals: Stellen Sie sicher, dass @happy-dom/global-registrator korrekt in Ihrer Preload-Datei importiert und registriert ist.

Probleme beim Rendern von React-Komponenten: Stellen Sie sicher, dass Sie sowohl @testing-library/react installiert als auch happy-dom korrekt eingerichtet haben.

Performance-Überlegungen

Happy-dom ist schnell, aber für sehr große Testsuiten möchten Sie vielleicht:

  • beforeEach verwenden, um den DOM-Zustand zwischen Tests zurückzusetzen
  • Vermeiden, zu viele DOM-Elemente in einem einzelnen Test zu erstellen
  • cleanup-Funktionen von Testing-Bibliotheken in Betracht ziehen
test-setup.ts
ts
import { afterEach } from "bun:test";
import { cleanup } from "@testing-library/react";

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

Vue Testing Library

Bun funktioniert auch mit Vue Testing Library:

bash
bun add -d @testing-library/vue @vue/test-utils
vue-component.test.ts
ts
/// <reference lib="dom" />

import { test, expect } from "bun:test";
import { render, screen } from "@testing-library/vue";
import MyComponent from "./MyComponent.vue";

test("rendert Vue-Komponente", () => {
  render(MyComponent, {
    props: {
      title: "Test Titel"
    }
  });
  
  expect(screen.getByText("Test Titel")).toBeInTheDocument();
});

Svelte Testing

Für Svelte-Komponenten können Sie @testing-library/svelte verwenden:

bash
bun add -d @testing-library/svelte
svelte-component.test.ts
ts
/// <reference lib="dom" />

import { test, expect } from "bun:test";
import { render, screen } from "@testing-library/svelte";
import MyComponent from "./MyComponent.svelte";

test("rendert Svelte-Komponente", () => {
  render(MyComponent, {
    props: {
      name: "Test Benutzer"
    }
  });
  
  expect(screen.getByText("Hallo Test Benutzer")).toBeInTheDocument();
});

Best Practices

DOM-Zustand isolieren

Stellen Sie sicher, dass jeder Test mit einem sauberen DOM-Zustand beginnt:

test-setup.ts
ts
import { afterEach } from "bun:test";

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

Asynchrone Updates handhaben

Verwenden Sie waitFor für asynchrone DOM-Updates:

async.test.ts
ts
import { test, expect } from "bun:test";
import { waitFor } from "@testing-library/react";

test("wartet auf DOM-Update", async () => {
  render(<AsyncComponent />);
  
  // Warten, bis der Inhalt geladen ist
  const content = await waitFor(() => screen.getByText("Geladen"));
  expect(content).toBeInTheDocument();
});

Accessibility-Tests

Verwenden Sie Testing Librarys Accessibility-Funktionen:

a11y.test.ts
ts
import { test, expect } from "bun:test";
import { render, screen } from "@testing-library/react";

test("Barrierefreiheit", () => {
  render(<Button aria-label="Menü schließen">X</Button>);
  
  // Nach accessiblem Namen suchen
  expect(screen.getByLabelText("Menü schließen")).toBeInTheDocument();
  
  // Rolle überprüfen
  expect(screen.getByRole("button")).toBeInTheDocument();
});

Bun von www.bunjs.com.cn bearbeitet