Native modules en asynchrone code mocken
Mock expo-location en andere native modules in Jest-configuratiebestanden, gebruik jest.fn() voor callbacks en test asynchrone flows met waitFor- en findBy-queries.
Native modules en asynchrone code mocken is een gratis React Native Academy-les op CoddyKit. Dit is les 4 van 4. Je kunt 3 lessen uit dit leerpad gratis volledig lezen — daarna ontgrendelt CoddyKit PRO alle lessen, plus praktische oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. Deze les maakt deel uit van het leertraject React Native Academy. Je voortgang wordt gesynchroniseerd op het web en in de CoddyKit-app. De cursus React Native Academy bevat in totaal 4 lessen.
Het probleem met native modules in Jest
Jest wordt uitgevoerd in een Node.js-omgeving, niet op een echt apparaat. Wanneer je component een native module zoals expo-camera of @react-native-async-storage/async-storage importeert, kan Jest de native code niet uitvoeren omdat er geen iOS- of Android-runtime beschikbaar is.
Hierdoor mislukken tests met fouten zoals 'jest-environment-jsdom is not supported' of 'Cannot read property of undefined'. De oplossing is om native modules na te maken — vervang ze door namaakimplementaties die alleen JavaScript gebruiken en zich voorspelbaar gedragen in tests.
Handmatige namaakimplementaties in de map __mocks__
Je kunt voor elke module een handmatige namaakimplementatie maken door een bestand te maken in de map __mocks__ naast node_modules. Jest gebruikt deze namaakimplementatie automatisch wanneer de module in testbestanden wordt geïmporteerd.
Maak bijvoorbeeld __mocks__/@react-native-async-storage/async-storage.js met een namaakimplementatie die gegevens in het geheugen opslaat. De Expo- en React Native-gemeenschappen onderhouden officiële namaakpakketten voor veelgebruikte native modules.
// __mocks__/@react-native-async-storage/async-storage.js
const storage = {};
export default {
getItem: jest.fn((key) => Promise.resolve(storage[key] ?? null)),
setItem: jest.fn((key, value) => {
storage[key] = value;
return Promise.resolve();
}),
removeItem: jest.fn((key) => {
delete storage[key];
return Promise.resolve();
}),
clear: jest.fn(() => {
Object.keys(storage).forEach((k) => delete storage[k]);
return Promise.resolve();
}),
getAllKeys: jest.fn(() => Promise.resolve(Object.keys(storage))),
};Het officiële namaakpakket gebruiken
@react-native-async-storage/async-storage wordt geleverd met een officiële Jest-namaakimplementatie op @react-native-async-storage/async-storage/jest/async-storage-mock. Registreer deze in je Jest-installatiebestand om hem voor alle tests te gebruiken zonder de namaakimplementatie handmatig te schrijven.
Ook react-native zelf maakt veel ingebouwde componenten na wanneer je de Jest-voorinstelling react-native gebruikt. Raadpleeg de documentatie van elke bibliotheek voor de aanbevolen configuratie van de Jest-namaakimplementatie.
// jest.config.js
module.exports = {
preset: 'jest-expo',
moduleNameMapper: {
'@react-native-async-storage/async-storage':
'@react-native-async-storage/async-storage/jest/async-storage-mock',
},
setupFilesAfterFramework: [
'@testing-library/jest-native/extend-expect',
],
};expo-location namaken
Modules uit de naamruimte expo-* hebben vaak native rechten en gps-hardware nodig. Maak ze na met jest.mock() bovenaan je testbestand, zodat ze gecontroleerde nagebootste waarden teruggeven zonder toegang tot een apparaat.
Geef opgeloste Promises terug vanuit asynchrone methoden om dezelfde API-vorm als de echte API te gebruiken. Door de retourwaarden te beheren, kun je alle vertakkingen testen: wat er gebeurt wanneer toestemming wordt verleend of geweigerd en wanneer gps specifieke coördinaten teruggeeft.
jest.mock('expo-location', () => ({
requestForegroundPermissionsAsync: jest.fn(),
getCurrentPositionAsync: jest.fn(),
PermissionStatus: { GRANTED: 'granted', DENIED: 'denied' },
}));
import * as Location from 'expo-location';
it('shows coordinates when permission is granted', async () => {
Location.requestForegroundPermissionsAsync
.mockResolvedValue({ status: 'granted' });
Location.getCurrentPositionAsync
.mockResolvedValue({ coords: { latitude: 37.78, longitude: -122.43 } });
const { findByText } = render(<LocationScreen />);
await findByText('37.78, -122.43');
});De Fetch-API namaken
Wanneer componenten HTTP-aanvragen doen met fetch, maak je de globale functie fetch in je tests na, zodat netwerkaanvragen geen echte servers bereiken. Gebruik jest.spyOn(global, 'fetch').mockResolvedValue() om fetch te vervangen door een gecontroleerde implementatie.
Geef een nagebootst object terug dat lijkt op Response en een methode json() heeft die je testgegevens retourneert. Zet de namaakimplementatie terug in afterEach, zodat elke test schoon begint.
beforeEach(() => {
global.fetch = jest.fn();
});
afterEach(() => {
jest.restoreAllMocks();
});
it('displays fetched posts in a list', async () => {
const mockPosts = [{ id: '1', title: 'Hello World' }];
global.fetch.mockResolvedValue({
ok: true,
json: () => Promise.resolve(mockPosts),
});
const { findByText } = render(<PostFeed />);
await findByText('Hello World');
expect(global.fetch).toHaveBeenCalledWith(
'https://api.example.com/posts'
);
});Axios namaken
Als je app Axios gebruikt, installeer je axios-mock-adapter om aanvragen te onderscheppen en nagebootste antwoorden terug te geven. Omwikkel je Axios-instantie met de adapter, definieer nagebootste antwoorden per eindpunt en zet de adapter tussen tests terug.
Deze aanpak is netter dan de volledige module axios namaken, omdat je hiermee specifieke URL-patronen en HTTP-methoden onafhankelijk kunt testen.
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
const mock = new MockAdapter(axios);
afterEach(() => mock.reset());
it('fetches and displays user profile', async () => {
mock.onGet('/api/users/123').reply(200, {
id: '123',
name: 'Alice',
email: 'alice@test.com',
});
const { findByText } = render(<ProfileScreen userId='123' />);
await findByText('Alice');
await findByText('alice@test.com');
});Asynchrone hooks testen met renderHook
RNTL exporteert een hulpprogramma renderHook om aangepaste hooks afzonderlijk te testen. Het rendert een minimale component die de hook aanroept en de retourwaarde van de hook beschikbaar maakt. Zo kun je hooklogica testen zonder deze aan een specifieke UI-component te koppelen.
Plaats statuswijzigingen bij asynchrone hooks die gegevens ophalen in act en gebruik waitFor om te wachten tot de asynchrone bewerking is voltooid voordat je controles uitvoert.
import { renderHook, act, waitFor } from '@testing-library/react-native';
import { useUserProfile } from '../src/hooks/useUserProfile';
it('fetches the user profile on mount', async () => {
global.fetch = jest.fn().mockResolvedValue({
ok: true,
json: () => Promise.resolve({ id: '1', name: 'Bob' }),
});
const { result } = renderHook(() => useUserProfile('1'));
// Initially loading
expect(result.current.loading).toBe(true);
// Wait for the fetch to complete
await waitFor(() => expect(result.current.loading).toBe(false));
expect(result.current.user?.name).toBe('Bob');
});AsyncStorage testen
Wanneer je componenten test die uit AsyncStorage lezen of ernaar schrijven, moet je beheren wat de opslag teruggeeft om verschillende beginstatussen te testen. Maak de opslag vóór de test na en controleer na een interactie de schrijfa anroepen.
Wis de geschiedenis van nagebootste aanroepen in beforeEach met jest.clearAllMocks(), zodat opslaglezingen uit de ene test niet doorwerken in de volgende. Zet de opslagkaart in het geheugen terug als je handmatige namaakimplementatie gegevens tussen aanroepen bewaart.
import AsyncStorage from '@react-native-async-storage/async-storage';
it('loads dark mode preference on mount', async () => {
// Arrange: storage returns 'dark' for theme key
AsyncStorage.getItem.mockResolvedValue('dark');
const { findByText } = render(<SettingsScreen />);
// Assert theme applied
await findByText('Dark Mode: ON');
expect(AsyncStorage.getItem).toHaveBeenCalledWith('theme');
});
it('saves the new theme when toggle is pressed', async () => {
AsyncStorage.getItem.mockResolvedValue('light');
const { getByTestId, waitFor } = render(<SettingsScreen />);
fireEvent(getByTestId('theme-toggle'), 'valueChange', true);
await waitFor(() =>
expect(AsyncStorage.setItem).toHaveBeenCalledWith('theme', 'dark')
);
});Testen met waitFor en findBy
waitFor(callback) roept de callback herhaaldelijk aan totdat deze geen fout meer veroorzaakt, tot aan een configureerbare time-out (standaard 1000 ms). Gebruik dit wanneer de UI-update plaatsvindt na een asynchrone bewerking waarvan de timing niet voorspelbaar is.
findBy*-query's, zoals findByText, zijn syntactische verkortingen voor waitFor(() => getByText(...)). Gebruik findBy voor afzonderlijke elementen en waitFor voor complexe controles met meerdere elementen of voorwaarden.
import { render, fireEvent, waitFor } from '@testing-library/react-native';
it('shows error message when API returns 400', async () => {
global.fetch = jest.fn().mockResolvedValue({
ok: false,
status: 400,
json: () => Promise.resolve({ message: 'Invalid email' }),
});
const { getByRole, findByText } = render(<SignUpForm />);
fireEvent.press(getByRole('button', { name: 'Create Account' }));
// Wait for the error to appear after the API response
expect(await findByText('Invalid email')).toBeTruthy();
// Alternatively:
await waitFor(() => {
expect(getByText('Invalid email')).toBeTruthy();
expect(getByRole('button', { name: 'Create Account' })).not.toBeDisabled();
});
});Timers namaken voor vertraagde invoervelden
Zoekinvoervelden vertragen API-aanroepen vaak — ze wachten tot de gebruiker klaar is met typen voordat ze een aanvraag starten. Gebruik voor het testen van dit vertraagde gedrag jest.useFakeTimers() en beheer de tijd met jest.advanceTimersByTime(ms) in plaats van te wachten op de echte vertraging.
Roep jest.useRealTimers() aan in afterEach om de echte timerfuncties terug te zetten voor andere tests die daarvan afhankelijk kunnen zijn.
it('triggers search after 500ms debounce', async () => {
jest.useFakeTimers();
const mockSearch = jest.fn().mockResolvedValue([]);
const { getByPlaceholderText } = render(<DebouncedSearch onSearch={mockSearch} />);
fireEvent.changeText(getByPlaceholderText('Search...'), 'react');
// Not yet called — debounce delay not elapsed
expect(mockSearch).not.toHaveBeenCalled();
// Advance time past the debounce window
await act(async () => {
jest.advanceTimersByTime(500);
});
expect(mockSearch).toHaveBeenCalledWith('react');
jest.useRealTimers();
});Testinstallatiebestanden voor globale namaakimplementaties
Plaats globale namaakimplementaties in een Jest-installatiebestand dat is geconfigureerd met setupFilesAfterFramework, in plaats van dezelfde installatie in elk testbestand te herhalen. Dit wordt één keer vóór alle tests uitgevoerd en registreert de namaakimplementaties globaal.
Veelgebruikte globale namaakimplementaties zijn native modules (AsyncStorage, camera, locatie), analysebibliotheken (om netwerkaanroepen te voorkomen) en prestatiebewaking. Houd het installatiebestand minimaal — voeg alleen namaakimplementaties toe die in de meeste tests nodig zijn.
// jest-setup.ts (referenced in jest.config.js setupFilesAfterFramework)
import '@testing-library/jest-native/extend-expect';
// Mock AsyncStorage globally
jest.mock('@react-native-async-storage/async-storage',
() => require('@react-native-async-storage/async-storage/jest/async-storage-mock')
);
// Mock analytics to avoid network calls in tests
jest.mock('@segment/analytics-react-native', () => ({
createClient: jest.fn(() => ({ track: jest.fn(), identify: jest.fn() })),
}));
// Silence console.error for expected React warnings in tests
const consoleError = console.error;
console.error = (...args) => {
if (String(args[0]).includes('Warning:')) return;
consoleError(...args);
};Korte controle
Test je begrip van de concepten uit deze les over mobiele ontwikkeling met React Native.
Samenvatting van de les
In deze les heb je geleerd: hoe je native modules namaakt met jest.mock() en handmatige namaakbestanden in de map __mocks__, hoe je HTTP-aanroepen namaakt met jest.fn() of axios-mock-adapter voor gecontroleerd testen van netwerkaanroepen en hoe je asynchrone stromen test met waitFor, findBy-query's en nagebootste timers. Hierna schrijven we end-to-endtests met Maestro die de echte app op een apparaat bedienen.
Leer JavaScript met een AI-tutor — gratis
Schrijf echte code en voer die uit in je browser, krijg direct hulp van een AI-tutor die 24/7 beschikbaar is en ga verder waar je gebleven bent op het web of in de app.
- Cursussen
- 30
- Lessen
- 120
Veelgestelde vragen
Is de les “Native modules en asynchrone code mocken” gratis?
Ja — je kunt hier op het web alle 3 lessen van het leerpad React Native Academy, waaronder “Native modules en asynchrone code mocken”, gratis volledig lezen. Daarna ontgrendelt CoddyKit PRO alle lessen, plus interactieve oefeningen met een ingebouwde code-editor en een AI-tutor die 24/7 beschikbaar is. De cursus React Native Academy bevat in totaal 4 lessen.
Wat leer ik in “Native modules en asynchrone code mocken”?
Mock expo-location en andere native modules in Jest-configuratiebestanden, gebruik jest.fn() voor callbacks en test asynchrone flows met waitFor- en findBy-queries. Je oefent met React Native Academy door code rechtstreeks in de browser uit te voeren. Een AI-begeleider die 24/7 beschikbaar is beantwoordt je vragen terwijl je de les doorwerkt.
Heb ik ervaring nodig om met React Native Academy te beginnen?
Ervaring vooraf is niet nodig. React Native Academy op CoddyKit is opgebouwd voor beginners tot gevorderden, zodat je hier of bij het begin kunt starten en in je eigen tempo kunt leren. Dit is les 4 van 4.
Hoe lang duurt de les “Native modules en asynchrone code mocken”?
De meeste lessen van CoddyKit duren ongeveer 5–10 minuten. Elke les is kort en interactief, zodat je gestaag vooruitgaat en op het web en in de app precies verdergaat waar je was gebleven.
Kan ik code schrijven en uitvoeren in deze les over React Native Academy?
Ja. Elke les over React Native Academy bevat een ingebouwde code-editor, zodat je rechtstreeks in je browser echte code kunt schrijven en uitvoeren en direct feedback van AI krijgt — lokale installatie is niet nodig.
Alle lessen in deze cursus
- Jest instellen in een React Native-project
- Componenten renderen met React Native Testing Library
- Gebeurtenissen uitvoeren en gebruikersinteractie testen
- Native modules en asynchrone code mocken