Magento 2 Experten — Hyvä Theme, Tailwind CSS & SEO aus einer Hand ›

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
package.json
{
  "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:

store/cartStore.test.ts
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

components/ProductCard.test.tsx
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();
  });
});
BibliothekAPI-Unterschied
React Testing Library (Web)fireEvent.click(...), sucht/vergleicht mit ECHTEN DOM-Knoten (toBeInTheDocument()).
React Native Testing LibraryfireEvent.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.