simedkom/docs/testing-guidlines.md

5.7 KiB

Panduan Pengujian (Testing Guidelines) Filament Resource

Dokumen ini berisi standar dan pola pengujian untuk semua Filament Resource dalam aplikasi ini menggunakan Pest dan Livewire Test Utility.


1. Persiapan (Setup)

Setiap file test harus menggunakan trait RefreshDatabase dan menyiapkan environment di dalam blok beforeEach.

Komponen Wajib Setup:

  • User: Buat user aktif menggunakan factory.
  • Permissions: Daftarkan permission yang relevan dengan Resource (format: Action:Model).
  • Role: Assign permission ke user tersebut.
uses(RefreshDatabase::class);

beforeEach(function () {
    $this->user = User::factory()->create(['is_active' => IsActive::ACTIVE]);

    // Contoh untuk Resource 'Post'
    $permissions = [
        'ViewAny:Post',
        'Create:Post',
        'Update:Post',
        'Delete:Post',
        'Restore:Post',
        'ForceDelete:Post',
    ];

    foreach ($permissions as $permission) {
        Permission::firstOrCreate(['name' => $permission, 'guard_name' => 'web']);
    }

    $this->user->givePermissionTo($permissions);
});

2. Kategori Pengujian

A. Rendering & Otorisasi

Memastikan halaman dapat diakses oleh user yang berhak dan ditolak untuk yang tidak berhak.

  • Positif: assertSuccessful().
  • Negatif: assertForbidden().
test('halaman list dapat diakses', function () {
    $this->actingAs($this->user);
    Livewire::test(ManagePosts::class)->assertSuccessful();
});

test('user tanpa akses ditolak mengakses halaman', function () {
    $guest = User::factory()->create();
    $this->actingAs($guest);
    Livewire::test(ManagePosts::class)->assertForbidden();
});

B. Menampilkan Data (Listing)

Memastikan tabel menampilkan data yang sesuai dan filter berfungsi (jika ada).

test('dapat menampilkan daftar data', function () {
    $posts = Post::factory()->count(3)->create();
    $this->actingAs($this->user);

    Livewire::test(ManagePosts::class)
        ->call('loadTable') // Jika menggunakan deferLoading
        ->assertCanSeeTableRecords($posts);
});

C. Operasi CRUD (Create, Read, Update, Delete)

Gunakan mountAction untuk action di level halaman (seperti 'create') dan mountTableAction untuk action di baris tabel (seperti 'edit').

// Create
test('dapat membuat data baru', function () {
    $this->actingAs($this->user);
    Livewire::test(ManagePosts::class)
        ->mountAction('create')
        ->setActionData(['title' => 'Judul Baru'])
        ->callMountedAction()
        ->assertHasNoActionErrors();

    $this->assertDatabaseHas('posts', ['title' => 'Judul Baru']);
});

// Edit
test('dapat mengubah data', function () {
    $post = Post::factory()->create();
    $this->actingAs($this->user);

    Livewire::test(ManagePosts::class)
        ->mountTableAction('edit', $post)
        ->setActionData(['title' => 'Judul Update'])
        ->callMountedTableAction()
        ->assertHasNoActionErrors();

    expect($post->refresh()->title)->toBe('Judul Update');
});

D. Validasi Form

Uji setiap aturan validasi kritis (required, unique, max, dll).

test('validasi: judul wajib diisi', function () {
    $this->actingAs($this->user);
    Livewire::test(ManagePosts::class)
        ->mountAction('create')
        ->setActionData(['title' => ''])
        ->callMountedAction()
        ->assertHasActionErrors(['title' => 'required']);
});

E. Soft Delete & Trash

Pengujian untuk fitur restore dan force delete biasanya membutuhkan role Developer.

test('dapat menghapus data (soft delete)', function () {
    $post = Post::factory()->create();
    $this->actingAs($this->user);

    Livewire::test(ManagePosts::class)->callTableAction('delete', $post);
    $this->assertSoftDeleted($post);
});

test('dapat merestore data yang dihapus', function () {
    // Berikan role Developer agar bisa melihat filter 'trashed'
    $roleDev = Role::firstOrCreate(['name' => RoleEnum::DEVELOPER->value]);
    $this->user->assignRole($roleDev);

    $post = Post::factory()->create(['deleted_at' => now()]);
    $this->actingAs($this->user);

    Livewire::test(ManagePosts::class)
        ->filterTable('trashed', 'with')
        ->callTableAction('restore', $post);

    $this->assertDatabaseHas('posts', ['id' => $post->id, 'deleted_at' => null]);
});

F. Fitur Khusus: Filter & Toggle

Jangan lupa menguji kolom toggle dan filter kustom.

// Toggle Status
test('dapat mengubah status is_active via toggle', function () {
    $post = Post::factory()->create(['is_active' => false]);
    $this->actingAs($this->user);

    Livewire::test(ManagePosts::class)
        ->call('updateTableColumnState', 'is_active', $post->id, true);

    expect($post->refresh()->is_active)->toBeTrue();
});

// Filter
test('dapat memfilter data berdasarkan kategori', function () {
    $postA = Post::factory()->create(['category' => 'A']);
    $postB = Post::factory()->create(['category' => 'B']);
    
    $this->actingAs($this->user);

    Livewire::test(ManagePosts::class)
        ->filterTable('category', 'A')
        ->assertCanSeeTableRecords([$postA])
        ->assertCanNotSeeTableRecords([$postB]);
});

3. Praktik Terbaik (Best Practices)

  1. Granularitas: Satu test case fokus pada satu aturan validasi atau satu alur logika.
  2. Keamanan: Selalu sertakan test untuk user yang tidak memiliki permission (unauthorized).
  3. Clean Up: Gunakan RefreshDatabase agar data antar test tidak saling mengganggu.
  4. Factory: Pastikan factory menghasilkan data yang valid sesuai integritas database.
  5. UI State: Gunakan assertActionHidden() untuk memastikan tombol (seperti 'edit' atau 'delete') benar-benar tersembunyi bagi user yang tidak punya akses.