Zum Inhalt springen
Kontakt

Sebastian Nawrot
Dorneystr. 45
44149 Dortmund

Webentwicklung & Technik

React Testing Tutorial: Komponenten richtig testen mit Jest, Vitest und Co.

Lerne React Testing mit praktischen Beispielen. Jest, Mocha, Jasmine und Vitest im Vergleich - mit React Testing Library und unserer Todo-App.

Sebastian Nawrot
14 Min. Lesezeit
#React#Testing#Jest#Vitest#React Testing Library#JavaScript#Tutorial
React Testing Tutorial: Komponenten richtig testen mit Jest, Vitest und Co.

Code ohne Tests ist wie ein Auto ohne Bremsen - es funktioniert, bis es das nicht mehr tut. In diesem umfassenden Tutorial zeige ich dir, wie du React-Komponenten professionell testest. Wir verwenden dabei unsere Todo-App aus der Tutorial-Serie als praktisches Beispiel.

Du lernst die wichtigsten Testing-Frameworks kennen: Jest, Mocha + Chai, Jasmine und Vitest. Alle Beispiele nutzen die React Testing Library - den modernen Standard für komponentenbasiertes Testing.

Warum Testen wichtig ist

Tests sind kein Nice-to-have, sondern essentiell für professionelle Softwareentwicklung:

  • Vertrauen bei Änderungen - Refactoring ohne Angst
  • Dokumentation - Tests zeigen, wie Komponenten funktionieren sollen
  • Bug-Prävention - Fehler früh erkennen, bevor sie in Produktion landen
  • Besseres Design - Testbarer Code ist oft auch besserer Code

Laut State of JS 2024 nutzen über 85% der professionellen React-Entwickler Testing-Tools. Es ist Zeit, dass du auch dazugehörst.

Arten von Tests

Bevor wir in die Frameworks eintauchen, ein kurzer Überblick über die Test-Typen:

Unit Tests

Testen einzelne Funktionen oder Komponenten isoliert. Schnell, fokussiert, viele davon.

// Beispiel: Eine Hilfsfunktion testen
function formatDate(date) {
  return date.toLocaleDateString('de-DE');
}

test('formatiert Datum korrekt', () => {
  const date = new Date('2026-02-21');
  expect(formatDate(date)).toBe('21.2.2026');
});

Integration Tests

Testen das Zusammenspiel mehrerer Komponenten. Wie verhält sich ein Formular mit seinen Eingabefeldern und Buttons zusammen?

End-to-End Tests (E2E)

Testen die komplette Anwendung aus Nutzersicht. Tools wie Cypress oder Playwright simulieren echte Browser-Interaktionen.

In diesem Artikel fokussieren wir uns auf Unit- und Integration-Tests - die Basis jeder guten Test-Suite.

Testing-Frameworks im Überblick

Hier ein Vergleich der wichtigsten JavaScript-Testing-Frameworks:

FeatureJestMochaJasmineVitest
TypAll-in-OneTest RunnerAll-in-OneAll-in-One
AssertionsEingebautBenötigt ChaiEingebautEingebaut
MockingEingebautBenötigt SinonEingebautEingebaut
SetupMinimalMehr KonfigurationModeratMinimal (mit Vite)
Snapshot TestsJaPlugin nötigPlugin nötigJa
PerformanceGutGutGutSehr schnell
Beste fürReactNode.js, FlexibilitätAngularVite-Projekte

Wann welches Framework?

  • Jest: Standard für React-Projekte, größtes Ecosystem
  • Mocha + Chai: Wenn du maximale Flexibilität brauchst
  • Jasmine: Häufig in Angular-Projekten, funktioniert aber auch mit React
  • Vitest: Perfekt für Vite-basierte Projekte, sehr schnell

Hinweis zu Karma: Karma war früher ein beliebter Test-Runner für Browser-Tests. Es wurde 2023 offiziell deprecated. Für neue Projekte empfehlen wir Vitest oder Jest als Alternative.

React Testing Library - Der moderne Standard

Die React Testing Library (RTL) hat das Testen von React-Komponenten revolutioniert. Ihr Motto:

"The more your tests resemble the way your software is used, the more confidence they can give you."

Philosophie: User-zentriertes Testing

RTL ermutigt dich, Komponenten so zu testen, wie ein Nutzer sie verwendet - nicht wie sie intern implementiert sind.

Schlecht (Implementation-Details testen):

// Testet interne State-Variable - fragil!
expect(component.state.isOpen).toBe(true);

Gut (Nutzer-Perspektive):

// Testet was der Nutzer sieht
expect(screen.getByText('Menü ist geöffnet')).toBeInTheDocument();

Die wichtigsten Queries

RTL bietet verschiedene Query-Methoden:

QueryFindet Element?Wirft Fehler?Async?
getBy*JaJa, wenn nicht gefundenNein
queryBy*OptionalNein, gibt null zurückNein
findBy*JaJa, nach TimeoutJa

Die häufigsten Selektoren:

// Nach Text
screen.getByText('Speichern');

// Nach Rolle (barrierefrei!)
screen.getByRole('button', { name: 'Speichern' });

// Nach Label
screen.getByLabelText('E-Mail-Adresse');

// Nach Placeholder
screen.getByPlaceholderText('Suche...');

// Nach Test-ID (letzter Ausweg)
screen.getByTestId('submit-button');

userEvent für Interaktionen

Für realistische Nutzer-Interaktionen verwenden wir @testing-library/user-event:

import userEvent from '@testing-library/user-event';

// Klicken
await userEvent.click(button);

// Tippen
await userEvent.type(input, 'Hallo Welt');

// Auswählen
await userEvent.selectOptions(select, 'option1');

Jest + React Testing Library (Empfohlen)

Jest ist das Standard-Framework für React-Testing. Es bietet alles out-of-the-box: Assertions, Mocking, Snapshot-Tests und mehr.

Setup mit Vite

Installiere die benötigten Pakete:

npm install -D jest @testing-library/react @testing-library/jest-dom @testing-library/user-event jest-environment-jsdom @babel/preset-env @babel/preset-react identity-obj-proxy

Erstelle jest.config.js:

export default {
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['<rootDir>/src/setupTests.js'],
  moduleNameMapper: {
    '\\.(css|less|scss|sass)$': 'identity-obj-proxy',
  },
  transform: {
    '^.+\\.(js|jsx)$': 'babel-jest',
  },
};

Erstelle babel.config.js:

export default {
  presets: [
    ['@babel/preset-env', { targets: { node: 'current' } }],
    ['@babel/preset-react', { runtime: 'automatic' }],
  ],
};

Erstelle src/setupTests.js:

import '@testing-library/jest-dom';

Füge das Test-Script in package.json hinzu:

{
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage"
  }
}

TodoItem testen

Erinnern wir uns an unsere TodoItem-Komponente aus der Todo-App Serie:

function TodoItem({ todo, onToggle, onDelete }) {
  return (
    <li className={`todo-item ${todo.completed ? 'completed' : ''}`}>
      <input
        type="checkbox"
        checked={todo.completed}
        onChange={() => onToggle(todo.id)}
      />
      <span className="todo-title">{todo.title}</span>
      <button
        className="delete-btn"
        onClick={() => onDelete(todo.id)}
        aria-label="Todo löschen"
      >
        ×
      </button>
    </li>
  );
}

Jetzt die Tests in TodoItem.test.jsx:

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import TodoItem from './TodoItem';

describe('TodoItem', () => {
  const mockTodo = { id: 1, title: 'React lernen', completed: false };
  const mockOnToggle = jest.fn();
  const mockOnDelete = jest.fn();

  beforeEach(() => {
    jest.clearAllMocks();
  });

  test('rendert den Todo-Titel', () => {
    render(
      <TodoItem
        todo={mockTodo}
        onToggle={mockOnToggle}
        onDelete={mockOnDelete}
      />
    );

    expect(screen.getByText('React lernen')).toBeInTheDocument();
  });

  test('Checkbox ist unchecked bei nicht abgeschlossenem Todo', () => {
    render(
      <TodoItem
        todo={mockTodo}
        onToggle={mockOnToggle}
        onDelete={mockOnDelete}
      />
    );

    const checkbox = screen.getByRole('checkbox');
    expect(checkbox).not.toBeChecked();
  });

  test('Checkbox ist checked bei abgeschlossenem Todo', () => {
    const completedTodo = { ...mockTodo, completed: true };
    render(
      <TodoItem
        todo={completedTodo}
        onToggle={mockOnToggle}
        onDelete={mockOnDelete}
      />
    );

    const checkbox = screen.getByRole('checkbox');
    expect(checkbox).toBeChecked();
  });

  test('ruft onToggle mit korrekter ID beim Checkbox-Klick auf', async () => {
    const user = userEvent.setup();
    render(
      <TodoItem
        todo={mockTodo}
        onToggle={mockOnToggle}
        onDelete={mockOnDelete}
      />
    );

    await user.click(screen.getByRole('checkbox'));

    expect(mockOnToggle).toHaveBeenCalledTimes(1);
    expect(mockOnToggle).toHaveBeenCalledWith(1);
  });

  test('ruft onDelete mit korrekter ID beim Button-Klick auf', async () => {
    const user = userEvent.setup();
    render(
      <TodoItem
        todo={mockTodo}
        onToggle={mockOnToggle}
        onDelete={mockOnDelete}
      />
    );

    await user.click(screen.getByRole('button', { name: /löschen/i }));

    expect(mockOnDelete).toHaveBeenCalledTimes(1);
    expect(mockOnDelete).toHaveBeenCalledWith(1);
  });

  test('hat "completed" Klasse bei abgeschlossenem Todo', () => {
    const completedTodo = { ...mockTodo, completed: true };
    render(
      <TodoItem
        todo={completedTodo}
        onToggle={mockOnToggle}
        onDelete={mockOnDelete}
      />
    );

    const listItem = screen.getByRole('listitem');
    expect(listItem).toHaveClass('completed');
  });
});

TodoForm testen

Die TodoForm-Komponente mit kontrolliertem Input:

import { useState } from 'react';

function TodoForm({ onAdd }) {
  const [title, setTitle] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    if (title.trim() === '') return;
    onAdd(title);
    setTitle('');
  };

  return (
    <form className="todo-form" onSubmit={handleSubmit}>
      <input
        type="text"
        value={title}
        onChange={(e) => setTitle(e.target.value)}
        placeholder="Was möchtest du erledigen?"
      />
      <button type="submit">Hinzufügen</button>
    </form>
  );
}

Tests in TodoForm.test.jsx:

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import TodoForm from './TodoForm';

describe('TodoForm', () => {
  const mockOnAdd = jest.fn();

  beforeEach(() => {
    jest.clearAllMocks();
  });

  test('rendert Input und Button', () => {
    render(<TodoForm onAdd={mockOnAdd} />);

    expect(screen.getByPlaceholderText(/was möchtest du erledigen/i)).toBeInTheDocument();
    expect(screen.getByRole('button', { name: /hinzufügen/i })).toBeInTheDocument();
  });

  test('erlaubt Texteingabe', async () => {
    const user = userEvent.setup();
    render(<TodoForm onAdd={mockOnAdd} />);

    const input = screen.getByPlaceholderText(/was möchtest du erledigen/i);
    await user.type(input, 'Neues Todo');

    expect(input).toHaveValue('Neues Todo');
  });

  test('ruft onAdd beim Submit mit Titel auf', async () => {
    const user = userEvent.setup();
    render(<TodoForm onAdd={mockOnAdd} />);

    const input = screen.getByPlaceholderText(/was möchtest du erledigen/i);
    await user.type(input, 'Neues Todo');
    await user.click(screen.getByRole('button', { name: /hinzufügen/i }));

    expect(mockOnAdd).toHaveBeenCalledWith('Neues Todo');
  });

  test('leert Input nach Submit', async () => {
    const user = userEvent.setup();
    render(<TodoForm onAdd={mockOnAdd} />);

    const input = screen.getByPlaceholderText(/was möchtest du erledigen/i);
    await user.type(input, 'Neues Todo');
    await user.click(screen.getByRole('button', { name: /hinzufügen/i }));

    expect(input).toHaveValue('');
  });

  test('ruft onAdd nicht auf bei leerem Input', async () => {
    const user = userEvent.setup();
    render(<TodoForm onAdd={mockOnAdd} />);

    await user.click(screen.getByRole('button', { name: /hinzufügen/i }));

    expect(mockOnAdd).not.toHaveBeenCalled();
  });

  test('ruft onAdd nicht auf bei nur Leerzeichen', async () => {
    const user = userEvent.setup();
    render(<TodoForm onAdd={mockOnAdd} />);

    const input = screen.getByPlaceholderText(/was möchtest du erledigen/i);
    await user.type(input, '   ');
    await user.click(screen.getByRole('button', { name: /hinzufügen/i }));

    expect(mockOnAdd).not.toHaveBeenCalled();
  });
});

TodoList testen

import { render, screen } from '@testing-library/react';
import TodoList from './TodoList';

describe('TodoList', () => {
  const mockTodos = [
    { id: 1, title: 'Erstes Todo', completed: false },
    { id: 2, title: 'Zweites Todo', completed: true },
  ];
  const mockOnToggle = jest.fn();
  const mockOnDelete = jest.fn();

  test('zeigt Empty-State bei leerer Liste', () => {
    render(
      <TodoList
        todos={[]}
        onToggle={mockOnToggle}
        onDelete={mockOnDelete}
      />
    );

    expect(screen.getByText(/keine todos vorhanden/i)).toBeInTheDocument();
  });

  test('rendert alle Todos', () => {
    render(
      <TodoList
        todos={mockTodos}
        onToggle={mockOnToggle}
        onDelete={mockOnDelete}
      />
    );

    expect(screen.getByText('Erstes Todo')).toBeInTheDocument();
    expect(screen.getByText('Zweites Todo')).toBeInTheDocument();
  });

  test('rendert korrekte Anzahl an Listenelementen', () => {
    render(
      <TodoList
        todos={mockTodos}
        onToggle={mockOnToggle}
        onDelete={mockOnDelete}
      />
    );

    const items = screen.getAllByRole('listitem');
    expect(items).toHaveLength(2);
  });
});

Mocha + Chai + React Testing Library

Mocha ist flexibler als Jest - du wählst selbst, welche Assertion-Library und welches Mocking-Tool du verwendest. Die beliebteste Kombination ist Mocha + Chai.

Setup

npm install -D mocha chai @testing-library/react @testing-library/jest-dom @testing-library/user-event jsdom global-jsdom sinon

Erstelle .mocharc.json:

{
  "require": ["global-jsdom/register", "./test/setup.js"],
  "extension": ["js", "jsx"],
  "spec": "src/**/*.test.{js,jsx}",
  "loader": "babel-register"
}

Erstelle test/setup.js:

import '@testing-library/jest-dom';

Chai Assertion-Syntax

Chai bietet drei verschiedene Assertion-Stile:

// Assert Style
assert.equal(value, 'erwarteter Wert');

// Expect Style (am beliebtesten)
expect(value).to.equal('erwarteter Wert');

// Should Style
value.should.equal('erwarteter Wert');

TodoItem mit Mocha/Chai

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { expect } from 'chai';
import sinon from 'sinon';
import TodoItem from './TodoItem';

describe('TodoItem', () => {
  const mockTodo = { id: 1, title: 'React lernen', completed: false };

  it('rendert den Todo-Titel', () => {
    render(
      <TodoItem
        todo={mockTodo}
        onToggle={() => {}}
        onDelete={() => {}}
      />
    );

    expect(screen.getByText('React lernen')).to.exist;
  });

  it('ruft onToggle beim Checkbox-Klick auf', async () => {
    const onToggle = sinon.spy();
    const user = userEvent.setup();

    render(
      <TodoItem
        todo={mockTodo}
        onToggle={onToggle}
        onDelete={() => {}}
      />
    );

    await user.click(screen.getByRole('checkbox'));

    expect(onToggle.calledOnce).to.be.true;
    expect(onToggle.calledWith(1)).to.be.true;
  });

  it('ruft onDelete beim Button-Klick auf', async () => {
    const onDelete = sinon.spy();
    const user = userEvent.setup();

    render(
      <TodoItem
        todo={mockTodo}
        onToggle={() => {}}
        onDelete={onDelete}
      />
    );

    await user.click(screen.getByRole('button', { name: /löschen/i }));

    expect(onDelete.calledOnce).to.be.true;
    expect(onDelete.calledWith(1)).to.be.true;
  });
});

Wann Mocha/Chai wählen?

  • Du brauchst maximale Flexibilität bei der Wahl deiner Tools
  • Du arbeitest in einem bestehenden Node.js-Projekt mit Mocha
  • Du willst Assertion-Libraries austauschen können
  • Das Team ist mit Mocha bereits vertraut

Jasmine + React Testing Library

Jasmine ist ein BDD-Framework (Behavior Driven Development) mit eingebauten Assertions und Spies. Es war das Standard-Framework bevor Jest populär wurde.

Setup

npm install -D jasmine @testing-library/react @testing-library/jest-dom @testing-library/user-event jsdom

Initialisiere Jasmine:

npx jasmine init

Erstelle spec/support/jasmine-setup.js:

import '@testing-library/jest-dom';
import { JSDOM } from 'jsdom';

const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>');
global.window = dom.window;
global.document = dom.window.document;

Jasmine-Syntax

Jasmine verwendet describe, it, expect - ähnlich wie Jest, aber mit anderen Matchern:

// Jest
expect(value).toBe(5);
expect(array).toContain(item);
expect(fn).toHaveBeenCalled();

// Jasmine
expect(value).toBe(5);
expect(array).toContain(item);
expect(fn).toHaveBeenCalled();  // Gleich!

TodoItem mit Jasmine

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import TodoItem from '../src/components/TodoItem';

describe('TodoItem', () => {
  const mockTodo = { id: 1, title: 'React lernen', completed: false };

  it('should render the todo title', () => {
    render(
      <TodoItem
        todo={mockTodo}
        onToggle={() => {}}
        onDelete={() => {}}
      />
    );

    expect(screen.getByText('React lernen')).toBeInTheDocument();
  });

  it('should call onToggle when checkbox is clicked', async () => {
    const onToggle = jasmine.createSpy('onToggle');
    const user = userEvent.setup();

    render(
      <TodoItem
        todo={mockTodo}
        onToggle={onToggle}
        onDelete={() => {}}
      />
    );

    await user.click(screen.getByRole('checkbox'));

    expect(onToggle).toHaveBeenCalledTimes(1);
    expect(onToggle).toHaveBeenCalledWith(1);
  });

  it('should have completed class when todo is completed', () => {
    const completedTodo = { ...mockTodo, completed: true };

    render(
      <TodoItem
        todo={completedTodo}
        onToggle={() => {}}
        onDelete={() => {}}
      />
    );

    const listItem = screen.getByRole('listitem');
    expect(listItem).toHaveClass('completed');
  });
});

Jasmine vs Jest

FeatureJestJasmine
SetupMinimalMehr Konfiguration
Mockingjest.fn()jasmine.createSpy()
Snapshot TestsEingebautPlugin nötig
Watch ModeEingebautPlugin nötig
Code CoverageEingebautIstanbul separat

Empfehlung: Für neue React-Projekte ist Jest die bessere Wahl. Jasmine macht Sinn, wenn du es bereits in einem Angular-Projekt nutzt und React hinzufügst.

Vitest - Die moderne Alternative

Vitest ist der neue Star am Testing-Himmel. Es ist speziell für Vite entwickelt und bietet:

  • Blitzschnelle Ausführung durch native ES-Module
  • Jest-kompatible API - Migration ist trivial
  • Out-of-the-box TypeScript-Support
  • Watch-Mode mit HMR (Hot Module Replacement)

Warum Vitest?

Wenn du Vite für dein React-Projekt nutzt (was du solltest!), ist Vitest die natürliche Wahl:

# Performance-Vergleich (typisches Projekt)
Jest:   ~15 Sekunden für 100 Tests
Vitest: ~3 Sekunden für 100 Tests

Der Geschwindigkeitsvorteil kommt von der nativen ESM-Unterstützung - keine Transpilation während der Tests nötig.

Setup (Minimal!)

Mit Vite ist das Setup minimal:

npm install -D vitest @testing-library/react @testing-library/jest-dom @testing-library/user-event jsdom

Erweitere vite.config.js:

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: 'jsdom',
    setupFiles: './src/setupTests.js',
    css: true,
  },
});

Erstelle src/setupTests.js:

import '@testing-library/jest-dom';

Füge Scripts hinzu:

{
  "scripts": {
    "test": "vitest",
    "test:ui": "vitest --ui",
    "test:coverage": "vitest --coverage"
  }
}

TodoItem mit Vitest

Die Syntax ist fast identisch zu Jest:

import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, test, expect, vi, beforeEach } from 'vitest';
import TodoItem from './TodoItem';

describe('TodoItem', () => {
  const mockTodo = { id: 1, title: 'React lernen', completed: false };
  const mockOnToggle = vi.fn();  // vi statt jest
  const mockOnDelete = vi.fn();

  beforeEach(() => {
    vi.clearAllMocks();  // vi statt jest
  });

  test('rendert den Todo-Titel', () => {
    render(
      <TodoItem
        todo={mockTodo}
        onToggle={mockOnToggle}
        onDelete={mockOnDelete}
      />
    );

    expect(screen.getByText('React lernen')).toBeInTheDocument();
  });

  test('ruft onToggle beim Checkbox-Klick auf', async () => {
    const user = userEvent.setup();
    render(
      <TodoItem
        todo={mockTodo}
        onToggle={mockOnToggle}
        onDelete={mockOnDelete}
      />
    );

    await user.click(screen.getByRole('checkbox'));

    expect(mockOnToggle).toHaveBeenCalledWith(1);
  });
});

Migration von Jest zu Vitest

Die Migration ist einfach - hier die wichtigsten Unterschiede:

// Jest
import { jest } from '@jest/globals';
const mock = jest.fn();
jest.clearAllMocks();

// Vitest
import { vi } from 'vitest';
const mock = vi.fn();
vi.clearAllMocks();

Vitest bietet auch einen Kompatibilitätsmodus:

// vite.config.js
export default defineConfig({
  test: {
    globals: true,  // Aktiviert jest-ähnliche Globals
  },
});

Mit globals: true funktionieren jest.fn(), describe, test, expect ohne Import.

Vergleichstabelle & Empfehlung

Feature-Matrix

FeatureJestMocha+ChaiJasmineVitest
All-in-OneJaNeinJaJa
Setup-AufwandGeringHochMittelMinimal (Vite)
PerformanceGutGutGutExzellent
TypeScriptJa (Babel)Ja (Config)Ja (Config)Ja (nativ)
Watch ModeJaPluginPluginJa (HMR)
Snapshot TestsJaPluginPluginJa
UI für TestsNeinNeinNeinJa
CommunityRiesigGroßMittelWachsend

Meine Empfehlung

Für bestehende React-Projekte: Bleib bei Jest

  • Größtes Ecosystem, beste Dokumentation
  • Alle wissen, wie es funktioniert

Für neue Vite-Projekte: Nutze Vitest

  • Schneller, weniger Konfiguration
  • Perfekte Vite-Integration

Für maximale Flexibilität: Mocha + Chai

  • Wenn du eigene Tool-Kombinationen brauchst
  • Bei bestehenden Node.js-Projekten

Für Angular-Projekte: Jasmine

  • Bereits integriert, warum wechseln?

Best Practices

Test-Struktur: Arrange-Act-Assert

Strukturiere jeden Test in drei Teile:

test('fügt neues Todo hinzu', async () => {
  // Arrange (Vorbereitung)
  const user = userEvent.setup();
  const mockOnAdd = jest.fn();
  render(<TodoForm onAdd={mockOnAdd} />);

  // Act (Ausführung)
  await user.type(screen.getByPlaceholderText(/erledigen/i), 'Neues Todo');
  await user.click(screen.getByRole('button'));

  // Assert (Prüfung)
  expect(mockOnAdd).toHaveBeenCalledWith('Neues Todo');
});

API-Calls mocken

Für Integration-Tests solltest du API-Calls mocken:

// Mit Jest
jest.mock('./api/todoApi', () => ({
  getAllTodos: jest.fn(() => Promise.resolve([
    { id: 1, title: 'Mock Todo', completed: false }
  ])),
  createTodo: jest.fn((title) => Promise.resolve({
    id: 2, title, completed: false
  })),
}));

Accessible Queries bevorzugen

Nutze barrierefreie Selektoren - sie machen deine App gleichzeitig zugänglicher:

// Gut - barrierefrei
screen.getByRole('button', { name: /speichern/i });
screen.getByLabelText('E-Mail');

// Weniger gut - fragil
screen.getByTestId('submit-button');
screen.getByClassName('email-input');  // Existiert nicht mal!

Code Coverage

Strebe 70-80% Coverage an - 100% ist meist nicht sinnvoll:

# Jest
npm test -- --coverage

# Vitest
npm test -- --coverage

Fokussiere dich auf kritische Business-Logik, nicht auf jede Zeile.

Fazit

Du hast jetzt einen umfassenden Überblick über React Testing:

  • React Testing Library ist der Standard für komponentenbasiertes Testing
  • Jest bleibt der sichere Standard für die meisten Projekte
  • Vitest ist die Zukunft für Vite-basierte Projekte
  • Mocha + Chai bietet maximale Flexibilität
  • Jasmine ist solide, aber nicht mehr erste Wahl

Das Wichtigste: Fang an zu testen! Selbst ein paar einfache Tests sind besser als keine. Nutze die Beispiele aus diesem Tutorial mit deiner Todo-App und baue von dort aus auf.


Weiterführende Links:

Möchtest du auch so einen Blog?

Ich entwickle moderne, SEO-optimierte Websites und Blogs mit Next.js, React und Tailwind CSS.