# Testing Guideline (Pest + Laravel + Livewire 3) Dokumen ini adalah **aturan wajib** dan **acuan tunggal** untuk seluruh penulisan testing. Tujuannya: - Konsistensi Mutlak (Uniformity) - Realistis sesuai flow aplikasi (No shortcuts) - Mudah dipahami AI dan manusia - Tidak ada logic testing yang "ngawang" atau "magic" --- ## 1. Tech Stack & Referensi Resmi Wajib mengacu pada dokumen berikut: - Pest PHP → https://pestphp.com - Livewire 3 Testing → https://livewire.laravel.com/docs/3.x/testing - Laravel Testing → https://laravel.com/docs/testing Framework lain, pendekatan custom, atau eksperimen **DILARANG KERAS**. --- ## 2. Aturan Global Testing (STRICT MODE) ### 2.1 Struktur Wajib (Seragam) - **SELALU gunakan `beforeEach()`** untuk setup awal. - Tidak boleh membuat data user secara inline di dalam test. - Semua logic setup yang berulang **harus di-extract ke helper method** di `Pest.php`. ### 2.2 Strict Data Generation (Factory ONLY) - **WAJIB menggunakan Factory** untuk semua pembuatan data database. - **DILARANG** menggunakan `new Model()` atau `Model::create()` secara manual di dalam file test. - Jika butuh data spesifik, gunakan `.state()` atau `factory(['key' => 'value'])`. - **Predictable Data**: Gunakan hardcoded string atau value yang pasti (misal: `test@example.com`, `Secret123!`) di dalam test assertion daripada mengandalkan random data dari factory yang tidak terukur. Contoh dasar setup: ```php beforeEach(function () { $this->setupUser(); }); ``` Helper `setupUser` di `Pest.php` (CONTOH STANDAR): ```php function setupUser(array $overrides = []): void { $test = test(); $test->user = User::factory()->create($overrides); $test->employee = Employee::factory()->for($test->user)->create(); $test->outlet = Outlet::factory()->create(); $test->user->outlets()->attach($test->outlet); $test->openingHours = OpeningHour::factory()->count(3)->create(); $test->outlet->openingHours()->attach($test->openingHours->pluck('id')->toArray()); } ``` --- ## 3. Business Rules (NON-NEGOTIABLE) ### 3.1 Relasi User & Role Flow HARUS REALISTIS, tidak boleh ada shortcut logic: - **User -> Employee**: One-to-one (Wajib ada). - **User -> Outlets**: Many-to-many (Wajib minimal 1 outlet). - **Outlet -> Opening Hours**: Wajib ada data jam operasional. - **Role/Permissions**: Harus di-assign secara eksplisit di setup jika test tersebut mengecek otorisasi. Jika ada test yang melompati relasi ini (misal: User tanpa Outlet tapi bisa transaksi) → **TEST TIDAK VALID**. --- ## 4. Struktur Folder & File ### 4.1 Pemisahan Component (WAJIB) Setiap Livewire Component harus memiliki file test sendiri: ``` tests/Feature/ ├── Auth/ │ ├── LoginTest.php │ └── ForgotPasswordTest.php ├── User/ │ ├── IndexTest.php │ ├── CreateTest.php │ └── EditTest.php ``` ❌ **DILARANG** menggabungkan Create/Update/Delete dalam satu file jika component-nya berbeda. --- ## 5. Scope Testing (STRICT CHECKLIST) ### 5.1 Otorisasi (The "Can/Cannot" Principle) Wajib test setiap level akses: - Role A bisa akses? - Role B tidak bisa akses? - Gunakan `actingAs($this->user)`. ### 5.2 Validasi (Granular Testing) - Test **setiap baris** aturan validasi yang ada di Form Object atau Component. - Wajib test: `required`, `email`, `unique`, `min/max`. - Gunakan predictable invalid data (misal: email tanpa '@'). ### 5.3 UI & State Verification - `assertSee()`: Pastikan text penting muncul. - `assertSet()`: Pastikan property Livewire berubah. - `assertDispatched()`: Pastikan event (toast/modal) terpanggil. - **Database Verification**: Gunakan `assertDatabaseHas()` untuk memastikan data benar-benar tersimpan/berubah. --- ## 6. Penamaan Test (FORMAT BAKU) Gunakan kalimat yang mendeskripsikan perilaku (behavioral): - `it('renders the login page correctly')` - `it('shows validation error when email is empty')` - `it('redirects to dashboard after successful login')` - `it('cannot delete user if not super-admin')` --- ## 7. Prinsip "Zero Assumption" 1. **Satu test = Satu Skenario**: Jangan menumpuk banyak assertion yang tidak relevan dalam satu `it()`. 2. **Hardcoded Assertions**: Jangan bandingkan data dengan data factory yang random. Bandingkan dengan value yang dimasukkan ke `->set()`. 3. **Clean Database**: Selalu gunakan `RefreshDatabase`. --- ## 8. Standarisasi AI & Developer Jika Anda (AI atau Developer) menemukan kode yang tidak mengikuti standar ini: - **TOLAK** implementasi tersebut. - **REFACTOR** hingga sesuai guidelines. - **JANGAN** pernah melakukan improvisasi yang mengurangi ketatnya aturan ini.