Suite test React Native Anda hijau, tetapi pengguna masih melaporkan bahwa mengetuk “Continue” tidak berfungsi di perangkat asli. Test komponen menemukan tombolnya, memanggil handler-nya, dan melihat layar yang diharapkan di lingkungan JavaScript yang di-mock. Ia tidak pernah memverifikasi prompt izin native, perilaku keyboard, animasi, platform API, atau stack navigasi yang sebenarnya.
Kesenjangan itulah yang membuat tim merasa yakin secara keliru. React Native Testing Library sangat bagus untuk menguji apa yang dirender oleh komponen dan bagaimana responsnya terhadap interaksi pengguna, tetapi bukan pengganti untuk pengujian perangkat atau pengukuran performa. Strategi yang andal adalah menggunakan setiap lapisan untuk kegagalan yang bisa diungkapkannya.
Table of Contents
- Mengapa User-Centric Testing Mengubah Segalanya
- Instalasi dan konfigurasi yang benar-benar berfungsi
- Core APIs, Queries, dan Assertions Dijelaskan
- Pola praktis untuk komponen, hooks, dan navigasi
- Debugging flaky test, CI, dan cek performa
- Menyatukan Semuanya dan Melangkah Maju
Mengapa User-Centric Testing Mengubah Segalanya
Kegagalan tes yang umum sudah dimulai sebelum tes ditulis. Developer memeriksa props komponen, mengakses state, atau membandingkan snapshot besar karena detail itu mudah di-assert. Tes lolos, lalu refactor mengubah struktur komponen tanpa mengubah pengalaman, dan suite tes pun gagal. Lebih buruk lagi, tes bisa tetap lolos padahal perilaku yang terlihat user salah karena asersi tidak pernah mendeskripsikan apa yang perlu dilihat user.
React Native Testing Library mengambil pendekatan sebaliknya. Anda me-render komponen, berinteraksi melalui kontrol yang terlihat, lalu meng-assert hasil yang bisa diamati user. Pendekatan itu sesuai dengan Contoh user-centric dari React Native Testing Library, serta panduan testing React Native untuk menjaga tes tetap singkat, memfokuskan tiap tes pada satu hal, memisahkan urusan view dari business logic dan state, dan lebih mengutamakan output yang terlihat atau accessibility helper daripada detail implementasi internal.

Uji perilaku yang diandalkan pengguna
Misalkan form login menonaktifkan tombol submit selama request berjalan. Tes yang rapuh mungkin memeriksa disabled pada instance komponen tertentu atau memverifikasi bahwa variabel state berubah. Uji yang lebih kuat menekan kontrol aksesibel “Sign in”, menunggu indikator loading, dan memeriksa apakah pesan error atau layar tujuan muncul.
Uji kedua tidak peduli apakah form menggunakan local state, reducer, custom hook, atau implementasi tombol yang berbeda. Yang penting adalah aplikasi mengomunikasikan hasil yang benar.
Aturan praktis: Jika pengguna tidak bisa mengamati perilaku tersebut, pertanyakan apakah itu termasuk dalam uji perilaku komponen.
Query berdasarkan label aksesibilitas dan role juga memaksa code produk yang lebih baik. Layar yang mengekspos label yang bermakna lebih mudah digunakan dengan teknologi bantu dan lebih mudah diuji. Koneksi ini penting saat Anda menilai cakupan yang lebih luas user experience aplikasi, karena testability dan usability sering meningkat bersama.
Pahami apa yang tidak dibuktikan test yang lulus
Uji komponen yang berpusat pada pengguna dapat membuktikan bahwa JavaScript merender cabang yang diharapkan dan merespons simulasi tekan. Namun, tidak bisa membuktikan bahwa prompt biometrik terbuka dengan benar, kamera native mengembalikan hasil yang dapat digunakan, atau alur pembayaran bertahan dari perilaku lifecycle yang spesifik platform.
Batas tersebut bukan kelemahan library. Ini adalah alasan untuk menjaga lapisan uji tetap jujur. Gunakan RNTL untuk perilaku komponen, lalu sisihkan uji berbasis perangkat untuk alur di mana integrasi native, navigasi nyata, izin, autentikasi, pembayaran, atau fungsionalitas inti aplikasi dapat mengubah hasil.
Instalasi dan konfigurasi yang benar-benar berfungsi
Setup modern dimulai dengan scoped package:
@testing-library/react-native
Versi lama react-native-testing-library Nama package npm masih ada sebagai artefak historis, tetapi proyek saat ini sebaiknya menggunakan scoped package yang dipelihara dalam keluarga Testing Library. Proyek ini repositori GitHub mendeskripsikannya sebagai utilitas React Native untuk mendorong praktik pengujian yang baik, dan riwayat rilisnya menunjukkan bahwa library ini terus berubah seiring React Native, bukan tetap sebagai helper statis.
Instal library dengan lingkungan Jest yang sudah ada. Proyek Expo umumnya menggunakan preset Expo Jest, sedangkan proyek React Native bare mungkin menggunakan preset React Native:
npm install --save-dev @testing-library/react-native jest
Untuk Expo, tambahkan preset yang sudah digunakan oleh proyek Anda:
{
"scripts": {
"test": "jest"
},
"jest": {
"preset": "jest-expo"
}
}
Untuk aplikasi React Native bare, gunakan konfigurasi Jest React Native yang sesuai sebagai gantinya. Pastikan preset tetap selaras dengan versi framework. Banyak kegagalan yang terlihat seperti masalah RNTL justru berasal dari React renderer, Babel transform, atau Jest preset yang tidak cocok.
Jaga file setup tetap eksplisit
Simpan konfigurasi environment bersama di file setup daripada mengulang mock di setiap test:
// jest.setup.js
import '@testing-library/react-native/extend-expect';
Lalu referensikan dari Jest:
{
"jest": {
"preset": "jest-expo",
"setupFilesAfterEnv": ["<rootDir>/jest.setup.js"]
}
}
Jika aplikasi Anda menggunakan React Navigation, Reanimated, gesture handling, safe-area context, atau modul storage, konfigurasikan hanya mock yang dibutuhkan environment test Anda. Mock global yang mengubah perilaku aplikasi bisa membuat setiap test lebih mudah lolos sekaligus membuat suite kurang bisa dipercaya.
TypeScript juga butuh perhatian serupa. Pastikan Jest melakukan transform pada .ts dan .tsx file melalui preset atau konfigurasi Babel Anda, dan pastikan tipe test tetap tersedia untuk compiler. Test yang berjalan secara lokal tetapi tidak di-type-check bisa menyembunyikan nama query yang salah, parameter navigasi yang tidak valid, atau struktur mock yang tidak aman.
Kronologi rilis sangat berguna saat mendiagnosis saran setup lama. Proyek ini mencatat 127 rilis, dengan v14.0.1 di-tag pada 2026-06-23, sementara v12.9.0, dirilis pada 2024-11-27, menambahkan dukungan resmi untuk React Native 0.77 dan Expo 52. Lini alpha v14 pada Maret 2025 beralih ke Universal Test Renderer dari React Test Renderer yang sudah deprecated dan bersiap untuk dukungan khusus React 19. Detail ini muncul di riwayat rilis RNTL, jadi jangan asal copy dependency renderer dari tutorial lama tanpa cek versi app Anda.
Untuk fondasi Jest yang praktis, bandingkan konfigurasi Anda dengan panduan unit tests JavaScript ini, lalu jalankan satu test komponen kecil sebelum menambahkan navigasi dan native mocks.

Core APIs, Queries, dan Assertions Dijelaskan
Test RNTL jadi terpercaya saat query-nya sesuai dengan apa yang bisa dilihat, ditemukan, dan dioperasikan user. API memang kecil, tapi memilih selector yang mengekspos detail implementasi bisa membuat test yang lolos jadi menyesatkan.
Mulai dengan render:
const screen = render(<LoginForm />);
Pilih query yang paling relevan bagi user. Utamakan query berbasis accessibility jika komponen menyediakannya, gunakan teks yang terlihat jika teks adalah perilakunya, dan simpan testID untuk kasus tanpa selector user-facing yang bermakna atau saat butuh integration hook yang stabil.

Pilih query berdasarkan timing dan intent
Setiap jenis query punya tujuan berbeda:
- Keberadaan sinkron: Gunakan
getByRole,getByText, atau query laingetBysaat elemen seharusnya sudah ada. Test akan langsung gagal jika tidak ada. - Kemunculan asinkron: Gunakan
findByRoleataufindByTextsaat rendering atau interaksi memicu update async. - Pengecekan ketiadaan: Gunakan
queryByTextatauqueryByTestIdketika sebuah elemen mungkin tidak ada dan hasil null lebih diharapkan daripada munculnya exception. - Fallback selector: Gunakan
getByTestIdsecara sengaja. Ini memberikan hook yang stabil untuk kontrol kompleks, namun tidak boleh menggantikan label aksesibel di seluruh aplikasi.
Untuk pengujian event yang terfokus, fireEvent.press adalah langsung:
fireEvent.press(screen.getByRole('button', { name: 'Save' }));
Gunakan userEvent ketika versi yang terinstal mendukung urutan interaksi yang lebih realistis. Apa pun pilihannya, lakukan assert pada UI yang dihasilkan:
expect(await screen.findByText('Saved')).toBeTruthy();
Handler assertion cocok untuk komponen yang kontrak publiknya berupa callback event. Ini lemah sebagai satu-satunya bukti bahwa alur pengguna berfungsi.
Utamakan assertion spesifik daripada snapshot
Assertion yang baik menggambarkan layar:
expect(screen.getByText('Account created')).toBeTruthy();
expect(screen.getByRole('button', { name: 'Continue' })).toBeEnabled();
Mereka juga dapat memverifikasi status aksesibilitas, seleksi, dan umpan balik validasi yang terlihat. Hindari memeriksa wiring internal:
expect(screen.getByTestId('submit-button').props.onPress).toBeDefined();
Asumsi itu membuktikan bahwa prop ada, bukan bahwa fitur berfungsi. Snapshot kecil yang disengaja dapat menangkap perubahan struktural, sedangkan snapshot navigasi atau layar yang besar sering kali menghasilkan review yang berisik dan memudahkan persetujuan pembaruan yang tidak dijelaskan.
Paket Testing Library termasuk dalam lingkup yang lebih luas testing-library organisasi npm. Paket aktifnya termasuk @testing-library/react-native, dengan versi 13.3.3 yang diterbitkan pada tahun 2026, sesuai dengan proyek repository proyek. Konvensi query bersama membantu di berbagai platform, tetapi tidak menentukan asumsi mana yang mewakili perilaku produk Anda.
Untuk perbandingan praktik pengujian komponen Jest yang lebih luas, lihat panduan unit testing React. RNTL tetap berhenti di batas komponen yang di-render JavaScript. Permission native, stack navigasi asli, keyboard perangkat, timing frame, dan perilaku memori butuh tooling E2E atau performance, bukan menambah mock komponen.
Video di bawah ini mendemonstrasikan workflow query dan assertion dalam konteks.
Pola praktis untuk komponen, hooks, dan navigasi
Test suite yang berguna mengikuti struktur aplikasi. Komponen presentasional butuh pengujian perilaku langsung, hooks butuh input dan output yang terkontrol, navigasi butuh provider yang cukup realistis, dan native module butuh mock yang tetap jelas berbeda dari verifikasi di perangkat nyata.

Komponen presentasional
Jaga pengujian komponen tetap dekat dengan public contract-nya:
const onSelect = jest.fn();
render(
<PlanCard
title="Team"
description="Shared workspace"
onSelect={onSelect}
/>
);
fireEvent.press(screen.getByRole('button', { name: 'Choose Team' }));
expect(onSelect).toHaveBeenCalled();
Label persisnya harus cocok dengan UI Anda. Yang penting adalah test menemukan kontrol sebagaimana user atau layanan aksesibilitas akan menemukannya, lalu memastikan hasil visual atau callback yang penting. Jangan mock semua child component secara default. Mock boundary yang mahal atau tidak terkait hanya jika mengaburkan perilaku yang sedang diuji.
Untuk custom hook, gunakan renderHook saat versi RNTL yang terinstal menyediakannya:
const { result } = renderHook(() => useSearch());
await act(async () => {
await result.current.submit('query');
});
expect(result.current.status).toBe('success');
Pengujian hook harus mengontrol boundary network atau repository, bukan mereproduksi seluruh aplikasi. Uji screen secara terpisah agar Anda tahu apakah state hook tersebut menjadi UI yang berguna.
Navigasi dan data asinkron
Untuk perilaku navigasi, merender screen di dalam navigator nyata NavigationContainer dan test navigator kecil sering kali lebih berharga daripada melakukan mock pada setiap metode navigasi. Tekan kontrol yang terlihat, tunggu konten tujuan, dan assert output screen baru tersebut. Sebuah useNavigation Mock masih cocok untuk tombol kecil yang satu-satunya tanggung jawabnya adalah dispatch typed route, tapi mock tidak akan memvalidasi registrasi route, parameter, atau perilaku nested navigator.
Data async juga butuh disiplin yang sama. Mock respons API atau repository, render screen, assert loading state, resolve request, lalu assert output sukses atau error. Gunakan findBy query untuk elemen yang diharapkan akhirnya muncul dan buat request yang ditolak eksplisit; jika tidak, test bisa lolos karena komponen tidak pernah mencapai branch yang dituju.
Mock native module
Mock untuk AsyncStorage, permissions, kamera, biometrik, dan platform API berguna untuk test JavaScript yang deterministik. Mock ini bukan bukti bahwa fitur native berfungsi. Pastikan perilaku mock tetap sesuai kontrak modul, reset calls di antara test, dan sertakan respons gagal alih-alih hanya memodelkan happy path.
| Skenario | Terbaik dengan RNTL | Perlu Validasi E2E |
|---|---|---|
| Validasi form dan error yang terlihat | Ya | Biasanya tidak |
| UI loading, success, dan error dari repository yang di-mock | Ya | Untuk alur production kritis |
| Navigasi antar screen terdaftar | Ya, dengan test navigator | Ya, jika gesture, deep link, atau perilaku platform penting |
| Keputusan state AsyncStorage | Ya, dengan mock yang terkontrol | Ya, jika launch dan persistensi berinteraksi dengan native lifecycle |
| Kamera, biometrik, permission, atau platform API | JS fallback dan logika branching | Ya, pada device asli atau representatif |
| Layout, performa rendering, dan native code | Tidak | Ya, dengan perangkat atau tooling khusus |
Batasan ini sangat praktis: mock dependensinya untuk menguji logika JavaScript Anda, lalu jalankan pengujian perangkat untuk memastikan perilaku asli dependensi tersebut.
Debugging flaky test, CI, dan cek performa
Test flaky sering kali menandakan waktu yang tidak terkontrol, shared state, atau assertion yang berlomba dengan UI. Identifikasi kondisi mana yang sedang terjadi sebelum menaikkan timeout. Timeout yang lebih lama bisa menyembunyikan masalah scheduling dan membuat suite lebih lambat.
Gunakan findBy untuk elemen yang diharapkan muncul setelah update. Gunakan waitFor untuk kondisi state atau mock calls. Jika fake timers diaktifkan, majukan timer tersebut saat interaksi membutuhkannya, lalu kembalikan ke real timer setelahnya. Sebuah act warning berarti React mendeteksi update di luar boundary interaksi yang diharapkan. Perbaiki awaityang hilang, interaksi user, atau timer flush alih-alih menekan warning tersebut.
Buat kegagalan CI dapat direproduksi
CI job yang andal menginstal dari lockfile, menjalankan perintah Jest yang sama seperti di lokal, dan mengisolasi mock state. Bersihkan mock calls di antara test, reset module saat module-level state memengaruhi perilaku, dan hapus ketergantungan pada urutan eksekusi. Caching Jest mempercepat feedback, tetapi perubahan dependensi atau konfigurasi memerlukan invalidasi cache yang sesuai.
Kegagalan hanya di CI memerlukan perbandingan lingkungan sebelum menulis ulang komponen. Periksa Node, package manager, pengaturan worker Jest, konfigurasi timer, dan variabel lingkungan. Reproduksi perintah yang sama secara lokal jika memungkinkan, lalu kurangi test yang gagal menjadi interaksi terkecil yang menunjukkan perbedaannya.
Observability mencakup celah yang berbeda. Pemantauan kesehatan aplikasi menyediakan konteks error produksi yang tidak dapat direproduksi oleh tes komponen ter-mock, termasuk kegagalan yang terkait dengan perangkat asli dan integrasi native.
Perjalanan yang sensitif terhadap keamanan memerlukan batas kedua. Gunakan test komponen untuk validasi dan transisi state, lalu tambahkan cakupan tingkat perangkat untuk handoff dan perilaku native. Untuk alur one-time-code, konsultasikan panduan tentang cara menguji alur verifikasi SMS ketika integrasi tersebut menjadi bagian dari perjalanan.
Anggap performa sebagai pengukuran, bukan asersi
Test fungsional dapat mengonfirmasi bahwa daftar dirender. Namun, test ini tidak dapat secara andal menentukan apakah refactoring mengubah durasi render atau jumlah render, karena runtime test menambahkan noise. Reassure mengukur nilai-nilai tersebut untuk sebuah skenario, mengulang skenario untuk mengurangi varians, dan menerapkan analisis statistik sebelum melaporkan perubahan yang bermakna. Dokumentasi dokumentasi pengujian performa juga mencakup pelaporan yang cocok untuk CI dan review pull-request.
Hindari asersi tetap seperti “render ini harus selesai di bawah ambang batas tertentu.” Worker CI yang sibuk dapat memicu kegagalan palsu, sementara ambang batas yang longgar bisa melewatkan regresi nyata. Gunakan pengukuran berulang untuk sinyal regresi, lalu periksa profil komponen dan perangkat ketika perbandingan menunjukkan perbedaan yang signifikan.
Aturan pengukuran: Tes fungsional menjawab apakah perilaku itu benar. Alat kinerja menjawab apakah skenario terukur berubah. Pisahkan pertanyaan-pertanyaan tersebut.
Menyatukan Semuanya dan Melangkah Maju
React Native Testing Library termasuk dalam lapisan luas dan cepat dari strategi pengujian Anda. Seharusnya mencakup perilaku komponen, perubahan state yang terlihat, hasil aksesibilitas, validasi, state data yang di-mock, dan integrasi antar komponen JavaScript. Fokuskan tes tersebut pada apa yang dapat diamati pengguna, dan buat kegagalan menunjuk ke perilaku spesifik, bukan pohon render yang besar.
Lapisan berbasis perangkat yang lebih kecil harus melindungi alur di mana mock bisa berbohong. React Native’s ringkasan pengujian menyatakan bahwa RNTL tidak menyediakan runtime React Native penuh dan tidak dapat menguji fitur native. Panduan yang sama merekomendasikan memasangkan tes komponen dengan alat E2E seperti Detox untuk alur kritis termasuk autentikasi, pembayaran, dan fungsionalitas inti aplikasi.
Jalur migrasi praktis
Anda tidak perlu menulis ulang suite yang ada dalam satu kali jalan.
- Pertahankan tes bisnis yang bernilai. Pindahkan state murni dan logika domain ke unit test yang fokus agar memberikan umpan balik yang jelas.
- Ganti dulu assertion implementasi. Ubah pengecekan prop dan internal-state menjadi output visual, status aksesibilitas, dan hasil interaksi.
- Perkecil snapshot. Simpan hanya snapshot yang dapat dipahami dan dikelola reviewer.
- Tambah coverage untuk native boundary. Untuk setiap module penting yang di-mock, identifikasi perilaku device yang masih perlu divalidasi.
- Lindungi alur kritis. Tambah coverage E2E untuk autentikasi, pembayaran, navigasi utama, permission, dan flow lain di mana perilaku native dapat mengubah hasil.
- Ukur screen sensitif secara terpisah. Gunakan perbandingan performa berulang untuk list, feed, dan render path yang berat daripada sekadar menebak dari durasi Jest.
Untuk keyakinan saat rilis, hubungkan suite ke testing integrasi CI/CD dan memerlukan lapisan pengujian yang tepat sebelum rilis. Jika perbaikan JavaScript atau aset harus sampai ke pengguna setelah validasi, Capgo dapat mengirim bundle web yang ditandatangani ke channel yang ditargetkan untuk aplikasi CapacitorJS dan Electron, dengan kontrol rollout dan perlindungan rollback. Alur pengiriman ini tidak menggantikan pengujian perangkat React Native, tetapi mengilustrasikan prinsip yang sama: validasi perilaku di lapisan tempat ia berjalan.
Pertanyaan yang tepat bukan apakah React Native Testing Library dapat menguji seluruh aplikasi Anda. Tidak bisa, dan batas resmi itu berguna. Pertanyaan yang tepat adalah apakah setiap risiko penting memiliki pengujian yang berjalan di lingkungan yang mampu mengungkapnya.
Capgo menghubungkan perubahan JavaScript dan aset yang tervalidasi ke pengiriman terkendali untuk tim CapacitorJS dan Electron, dengan channel yang ditargetkan, visibilitas rollout, dan perlindungan rollback. Kunjungi Capgo untuk melihat bagaimana hal ini dapat melengkapi alur pengujian komponen, E2E, dan CI Anda.