Laravel Inertia Vue 3: Automated Testing & CI/CD Deploy
Lanjutan Laravel Inertia Vue 3 Bagian 4 berfokus pada pengujian otomatis menyeluruh (automated testing) menggunakan Pest PHP serta penerapan jalur pengiriman berkelanjutan (CI/CD zero-downtime deployment) ke infrastruktur produksi. Mengotomatiskan verifikasi komponen Inertia dan pembaruan kode tanpa memutus koneksi WebSocket menjamin keandalan sistem Enterprise Architecture maupun platform SaaS Anda setiap kali rilis fitur baru.
Pada bagian ketiga sebelumnya, kita telah membangun orkestrasi antrean Redis Queue, ekspor laporan skala besar, dan pembaruan waktu nyata lewat Laravel Reverb. Namun, saat saya memimpin tim pengembang yang merilis pembaruan harian pada aplikasi manajemen armada klien di Cloud VPS bulan lalu, ketiadaan pengujian otomatis langsung memicu regresi fatal pada otorisasi RBAC serta memutus ratusan sesi Reverb aktif setiap kali git pull dijalankan.
Mengandalkan pengujian klik manual di peramban sebelum rilis tidak lagi memadai ketika arsitektur SPA Anda sudah melibatkan kanal siaran privat dan pekerjaan latar belakang. Dalam penutup seri panduan ini, saya akan membedah cara menulis pengujian integrasi Inertia dengan Pest, menyusun alur GitHub Actions, serta mengeksekusi zero-downtime deployment yang menjaga pekerja antrean tetap konsisten.
1. Prasyarat Teknis & Komparasi Strategi Deployment Produksi
Sebelum menyiapkan skrip pengujian dan otomasi rilis, pastikan lingkungan proyek Anda sudah menggunakan PHP 8.3+, Laravel 11 atau 12, Pest PHP v3 dengan plugin pengujian Inertia bawaan, akun repositori GitHub dengan fitur GitHub Actions aktif, serta peladen produksi Ubuntu 24.04 LTS Cloud VPS yang dikonfigurasi dengan Nginx, PHP-FPM, Redis, dan Supervisor.
Kesalahan klasik yang sering menjatuhkan reputasi pengembang di lingkungan produksi adalah menarik perubahan kode langsung ke direktori aktif aplikasi saat pengguna sedang bertransaksi. Tabel berikut membandingkan risiko metode rilis manual konvensional terhadap pendekatan Automated CI/CD Zero-Downtime:
Tahapan Rilis | Manual Git Pull di Server | CI/CD Atomic Zero-Downtime | Dampak Operasional & Keamanan |
|---|---|---|---|
Validasi Kode | Mengandalkan pengecekan manual di laptop pengembang. | Eksekusi otomatis seluruh suite Pest & cek API Security. | Mencegah celah otorisasi lolos ke peladen produksi. |
Kompilasi Aset Vite | Menjalankan | Dibangun di runner CI lalu diunggah sebagai artefak statis. | Bebas lonjakan CPU/RAM dan aset Vue tidak pernah hilang sesaat. |
Perpindahan Rilis | Menimpa berkas lama secara langsung saat HTTP berjalan. | Pengalihan symlink direktori rilis baru secara atomik. | Nol galat |
Queue & Reverb | Worker lama tetap memakai kode usang di dalam memori. | Sinyal | Worker menyelesaikan tugas berjalan lalu memuat ulang kode baru. |
2. Langkah 1: Menulis Automated Testing Inertia, RBAC & Queue dengan Pest
Keunggulan utama arsitektur Inertia.js dibandingkan SPA REST API terpisah adalah kemampuan menguji komponen frontend Vue 3 dan pengendali backend Laravel dalam satu permintaan HTTP terpadu. Dengan helper assertInertia() milik Pest, kita bisa memverifikasi nama komponen Vue yang dirender, struktur shared props otorisasi, hingga antrean ekspor Excel tanpa perlu menyalakan peramban berat.
<?php
use App\Events\ExportCompleted;
use App\Jobs\ExportProductsJob;
use App\Models\Product;
use App\Models\User;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Facades\Storage;
use Inertia\Testing\AssertableInertia as Assert;
test('admin dapat melihat halaman produk beserta shared props izin RBAC', function () {
$admin = User::factory()->create(['role' => 'admin']);
Product::factory()->count(15)->create();
$this->actingAs($admin)
->get('/products')
->assertOk()
->assertInertia(fn (Assert $page) => $page
->component('Products/Index')
->where('auth.can.create_product', true)
->where('auth.can.delete_product', true)
->has('products.data', 10)
);
});
test('staf biasa ditolak saat memaksa mutasi data produk (API Security)', function () {
$staff = User::factory()->create(['role' => 'staff']);
$product = Product::factory()->create();
$this->actingAs($staff)
->put("/products/{$product->id}", [
'name' => 'Manipulasi Harga Ilegal',
'price' => 100,
])
->assertForbidden();
});
test('ekspor produk mengirim job ke antrean dan menyiarkan event selesai', function () {
Queue::fake();
Event::fake([ExportCompleted::class]);
Storage::fake('public');
$admin = User::factory()->create(['role' => 'admin']);
Product::factory()->count(5)->create();
// 1. Pastikan endpoint HTTP langsung melempar tugas ke Redis Queue
$this->actingAs($admin)
->post('/products/export', ['search' => ''])
->assertRedirect();
Queue::assertPushed(ExportProductsJob::class, function ($job) use ($admin) {
return $job->userId === $admin->id;
});
// 2. Eksekusi job secara langsung dan verifikasi berkas CSV serta event broadcast
(new ExportProductsJob($admin->id))->handle();
Event::assertDispatched(ExportCompleted::class, function ($event) use ($admin) {
return $event->userId === $admin->id && str_ends_with($event->fileName, '.csv');
});
});Bedah Penjelasan Kode Pengujian Pest: Metode assertInertia() memeriksa muatan JSON internal yang dikirim Laravel ke komponen Vue 3, memastikan prop products.data terpaginasi tepat 10 baris serta kunci auth.can bernilai akurat. Sementara itu, kombinasi Queue::fake() dan Event::fake() memvalidasi alur asinkron dari ujung ke ujung dalam hitungan milidetik.
Tips Praktis & Optimasi Performa dari Pengalaman Saya: Aktifkan eksekusi paralel dengan menjalankan
php artisan test --parallelketika jumlah pengujian Anda sudah melewati 100 skenario. Dalam proyek SaaS berarsitektur multi-modul yang saya tangani, menjalankan pengujian paralel pada 4 inti CPU berhasil memangkas waktu tunggu pipeline CI/CD dari 4 menit 20 detik menjadi hanya 48 detik tanpa mengorbankan isolasi transaksi basis data.
3. Langkah 2: Menyusun Pipeline GitHub Actions untuk Build & Test Otomatis
Setelah seluruh skenario pengujian lolos secara lokal, kita mengotomatiskan proses verifikasi dan kompilasi aset frontend Vue 3 di peladen awan GitHub. Buat berkas .github/workflows/deploy.yml agar setiap git push ke cabang main wajib melewati gerbang pengujian sebelum menyentuh server produksi.
name: Test and Zero-Downtime Deploy
on:
push:
branches: [ main ]
jobs:
verify-and-build:
runs-on: ubuntu-latest
steps:
- name: Checkout Kode Sumber
uses: actions/checkout@v4
- name: Siapkan Runtime PHP 8.3
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
extensions: mbstring, pdo_sqlite, redis
coverage: none
- name: Instal Dependensi Composer
run: composer install --no-interaction --prefer-dist --optimize-autoloader
- name: Jalankan Automated Testing Pest
env:
APP_ENV: testing
APP_KEY: base64:2fl+Ktvkfl+Fuz4Qp/A75G2RTiWVA/ZoKZvp6fiiM10=
DB_CONNECTION: sqlite
DB_DATABASE: :memory:
run: php artisan test --parallel
- name: Kompilasi Aset Produksi Vue 3 dengan Vite
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci && npm run build
- name: Unggah Artefak Aset Terkompilasi
uses: actions/upload-artifact@v4
with:
name: vite-build-assets
path: public/build
deploy-production:
needs: verify-and-build
runs-on: ubuntu-latest
steps:
- name: Unduh Artefak Build
uses: actions/download-artifact@v4
with:
name: vite-build-assets
path: public/build
- name: Eksekusi Skrip Atomic Deployment ke Cloud VPS
uses: appleboy/ssh-action@v1.0.3
with:
host: ${{ secrets.VPS_HOST }}
username: ${{ secrets.VPS_USER }}
key: ${{ secrets.VPS_SSH_KEY }}
script: |
/var/www/deploy-atomic.shBedah Penjelasan Kode Workflow CI/CD: Tahap verify-and-build menjalankan kompilasi npm run build di mesin virtual GitHub dan menyimpannya sebagai artefak. Dengan cara ini, server produksi Anda tidak perlu memasang Node.js maupun mengorbankan ratusan megabyte RAM untuk membundel komponen Vue 3 saat jam trafik padat.

4. Langkah 3: Skrip Atomic Zero-Downtime Deployment di Cloud VPS
Di peladen produksi Cloud VPS, kita memisahkan folder penyimpanan persisten (storage dan berkas .env) dari direktori rilis kode sumber. Setiap rilis baru ditempatkan pada folder berstempel waktu, lalu tautan simbolis /var/www/app/current dialihkan secara instan menggunakan perintah ln -sfn.
#!/usr/bin/env bash
set -e
APP_DIR="/var/www/app"
RELEASES_DIR="$APP_DIR/releases"
SHARED_DIR="$APP_DIR/shared"
RELEASE_NAME=$(date +%Y%m%d%H%M%S)
NEW_RELEASE_DIR="$RELEASES_DIR/$RELEASE_NAME"
# 1. Kloning kode terbaru ke direktori rilis terisolasi
git clone --depth 1 --branch main git@github.com:organisasi/proyek-spa.git "$NEW_RELEASE_DIR"
cd "$NEW_RELEASE_DIR"
# 2. Instal paket produksi dan tautkan berkas persisten (.env & storage)
composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader
ln -nfs "$SHARED_DIR/.env" "$NEW_RELEASE_DIR/.env"
rm -rf "$NEW_RELEASE_DIR/storage"
ln -nfs "$SHARED_DIR/storage" "$NEW_RELEASE_DIR/storage"
# 3. Optimasi konfigurasi, rute, dan jalankan migrasi aman
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan migrate --force
# 4. Pengalihan symlink atomik (Zero-Downtime Switch)
ln -sfn "$NEW_RELEASE_DIR" "$APP_DIR/current"
# 5. Muat ulang OPcache PHP-FPM dan perbarui worker Queue & Reverb
sudo systemctl reload php8.3-fpm
php "$APP_DIR/current/artisan" queue:restart
php "$APP_DIR/current/artisan" reverb:restart
# 6. Bersihkan rilis lama (sisakan 3 rilis terakhir untuk rollback cepat)
ls -1dt $RELEASES_DIR/* | tail -n +4 | xargs -r rm -rfBedah Penjelasan Skrip Atomic Deployment: Pemanggilan php artisan queue:restart dan reverb:restart tidak mematikan proses secara brutal di tengah jalan. Perintah tersebut mengirimkan sinyal halus lewat tembolok Redis agar worker menyelesaikan pekerjaan ekspor yang sedang berjalan terlebih dahulu sebelum dimuat ulang oleh Supervisor dengan kode rilis terbaru.

Troubleshooting & Skenario Error Handling di Lapangan: Salah satu anomali paling membingungkan pasca-deployment adalah pengguna yang sedang membuka aplikasi SPA tiba-tiba mendapatkan galat konsol peramban
Failed to fetch dynamically imported module: /build/assets/Index-oldhash.jsatau halaman memuat ulang secara penuh setiap kali mengklik menu. Penyebabnya adalah peramban masih memegang manifes Vite lama sementara berkas JS lama telah terhapus oleh rilis baru. Pastikan Anda mengonfigurasi bloklocation ^~ /build/di Nginx dengan headerCache-Control "public, max-age=31536000, immutable"serta membiarkan Inertia mendeteksi perubahan hash versi aset secara otomatis melalui status HTTP409 Conflictbawaan middlewareHandleInertiaRequests.
5. FAQ Teknis: Pertanyaan Seputar Testing & CI/CD Laravel Inertia
1. Kapan perlu menambahkan Playwright atau Laravel Dusk jika sudah memakai Pest assertInertia()?
Gunakan assertInertia() untuk 90% pengujian logika bisnis, validasi otorisasi RBAC, dan struktur data halaman karena eksekusinya sangat cepat. Tambahkan pengujian peramban nyata seperti Playwright hanya untuk alur kritis yang bergantung pada interaksi DOM kompleks seperti penarikan berkas drag-and-drop atau verifikasi rendering grafik kanvas.
2. Mengapa OPcache PHP-FPM masih menyajikan kode lama meskipun symlink current sudah berpindah?
Secara bawaan, ekstensi OPcache di PHP-FPM menyimpan jalur resolusi symlink di dalam tembolok memori. Pastikan Anda menyertakan perintah sudo systemctl reload php8.3-fpm tepat setelah pengalihan ln -sfn serta mengonfigurasi variabel Nginx menggunakan $realpath_root alih-alih $document_root pada parameter SCRIPT_FILENAME.
3. Bagaimana cara melakukan rollback darurat jika ditemukan bug kritis setelah deployment?
Karena direktori tiga rilis sebelumnya tetap tersimpan utuh di dalam folder /var/www/app/releases, Anda cukup mengarahkan kembali tautan simbolis ln -sfn /var/www/app/releases/ID_RILIS_LAMA /var/www/app/current lalu menjalankan sudo systemctl reload php8.3-fpm untuk memulihkan sistem dalam waktu kurang dari 3 detik.
4. Apakah migrasi basis data otomatis aman dijalankan dalam skrip zero-downtime?
Aman selama Anda menerapkan aturan backward-compatible migration: jangan pernah menghapus atau mengganti nama kolom yang masih dipakai kode lama dalam satu siklus rilis yang sama. Tambahkan kolom baru terlebih dahulu pada rilis pertama, lalu hapus kolom usang setelah kode produksi sepenuhnya berhenti mengaksesnya.
Diskusi & Komentar
0Sampaikan pertanyaan teknis, masukan, atau feedback Anda seputar artikel ini.
Belum Ada Komentar
Jadilah pembaca pertama yang memulai diskusi menarik atau bertanya seputar materi artikel ini!