# 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.
