Authentication adalah fitur dengan banyak kondisi: login sukses, password salah, sudah login, sudah logout, belum verifikasi email. Setiap kondisi layak punya test sendiri, dan Laravel menyiapkan perangkat khususnya: actingAs() untuk login instan, assertAuthenticated() dan assertGuest() untuk memeriksa status, plus perilaku test client yang memudahkan alur multi-request. Chapter ini merangkum pola-pola pengujian auth yang telah kita pakai di seluruh section, lalu menutupnya dengan jebakan-jebakan yang paling sering memakan korban.

actingAs: Login Tanpa Formulir #

Saat yang mau kita uji bukan proses loginnya — melainkan halaman setelah login — actingAs() menghemat seluruh langkah formulir:

php
public function test_acting_as_membypass_formulir_login(): void
{
    $this->assertGuest();

    $budi = $this->createUserBudi();

    $response = $this->actingAs($budi)->get('/ringkasan');

    $response->assertOk();

    $this->assertAuthenticated();
    $this->assertAuthenticatedAs($budi);
}

Method assertGuest() di awal membuktikan titik nol, lalu actingAs($budi) mengikat user itu ke guard web. Dua assertion penutup berbeda peran: assertAuthenticated() hanya memastikan ada yang login, sedangkan assertAuthenticatedAs($budi) memastikan yang login benar-benar user spesifik tersebut. User di sini dibuat helper kecil yang membungkus factory dengan nilai tetap:

php
private function createUserBudi(): User
{
    return User::factory()->create([
        'name' => 'Budi',
        'email' => '[email protected]',
        'password' => 'rahasia-budi-123',
    ]);
}

Pola helper seperti ini membuat kredensial hanya hidup di satu tempat; bila password berubah, satu method yang kita perbaiki. Class test kita juga memakai trait RefreshDatabase, jadi setiap method mulai dari database bersih — user dari test sebelumnya tidak pernah mengganggu. Nilai-nilai eksplisit pada factory menjaga output tetap deterministik: nama selalu Budi, email selalu [email protected]. Method actingAs() juga menerima guard kedua sebagai argumen, actingAs($budi, 'admin'), yang kita pakai saat menguji route ber-guard khusus. Output nyatanya:

text
acting_as: status=200, isi="Ringkasan milik [email protected].", [email protected]

Menguji Alur Login Lengkap #

Untuk menguji login itu sendiri, kita kirim request persis seperti formulir sungguhan — dua skenario dalam satu method:

php
public function test_alur_login_lengkap_dari_formulir(): void
{
    $this->createUserBudi();

    // Kredensial salah ditolak
    $gagal = $this->post('/login', [
        'email' => '[email protected]',
        'password' => 'password-yang-salah',
    ]);

    $gagal->assertSessionHasErrors('email');
    $this->assertGuest();

    // Kredensial benar diterima
    $sukses = $this->post('/login', [
        'email' => '[email protected]',
        'password' => 'rahasia-budi-123',
    ]);

    $sukses->assertRedirect('/dashboard');
    $this->assertAuthenticated();
}

Output yang Dihasilkan:

text
login_flow: gagal=302, sukses=302, request_berikutnya=200

Angka 302 pada percobaan gagal adalah redirect kembali ke formulir — membawa error validasi di session, bukan halaman sukses. Perhatikan bahwa assertion-nya menargetkan field email, bukan password: controller sengaja memakai pesan umum “Email atau password salah” pada field email agar pengguna tidak mengetahui bagian mana yang salah. Nilai request_berikutnya=200 membuktikan hal berikutnya yang penting (lihat jebakan pertama di bawah).

Menguji Logout dan remember me #

Logout diuji dari dua sisi: response-nya dan status sesudahnya:

php
public function test_logout_mengembalikan_status_guest(): void
{
    $budi = $this->createUserBudi();

    $this->actingAs($budi);

    $response = $this->post('/logout');

    $response->assertRedirect('/login');
    $this->assertGuest();
}

Output yang Dihasilkan:

text
logout: status=302, setelah_logout=302, target=http://localhost:8000/login

Untuk remember me, cukup periksa cookie recaller hadir di response login — nama cookie-nya selalu berawalan remember_:

php
$response = $this->post('/login', [
    'email' => '[email protected]',
    'password' => 'rahasia-budi-123',
    'remember' => '1',
]);

$namaCookie = collect($response->headers->getCookies())
    ->map(fn ($cookie) => $cookie->getName())
    ->first(fn ($name) => str_starts_with($name, 'remember_'));

Output yang Dihasilkan:

text
remember: cookie=remember_web_59ba36addc2b2f9401580f014c7f58ea4e30989d

Skenario yang lebih dalam — cookie remember yang menghidupkan login setelah session hangus — memakai teknik refreshApplication() yang sudah kita bedah di chapter Remember Me .

Jebakan Umum Pengujian Auth #

Session menyatu antar request dalam satu test. Test client memakai satu instance aplikasi, jadi session login dari $this->post('/login', ...) otomatis terbawa ke $this->get('/ringkasan', ...) tanpa kita mengurus cookie. Itulah sebabnya request_berikutnya=200 di atas — dan mengapa urutan request dalam satu test method penting. Bila kita butuh data session awal, $this->withSession(['warna' => 'biru']) menyuntikkannya sebelum request pertama:

text
session_antar_request: data_lama="biru"

CSRF otomatis dilewati saat testing. Kita mengirim POST /login tanpa token CSRF apa pun dan tidak pernah mendapat TokenMismatchException. Middleware CSRF Laravel (PreventRequestForgery) memang mem-bypass pemeriksaan saat runningUnitTests() — kita tidak perlu mensimulasikan token di feature test.

Status auth tidak bocor antar test. Setiap method test dijalankan dengan aplikasi yang di-boot ulang, jadi actingAs() di test pertama tidak pernah membocorkan login ke test kedua:

php
public function test_setiap_test_mulai_sebagai_guest(): void
{
    $this->assertGuest();
}

Output yang Dihasilkan:

text
isolasi_antar_test: status_awal=guest

Dengan pola pengujian ini, seluruh siklus authentication kita — dari formulir login, verifikasi email, remember me, hingga manajemen session — dapat dijaga dari regresi. Peralatan feature test yang sama akan terus menemani kita di section berikutnya saat menguji fitur di atasnya. Pendalaman lebih lanjut ada di dokumentasi HTTP Tests .