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:
| Feature | Jest | Mocha | Jasmine | Vitest |
|---|---|---|---|---|
| Typ | All-in-One | Test Runner | All-in-One | All-in-One |
| Assertions | Eingebaut | Benötigt Chai | Eingebaut | Eingebaut |
| Mocking | Eingebaut | Benötigt Sinon | Eingebaut | Eingebaut |
| Setup | Minimal | Mehr Konfiguration | Moderat | Minimal (mit Vite) |
| Snapshot Tests | Ja | Plugin nötig | Plugin nötig | Ja |
| Performance | Gut | Gut | Gut | Sehr schnell |
| Beste für | React | Node.js, Flexibilität | Angular | Vite-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:
| Query | Findet Element? | Wirft Fehler? | Async? |
|---|---|---|---|
getBy* | Ja | Ja, wenn nicht gefunden | Nein |
queryBy* | Optional | Nein, gibt null zurück | Nein |
findBy* | Ja | Ja, nach Timeout | Ja |
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
| Feature | Jest | Jasmine |
|---|---|---|
| Setup | Minimal | Mehr Konfiguration |
| Mocking | jest.fn() | jasmine.createSpy() |
| Snapshot Tests | Eingebaut | Plugin nötig |
| Watch Mode | Eingebaut | Plugin nötig |
| Code Coverage | Eingebaut | Istanbul 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
| Feature | Jest | Mocha+Chai | Jasmine | Vitest |
|---|---|---|---|---|
| All-in-One | Ja | Nein | Ja | Ja |
| Setup-Aufwand | Gering | Hoch | Mittel | Minimal (Vite) |
| Performance | Gut | Gut | Gut | Exzellent |
| TypeScript | Ja (Babel) | Ja (Config) | Ja (Config) | Ja (nativ) |
| Watch Mode | Ja | Plugin | Plugin | Ja (HMR) |
| Snapshot Tests | Ja | Plugin | Plugin | Ja |
| UI für Tests | Nein | Nein | Nein | Ja |
| Community | Riesig | Groß | Mittel | Wachsend |
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:

