Kamu mungkin berada dalam salah satu situasi di bawah ini. Entah proyek JavaScript kamu hampir tidak memiliki tes dan setiap refactor terasa berisiko, atau kamu sudah memiliki tes dan separuh di antaranya lambat, rapuh, dan sulit dipercaya.
Terutama dalam Capacitor dan aplikasi Electron. Fitur sederhana dapat menyentuh logika bisnis bersama, API browser, plugin native, file lokal, IPC, dan layanan jarak jauh dalam aliran yang sama. Jika kamu menguji bagian-bagian tersebut dengan cara yang salah, suite tes kamu akan menjadi labirin dependensi palsu. Jika kamu mengujinya dengan cara yang benar, kamu akan mendapatkan feedback cepat pada logika yang rusak. Pengujian unit yang baik tidak dimulai dengan sintaks matcher yang cerdas. Ini dimulai dengan batasan yang disiplin: uji logika murni secara langsung, isolasi efek sampingan, dan hindari menulis tes yang runtuh ketika kamu mengubah nama fungsi internal. Tabel Konten
Pemilihan Framework Pemrograman JavaScript
Mengapa framework tidak boleh dianggap opsional
- Jest vs Mocha secara singkat
- Pengaturan Proyek dan Ujian Pertama
- Menguasai Mock dan Asynchronous Code
- Strategi Lanjutan untuk Ujian yang Kuat
- Menguji untuk CI, Capacitor, dan Aplikasi Electron
- Faq tentang Pengujian Satuan JavaScript
Memilih Framework Pengujian JavaScript
Proyek JavaScript profesional membutuhkan runner pengujian yang nyata. Skrip ad-hoc dan pengecekan console manual tidak dapat berkembang ketika beberapa insinyur menyentuh kodebase yang sama. Anda membutuhkan penemuan pengujian, asertasi, penanganan async, mock, dan cara menjalankan semuanya secara konsisten dalam pengembangan lokal dan CI.
Guidance saat ini terus berkembang menuju beberapa pilihan mainstream yang kecil. Jest, Mocha, dan Jasmine seringkali dihimbau sebagai kerangka utama, dengan Jest seringkali diidentifikasi sebagai struktur tes bawaan, asertasi, pemalsuan, dan dukungan async dalam satu paket, seperti yang ditunjukkan dalam lab tes JavaScript ini Tabel perbandingan menampilkan kerangka tes JavaScript populer termasuk Jest, Mocha, Cypress, dan Playwright.

Kesalahan pertama tim membuat adalah menganggap tes unit sebagai kegiatan sampingan. Biasanya hal ini menyebabkan penamaan file tidak konsisten, asertasi kustom yang tidak diingat, dan bantuan yang hanya dipahami oleh satu orang
Kerangka memberikan Anda bahasa bersama:
Struktur tes
- dengan dan
describeatautest__CAPGO_KEEP_0__it - Pengecekan Asumsi dengan matcher yang mudah dibaca
- Hook untuk setup dan teardown
- Support Asinkron untuk promise dan timer
- Alat Mocking untuk dependensi eksternal
Jika tim Anda juga membutuhkan pandangan yang lebih luas tentang otomatisasi tes di luar pekerjaan tingkat unit, Capgo memiliki gambaran yang berguna tentang pemantauan otomatis dalam alur pengiriman aplikasi.
Jest vs Mocha secara singkat
Jest dan Mocha mewakili dua filosofi yang berbeda.
Jest adalah pilihan semua dalam satu. Ini membawa kebanyakan dari apa yang tim butuhkan pada hari pertama. Mocha adalah lebih modular. Ini memberikan Anda runner dan mengharapkan Anda untuk menyusun sisa dari stack.
Fitur Jest
| Mocha | Kompleksitas pengaturan | Lebih rendah untuk tim kebanyakan |
|---|---|---|
| Tinggi karena biasanya Anda menambahkan library asseri dan mocking | Asertasi | Tersedia secara bawaan |
| __CAPGO_KEEP_0__ | __CAPGO_KEEP_0__ | Biasanya dipasangkan dengan library lain |
| Menggunakan mock | Dibangun secara internal | Biasanya dipasangkan dengan library lain |
| Menguji asinkron | Dibangun secara internal dan sederhana | Dapat didukung, tetapi tergantung pada pengaturan sekitar |
| Alur kerja penutupan | Biasanya diintegrasi ke dalam toolchain yang sama | Seringkali lebih terpisah-pisah |
| Pilihan terbaik | Proyek baru, tim yang ingin konsistensi | Paket-paket lama, tim yang ingin mengontrol modul |
Aturan praktis: Jika tim Anda harus bertanya-tanya perpustakaan asertasi dan perpustakaan mocking mana yang harus dipasangkan dengan runner, kemungkinan besar Anda ingin menggunakan Jest.
Apa yang saya rekomendasikan untuk tim kebanyakan
Untuk proyek modern kebanyakan, saya akan memilih Jest kecuali kodebase sudah memiliki alasan kuat untuk tetap menggunakan Mocha. Saran saya semakin kuat ketika aplikasi termasuk Capacitor atau Electron, karena proyek-proyek tersebut sudah memiliki bagian yang cukup bergerak. Mengurangi penyebaran alat uji membayar cepat.
Mocha masih relevan dalam layanan Node.js yang lebih tua atau kodebase yang sudah lama hidup di mana ekosistem di sekitarnya sudah terjalin. Tapi untuk seorang insinyur mid-level yang mengatur suite yang kuat dari awal, Jest biasanya mengurangi gesekan lebih banyak daripada yang dibuat.
One catatan penting. Cypress dan Playwright adalah alat-alat yang sangat baik, tetapi mereka menyelesaikan masalah yang berbeda. Mereka lebih baik untuk pengujian browser-level dan end-to-end, bukan loop dalam yang cepat di mana unit tests JavaScript harus hidup.
Konfigurasi Proyek dan Ujian Pertama
Konfigurasi pengujian yang bersih haruslah membosankan. Jika menambahkan ujian pertama terasa rumit, maka suite tidak akan tetap sehat.

Konfigurasi Jest yang Sederhana
Mulai dengan proyek JavaScript yang sudah memiliki package.jsonLalu tambahkan Jest sebagai dependensi pengembangan dan hubungkan skrip pengujian.
{
"scripts": {
"test": "jest"
}
}
Itu sudah cukup untuk banyak proyek. Anda dapat menambahkan konfigurasi lebih lanjut jika sistem modul, transpilasi, atau struktur monorepo memerlukan.
Jika Anda sedang membangun aplikasi Capacitor secara lokal dan ingin lingkungan pengembangan Anda dalam kondisi sebelum menambahkan ujian di sekitar logika yang dibagikan, Capgo's guide ke mengatur lingkungan lokal Capacitor adalah mitra yang sangat berguna.
Tulis ujian sebelum code
Polanya test pertama bukan hanya preferensi pribadi. Badan Perlindungan Konsumen Keuangan Amerika Serikat (Consumer Financial Protection Bureau) mengeluarkan pedoman JavaScript yang secara eksplisit merekomendasikan menulis test pertama, mengorganisir test dengan describe dan it, dan mengatur periksa sekitar expect(...) klaim dalam pedoman pengujian unit JavaScript-nya Hal ini penting karena test pertama mengubah cara Anda merancang __CAPGO_KEEP_0__. Fungsi cenderung menjadi lebih kecil, dependensi menjadi lebih terlihat, dan efek sampingan berhenti mengalir ke logika yang seharusnya tetap murni..
That matters because test-first changes how you design code. Functions tend to become smaller, dependencies become more visible, and side effects stop leaking into logic that should stay pure.
Gunakan Arrange Act Assert setiap kali
// math.js
function addTax(amount, rate) {
return amount + amount * rate;
}
module.exports = { addTax };
// math.test.js
const { addTax } = require('./math');
describe('addTax', () => {
it('returns the amount with the tax applied', () => {
expect(addTax(100, 0.2)).toBe(120);
});
});
The
Arrange, Act, Assert Penggunaan test pertama mengubah cara Anda merancang __CAPGO_KEEP_0__. Fungsi cenderung menjadi lebih kecil, dependensi menjadi lebih terlihat, dan efek sampingan berhenti mengalir ke logika yang seharusnya tetap murni. Menggunakan pola yang tepat menjaga tes tetap mudah dibaca, bahkan ketika mereka semakin kompleks.
- Susun masukan dan setiap setup yang dibutuhkan.
- Lakukan dengan memanggil fungsi.
- Pastikan hasilnya.
Diterapkan pada helper validasi:
function isSupportedPlatform(platform) {
return ['ios', 'android', 'web', 'desktop'].includes(platform);
}
describe('isSupportedPlatform', () => {
it('returns true for ios', () => {
// Arrange
const platform = 'ios';
// Act
const result = isSupportedPlatform(platform);
// Assert
expect(result).toBe(true);
});
});
Tes kecil bertahan lama. Sebuah tes biasanya harus menjawab satu pertanyaan, bukan menceritakan alur kerja yang panjang.
Untuk Capacitor dan proyek Electron, disiplin itu lebih penting karena logika murni Anda sering kali berada di samping integrasi desktop atau native code. Jaga aturan bisnis tetap dapat diuji tanpa runtime platform, dan tes pertama Anda tidak akan menjadi tes yang berguna terakhir.
Menguasai Mocks dan Asynchronous Code
Banyak bug di aplikasi code tidak berasal dari penjumlahan dua angka. Mereka berasal dari code yang mencapai luar diri sendiri: permintaan jaringan, file, plugin API, timer, saluran IPC, lapisan penyimpanan.
Dimana mocking membantu. Ini memberikan Anda kontrol atas batasan sehingga tes dapat fokus pada keputusan-keputusan code Anda.

Mock batasan, bukan semuanya
Panduan tes yang dapat dipertahankan menekankan penutupan perilaku tunggal dan pernyataan kuat satu per tes, dan juga mengingatkan bahwa menggunakan mock yang berlebihan membuat tes menjadi rapuh dan terikat pada detail implementasi, seperti yang disingkatkan dalam artikel TestRail tentang tes unit yang dapat dipertahankan.
Pesan tersebut sangat penting dalam JavaScript. Tim sering kali memulai dengan mengmock semua modul yang diimport dan akhirnya menguji apakah fungsi memanggil fungsi lain dalam urutan yang
Target yang buruk untuk tes yang berat mock:
- apakah helper A memanggil helper B
- apakah layanan C memanggil serializer D
- apakah fungsi pribadi internal berjalan dua kali
Target yang lebih baik:
- apa yang dikembalikan oleh fungsi
- apakah ia menangani ketergantungan yang gagal dengan benar
- apakah ia mengubah data menjadi bentuk yang diharapkan
Polanya yang lebih baik untuk Capacitor dan Electron code
Dalam aplikasi mobile dan desktop, saya lebih suka layer penutup di sekitar API native atau platform. Kemudian, unit tests memalsukan layer penutup, bukan platform itu sendiri.
Struktur contoh:
// cameraGateway.js
async function getPhoto(cameraPlugin) {
return cameraPlugin.getPhoto();
}
module.exports = { getPhoto };
// profilePhotoService.js
async function loadProfilePhoto(cameraGateway) {
const photo = await cameraGateway.getPhoto();
return { path: photo.path, ready: true };
}
module.exports = { loadProfilePhoto };
// profilePhotoService.test.js
const { loadProfilePhoto } = require('./profilePhotoService');
test('returns mapped photo data', async () => {
const fakeCameraGateway = {
getPhoto: jest.fn().mockResolvedValue({ path: '/tmp/pic.jpg' })
};
const result = await loadProfilePhoto(fakeCameraGateway);
expect(result).toEqual({ path: '/tmp/pic.jpg', ready: true });
});
Polanya itu berlaku juga untuk Electron. Tutup ipcRendererUntuk tim yang menguji logika rilis dan jalur pembaruan di __CAPGO_KEEP_0__ aplikasi, __CAPGO_KEEP_1__ memiliki panduan relevan
For teams testing release logic and update paths in Capacitor apps, Capgo has a relevant guide on menguji pembaruan OTA secara mock dengan Capacitor.
Jika tim Anda masih normalisasi gaya tes async: sebuah walkthrough cepat membantu
Menguji arus async tanpa flakiness
Gunakan async/await dalam tes ketika code yang diuji kembali sebuah promise. Lebih jelas daripada pola callback berat dan lebih mudah untuk di debug.
async function fetchProfile(api) {
const response = await api.getUser();
return response.name;
}
test('returns the user name from the API response', async () => {
const api = {
getUser: jest.fn().mockResolvedValue({ name: 'Ava' })
};
const result = await fetchProfile(api);
expect(result).toBe('Ava');
});
Juga uji jalur gagal:
test('throws when the API request fails', async () => {
const api = {
getUser: jest.fn().mockRejectedValue(new Error('network failed'))
};
await expect(fetchProfile(api)).rejects.toThrow('network failed');
});
Uji jalur yang bahagia dan jalur yang tidak bahagia. Di produksi, jalur yang tidak bahagia biasanya yang diingat pengguna.
Strategi Lanjutan untuk Tes yang Kuat
Suatu suite tes menjadi berguna ketika tetap berguna setelah code berubah. Itu lebih sulit daripada menulis sebuah tumpukan tes yang berhasil.

Gunakan pembagian tes sebagai anggaran
Panduan praktis yang satu merekomendasikan sebuah 70/20/10 dipisahkan di unit, integrasi, dan tes akhir-ke-akhir, dengan tes unit yang memberikan feedback yang paling cepat dan gagal yang paling stabil. Panduan yang sama mengatakan bahwa suatu suite unit yang lengkap seharusnya selesai dalam kurang dari 10 detik, dan periksa pre-commit seharusnya tetap kurang dari 5 detik, menurut panduan tes ini OpenReplay.
Saya menganggap itu sebagai alat anggaran, bukan agama. Jika sebagian besar upaya Anda masuk ke tes akhir-ke-akhir, tim Anda akan menunggu terlalu lama untuk mendapatkan feedback. Jika semuanya hanya unit, Anda akan melewatkan batasan sistem yang nyata.
Untuk aplikasi Capacitor atau Electron, keseimbangan yang sehat biasanya terlihat seperti ini:
- Tes unit untuk logika harga, aturan akses, serialisasi, kelayakan update, flag fitur, dan transformasi keadaan
- Integrasi tes untuk pengguna adapter penyimpanan, pembungkus plugin, dan kontrak IPC
- Tes E2E untuk beberapa perjalanan kritikal seperti login, alur pembelian, sinkron, atau permintaan pembaruan
Indeks koverasi bukanlah target
Laporan koverasi berguna ketika membantu Anda menemukan cabang yang belum diuji dalam logika penting. Mereka menjadi berbahaya ketika tim mengejar persentase koverasi untuk kepentingan mereka sendiri.
Validator login dengan ujian kasus sampingan yang berpikir memberikan nilai lebih daripada file yang tertutup penuh dengan asertasi trivial. Hal itu terutama benar untuk input-heavy code seperti formulir, parser, logika tanggal, dan periksa izin. Jika tim Anda memperketat kualitas di sekitar validasi UI berat, panduan ini tentang menguasai validasi formulir frontend merupakan tambahan yang baik untuk strategi tes tingkat unit.
Tes perilaku pertama bertahan dari refaktor
Suku yang dapat diandalkan harus memungkinkan Anda merakit internal tanpa menulis ulang setengah tes. Cara termudah untuk mencapai sana adalah dengan mengklaim perilaku yang dapat dilihat bukan detail implementasi.
Kasus penggunaan yang tetap relevan:
- Kondisi batas seperti input kosong, nilai seperti null, jenis data tidak valid, dan string yang terlalu besar
- Hasil domain seperti “penolakan kembali karena kekurangan izin”
- Transisi keadaan seperti “mengubah status sebagai menunggu setelah metadata diunduh diverifikasi”
Kasus penggunaan yang sering rusak:
- menginspeksi panggilan helper internal
- mengklaim urutan metode privat
- menggantikan setiap lapisan dalam rantai panggilan
For tim tim pengembang aplikasi yang membangun proses rilis yang disiplin, artikel Capgo tentang jaminan kualitas aplikasi bermanfaat karena menghubungkan pekerjaan tes dengan pipa rilis yang lebih luas.
Tes untuk CI, Capacitor, dan aplikasi Electron
Tes yang hanya berjalan di satu mesin pengembang bukanlah jaring pengaman. Itu adalah kebiasaan lokal.
CI mengubah tes unit ke infrastruktur tim. Setiap push, pull request, atau branch rilis dapat menjalankan perintah yang sama dengan harapan yang sama. Konsistensi itu lebih penting lagi untuk Capacitor dan aplikasi Electron, karena pergeseran lingkungan menyebabkan kegagalan yang halus.
Jadikan CI sebagai jalur eksekusi default
Paling tidak, CI Anda harus menginstal dependensi dan menjalankan suite unit pada setiap set perubahan. Simpan perintah identik dengan pengembangan lokal saat mungkin.
Alur kerja GitHub Actions yang sederhana dapat sekecil ini:
name: test
on: [push, pull_request]
jobs:
unit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm test
Itu sudah cukup untuk menangkap import yang rusak, asseri yang gagal, dan asumsi platform yang tidak sengaja sebelum mereka mendarat di utama.
Untuk tim mobile yang mengirimkan melalui pipa otomatis, Capgo memiliki panduan praktis untuk mengatur CI/CD untuk aplikasi Capacitor.
Menguji interaksi plugin Capacitor
Cara yang salah untuk menguji unit plugin Capacitor code adalah dengan menarik plugin native secara langsung ke dalam setiap layanan. Hal ini membuat suite uji Anda terikat dengan jembatan platform.
Polanya yang lebih baik adalah abstraksi tipis:
// deviceStorage.js
async function saveFile(filesystem, path, data) {
return filesystem.writeFile({ path, data });
}
module.exports = { saveFile };
// draftService.js
async function persistDraft(storage, draft) {
await storage.save('draft.json', JSON.stringify(draft));
return { saved: true };
}
module.exports = { persistDraft };
// draftService.test.js
const { persistDraft } = require('./draftService');
test('persists a serialized draft', async () => {
const storage = {
save: jest.fn().mockResolvedValue(undefined)
};
const result = await persistDraft(storage, { title: 'Hello' });
expect(result).toEqual({ saved: true });
});
Ide yang sama berlaku untuk akses kamera, prompt biometrik, registrasi token push, dan status jaringan. Simpan panggilan plugin di adapter. Uji logika aplikasi terhadap interface yang Anda kendalikan.
Menguji Electron main renderer dan IPC code
Aplikasi Electron memiliki dua sambungan penting: proses utama code dan proses renderer codeJangan memadukan mereka dalam uji.
Pengaturan yang dapat diandalkan biasanya memisahkan:
- Uji unit renderer untuk model tampilan, keadaan, pengaturan format, dan logika bisnis sisi UI
- Unit tes proses utama untuk menu, operasi file, dan keputusan siklus aplikasi
- Tes kontrak IPC untuk bentuk pesan dan respons yang diharapkan
Contoh wrapper IPC:
// ipcGateway.js
function sendSettings(ipcRenderer, payload) {
ipcRenderer.send('settings:update', payload);
}
module.exports = { sendSettings };
// ipcGateway.test.js
const { sendSettings } = require('./ipcGateway');
test('sends settings update over ipc', () => {
const ipcRenderer = { send: jest.fn() };
sendSettings(ipcRenderer, { theme: 'dark' });
expect(ipcRenderer.send).toHaveBeenCalledWith('settings:update', { theme: 'dark' });
});
Jika Anda kemudian mengubah implementasi internal dari satu bantuan ke bantuan lain, tes ini masih berlaku karena memverifikasi perilaku yang penting. Itulah standar yang Anda inginkan di desktop dan mobile code.
Faq yang Sering Ditanyakan Tentang Pengujian Satuan JavaScript
Apa perbedaan antara pengujian satuan integrasi dan E2E
A Pengujian satuan memeriksa satu bagian logika kecil secara isolasi. Sebuah Tes Integrasi Mengatur apakah beberapa komponen atau layanan bekerja bersama-sama dengan benar. Sebuah Tes Akhir ke Akhir Menguji perjalanan pengguna melalui aplikasi yang berjalan.
Pakai tes unit untuk kepercayaan cepat dalam aturan bisnis. Pakai tes integrasi untuk celah seperti penyimpanan, wrapper plugin, dan IPC. Pakai tes E2E dengan sedikit untuk alur kerja yang akan sangat terganggu jika mereka rusak.
Apakah kita harus mencapai coverase penuh
Tidak. Coverase penuh dapat mendorong tim ke tes yang tidak berharga.
Coverase berguna ketika menunjukkan risiko code yang tidak pernah digunakan. Tidak berguna ketika insinyur menambahkan asertasi dangkal hanya untuk memuaskan dashboard. Jika suite Anda sangat rapuh, coverase yang lebih banyak tidak akan menyelamatkannya.
Bagaimana kita menambahkan tes ke basis kode yang sudah ada
Mulai dari tempat perubahan sudah terjadi. Jangan membuat tim beku dan mengumumkan perubahan besar dalam strategi tes.
Sebuah urutan yang praktis seperti ini:
- Pertahankan code yang aktif terlebih dahulu dengan menambahkan tes ke modul yang Anda sentuh selama pekerjaan fitur atau perbaikan bug
- Mengambil logika murni dari file yang sulit diuji sehingga aturan bisnis dapat diuji tanpa kebisingan framework atau runtime
- Menambahkan wrapper celah sekitar plugin native, klien jaringan, panggilan filesystem, dan IPC Electron
- Menolak pola yang rapuh ketika memperkenalkan mock. Panduan dari praktik terbaik pengujian JavaScript terutama berguna di sini karena menyoroti masalah yang sering terlewatkan yaitu over-mocking dan tes yang rapuh yang mengikuti
Tujuan bukanlah kesempurnaan segera. Itu adalah perbaikan yang stabil di tempat-tempat di mana regresi menghabiskan biaya tim paling banyak
Jika tim Anda mengirimkan Capacitor atau Aplikasi Electron dan perlu proses rilis yang lebih bersih seputar perubahan JavaScript, __CAPGO_KEEP_0__ Capgo Ditulis oleh