Testing mit Jest und React Native Testing Library
Testing mit Jest und React Native Testing Library
~17 Min. Lesezeit Zuletzt aktualisiert am 8. August 2026
Expo-Projekte nutzen standardmäßig Jest statt Vitest aus "React für Profis" Kapitel 44 (Vitest ist Vite-spezifisch, Expo nutzt Metro als Bundler) – die API ist aber fast identisch, GENAU wie React Native Testing Library ("RNTL") das direkte Gegenstück zur React Testing Library ist, nur für native statt DOM-Elemente.
Installation
npx expo install jest-expo --dev
npm install --save-dev @testing-library/react-native jest{
"scripts": {
"test": "jest"
},
"jest": {
"preset": "jest-expo"
}
}jest-expo ist ein vorkonfiguriertes Jest-Preset SPEZIELL für Expo-Projekte – es übernimmt automatisch die richtige Transformation für .tsx-Dateien, native Module-Mocks (z. B. für expo-image) und weitere Expo-spezifische Setup-Details, die man sonst manuell konfigurieren müsste.
Den Zustand-Store isoliert testen
Genau wie in "React für Profis" Kapitel 44 beginnen wir mit dem EINFACHSTEN Fall – hier besonders praktisch, weil useCartStore selbst außerhalb einer React-Komponente aufrufbar ist:
import { describe, it, expect, beforeEach } from '@jest/globals';
import { useCartStore } from './cartStore';
describe('useCartStore', () => {
beforeEach(() => {
useCartStore.setState({ cart: [] }); // Store vor jedem Test zurücksetzen
});
it('startet mit einem leeren Warenkorb', () => {
expect(useCartStore.getState().cart).toEqual([]);
});
it('fügt ein Produkt hinzu', () => {
useCartStore.getState().addProduct({ sku: 'a1', name: 'Test', price: 10 });
expect(useCartStore.getState().cart).toHaveLength(1);
});
it('entfernt ein Produkt anhand der sku', () => {
useCartStore.getState().addProduct({ sku: 'a1', name: 'Test', price: 10 });
useCartStore.getState().removeProduct('a1');
expect(useCartStore.getState().cart).toEqual([]);
});
});useCartStore.setState(...)/.getState() – Zustand-Stores sind AUCH AUSSERHALB von React-Komponenten voll nutzbar (der Hook useCartStore(selector) ist nur EINE Art, auf den Store zuzugreifen) – ideal für Tests, die keine Komponente rendern müssen. beforeEach setzt den Store vor JEDEM einzelnen Test zurück, damit Tests sich nicht gegenseitig beeinflussen (ohne persist-Middleware in Tests, siehe Warnung unten).
Achtung: In echten Tests würde persist (die AsyncStorage-Middleware aus Kapitel 2) versuchen, auf natives AsyncStorage zuzugreifen, das in der Jest-Testumgebung nicht existiert. jest-expo mockt AsyncStorage AUTOMATISCH mit einer In-Memory-Variante – Tests laufen dadurch trotzdem, OHNE echte Persistenz zwischen Testläufen.
ProductCard mit RNTL testen
import { describe, it, expect, jest } from '@jest/globals';
import { render, screen, fireEvent } from '@testing-library/react-native';
import ProductCard from './ProductCard';
describe('ProductCard', () => {
const defaultProps = {
name: 'Wanderschuhe',
price: 89.99,
imageUrl: 'https://example.com/schuhe.jpg',
onPress: jest.fn(),
isFavorite: false,
onToggleFavorite: jest.fn(),
};
it('zeigt Name und Preis an', () => {
render(<ProductCard {...defaultProps} />);
expect(screen.getByText('Wanderschuhe')).toBeTruthy();
expect(screen.getByText('$89.99')).toBeTruthy();
});
it('ruft onPress auf, wenn die Karte gedrückt wird', () => {
render(<ProductCard {...defaultProps} />);
fireEvent.press(screen.getByText('Wanderschuhe'));
expect(defaultProps.onPress).toHaveBeenCalledTimes(1);
});
it('ruft onToggleFavorite auf, ohne onPress auszulösen', () => {
render(<ProductCard {...defaultProps} />);
fireEvent.press(screen.getByText('♡'));
expect(defaultProps.onToggleFavorite).toHaveBeenCalledTimes(1);
expect(defaultProps.onPress).not.toHaveBeenCalled();
});
});| Bibliothek | API-Unterschied |
|---|---|
| React Testing Library (Web) | fireEvent.click(...), sucht/vergleicht mit ECHTEN DOM-Knoten (toBeInTheDocument()). |
| React Native Testing Library | fireEvent.press(...) (kein "Klick" auf mobilen Geräten), arbeitet mit React Natives EIGENEM Element-Baum, nicht dem DOM (toBeTruthy() statt toBeInTheDocument()). |
Das dritte Test-Beispiel verifiziert INDIREKT dasselbe wie in "React für Profis" Kapitel 44: dass event.stopPropagation() in handleToggleFavorite tatsächlich funktioniert – ein Bug in dieser Zeile würde onPress zusätzlich auslösen und diesen Test fehlschlagen lassen.
Bonus: eigene Mocks für native Module
Manche Bibliotheken brauchen einen EXPLIZITEN Mock, den jest-expo nicht automatisch mitbringt – z. B. react-native-reanimated:
// jest.setup.js:
import 'react-native-reanimated/jestSetup';Tipp: Faustregel identisch zu "React für Profis" Kapitel 44: testen Sie SICHTBARES Verhalten (welcher Text erscheint, welche Callbacks werden aufgerufen), nicht interne Implementierung. Ein Test, der screen.getByText(...) statt einer internen State-Variable prüft, bleibt auch nach einem Refactoring gültig – GENAU das haben wir bereits mit isFavorite als PROP statt lokalem State in Kapitel 3 vorbereitet.