Belajar WebAssembly - Testing & Debugging
Episode 14 of 23

Belajar WebAssembly - Testing & Debugging

Menguasai strategi testing dan debugging modul WebAssembly: cargo test untuk target wasm, wasm-bindgen-test, browser testing dengan Playwright, serta wasm-tools print/dump, DWARF + LLDB/Chrome DevTools, dan section name

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Setelah di episode 13 kalian membangun modul Wasm untuk data processing — pada episode ini kita membahas hal yang sering dianggap membosankan namun menentukan produksi: testing dan debugging. Modul Wasm punya tantangan unik: ia berjalan di host yang berbeda (Node, browser, edge), interop-nya melintasi batas bahasa, dan bytecode-nya tidak mudah "diinspect" seperti kode sumber biasa.

Mengapa topik ini penting? Karena bug di interop Wasm–JS adalah salah satu sumber frustrasi terbesar: kesalahan tipe, salah offset memory, atau data race antar bahasa. Tanpa strategi testing dan tool debugging yang tepat, masalah-masalah ini berubah menjadi misteri yang memakan waktu berhari-hari.

Testing Rust untuk Target Wasm

cargo test di target host

Logika murni — fungsi yang tidak bergantung pada wasm-bindgen — bisa diuji sebagai unit test biasa:

Jalankan unit test di host
cargo test
unit-test.rs
#[wasm_bindgen]
pub fn fib(n: u32) -> u32 {
    match n {
        0 | 1 => n,
        _ => fib(n - 1) + fib(n - 2),
    }
}
 
#[cfg(test)]
mod tests {
    use super::*;
 
    #[test]
    fn fib_sederhana() {
        assert_eq!(fib(0), 0);
        assert_eq!(fib(1), 1);
        assert_eq!(fib(10), 55);
    }
}

Logika diuji cepat di host native (ratusan ms). Ini lapisan pertama dan termurah.

wasm-bindgen-test di browser

Untuk fungsi yang bergantung pada interop — string, JsValue, memory — pakai wasm-bindgen-test, yang menjalankan test di browser/Node sebagai Wasm:

Tambah wasm-bindgen-test
cargo add --dev wasm-bindgen-test
interop-test.rs
use wasm_bindgen_test::*;
 
#[wasm_bindgen_test]
fn sapaan_benar() {
    assert_eq!(sapaan("Budi"), "Halo, Budi!");
}
 
#[wasm_bindgen_test]
async fn async_interop() {
    let hasil = js_sys::Promise::resolve(&JsValue::from(42)).await;
    assert_eq!(hasil, JsValue::from(42));
}
Jalankan test interop di browser
wasm-pack test --headless --chrome

Test ini menjalankan modul Wasm yang sesungguhnya di engine browser — menguji interop persis seperti kondisi produksi.

Browser Testing dengan Playwright

Untuk menguji seluruh aplikasi — termasuk modul Wasm yang dipanggil dari UI — gunakan Playwright. Ini menguji "user journey", bukan hanya unit:

JSwasm.spec.js
import { test, expect } from "@playwright/test"
 
test("aplikasi memakai modul wasm", async ({ page }) => {
  await page.goto("/")
 
  await page.fill("#angka", "20")
  await page.click("#hitung")
 
  await expect(page.locator("#hasil")).toHaveText("6765")
})
Jalankan test Playwright
npx playwright test

Playwright memuat halaman nyata di Chromium/Firefox/WebKit, menunggu init() selesai, dan memverifikasi output — menangkap masalah yang tidak terlihat di unit test: salah inisialisasi, timing, dan interaksi DOM.

Debugging: wasm-tools print dan dump

Ketika masalah ada di dalam modul, mulai dari pembacaan struktur:

Baca modul sebagai WAT
wasm-tools print modul.wasm

Output WAT menunjukkan fungsi, imports, exports, dan instruksi secara persis — untuk memverifikasi apa yang benar-benar dikompilasi compiler.

Untuk inspeksi raw binary:

Dump struktur binary
wasm-tools dump modul.wasm

dump menampilkan setiap section — type, function, code, data — plus ukuran dan offset-nya. Berguna untuk mendiagnosis masalah ukuran atau section yang korup.

DWARF dan Debugging Source-Level

Compiler modern bisa menyertakan informasi DWARF ke dalam modul Wasm — metadata yang memetakan bytecode kembali ke kode sumber.

Kompilasi dengan debug info

Kompilasi Rust dengan DWARF
cargo build --target wasm32-unknown-unknown --features debug

Chrome DevTools

Chrome DevTools punya debugger Wasm source-level: dengan DWARF, kalian bisa memasang breakpoint di kode Rust/C asli, melangkah per baris, dan menginspeksi variabel — persis seperti debugging native di IDE.

LLDB untuk Wasm

LLDB (dengan support Wasm dari Wasmtime ecosystem) bisa men-debug modul di sisi server:

Debug via wasmtime + lldb
wasmtime run --debug modul.wasm

Section name: Nama untuk Readability

Modul yang di-minify tanpa nama fungsi sangat sulit di-debug. Compiler dapat menyertakan custom section name yang menyimpan nama fungsi dan parameter:

Set nama fungsi saat build Rust
RUSTFLAGS="-C symbol-mangling-version=v0" cargo build --release
Print nama-nama fungsi
wasm-tools print modul.wasm

Output print akan menampilkan (func $nama_fungsi_asli ...) alih-alih (func (;0;) ...) — perbedaan antara "membaca hieroglif" dan "membaca kode". Kebiasaan kecil yang menyelamatkan waktu debugging berjam-jam.

Tip

Jadikan pipeline tiga lapis sebagai default: unit test host (cargo test) untuk logika, wasm-bindgen-test untuk interop, dan Playwright untuk aplikasi utuh. Setiap lapisan menangkap kelas bug yang berbeda dengan biaya yang naik bertahap.

Common Pitfalls

  • Hanya menguji di host — kode yang lolos cargo test native bisa gagal di browser karena perbedaan ABI; selalu ada satu lapis test interop.
  • Mengabaikan panicpanic! di Rust berubah menjadi trap Wasm; aktifkan hook yang mengubahnya menjadi error yang bisa dibaca.
  • Salah membandingkan floatf32/f64 hampir selalu butuh epsilon; assert_eq! langsung menghasilkan kegagalan menyesatkan.
  • Lupa mem-build release — test harus menguji artefak yang sama dengan produksi, bukan debug build.

Warning

Untuk modul yang mem-parse input eksternal, tambahkan fuzz testing (mis. cargo-fuzz) di lapisan unit test: hasilnya tidak boleh trap atau menghabiskan memory pada input acak. Bug parsing adalah kelas bug paling umum di runtime produksi.

Penutup

Pada episode 14 ini, kalian telah membangun strategi testing dan debugging untuk modul WebAssembly.

Inti yang harus dibawa pulang:

  • Uji logika dengan cargo test (host), interop dengan wasm-bindgen-test, aplikasi dengan Playwright.
  • wasm-tools print/dump untuk inspeksi struktur modul.
  • DWARF memungkinkan debugging source-level di Chrome DevTools dan LLDB.
  • Section name dan build release yang konsisten menjaga modul tetap bisa dibaca.

Di episode 15 selanjutnya kita akan membahas optimasi ukuran & performawasm-opt dari Binaryen, wasm-strip, --release dan opt-level="z", code splitting dengan lazy instantiation, benchmark, dan menghindari alloc di hot-path. Sampai jumpa di episode 15!

Belajar WebAssembly - Testing & Debugging | Belajar Web Assembly