Halaman terlindungi adalah tempat bug paling memalukan bercokol: tamu yang bisa membuka dasbor, logout yang tidak benar-benar mengeluarkan user, atau cookie remember me yang tidak pernah dikirim. Chapter Authentication Testing di section Authentication telah membahas dasar-dasarnya; dari perspektif testing, sekarang kita naik satu tingkat — menyusun matriks lengkap yang menguji setiap kombinasi tamu/user, request web/JSON, dan alur login-logout-remember me dalam satu suite nyata. Pendekatan matriks penting karena kegagalan auth jarang berdiri sendiri: satu middleware yang terlepas langsang merusak banyak halaman sekaligus.

actingAs: Login Instan untuk Halaman Terlindungi #

Saat yang diuji adalah halaman setelah login, actingAs($user) memanggil be($user) di balik layar untuk menetapkan user pada guard, lalu mengembalikan $this agar bisa dirantai dengan request:

php
public function test_acting_as_dengan_guard_web(): void
{
    $budi = $this->userBudi(['role' => 'admin']);

    $this->assertGuest();

    $this->actingAs($budi, 'web')
        ->get('/dashboard')
        ->assertOk()
        ->assertSee('Ringkasan milik [email protected].');

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

Tiga assertion status di atas punya peran berbeda. assertGuest() membuktikan titik nol sebelum aksi, assertAuthenticated() memastikan ada user yang login setelahnya, dan assertAuthenticatedAs($budi) mengunci identitasnya — bukan sekadar “ada yang masuk”. Argumen kedua 'web' menetapkan guard secara eksplisit; test suite kita memakainya untuk kejujuran intent, sementara aplikasi multi-guard sungguhan (misal panel admin terpisah) wajib memakainya.

Method be() juga bisa dipanggil langsung, $this->be($budi) — perilakunya sama, hanya tidak mengembalikan $this sehingga cocok saat kita ingin menetapkan user tanpa langsung merantai request:

php
public function test_be_menetapkan_user_tanpa_rantai(): void
{
    $budi = $this->userBudi();

    $this->be($budi);

    $this->get('/dashboard')->assertOk();
    $this->assertAuthenticatedAs($budi);
}

Matriks Akses sebagai Data Provider #

Kombinasi tamu/user × web/JSON adalah matriks empat sel yang paling sering kita perlukan. PHPUnit data provider membuat setiap sel menjadi test tersendiri:

php
public static function matriksDashboard(): array
{
    return [
        'tamu web dialihkan ke login' => [false, false, 302],
        'tamu json ditolak 401' => [false, true, 401],
        'user terautentikasi masuk' => [true, false, 200],
        'user terautentikasi via json masuk' => [true, true, 200],
    ];
}

#[DataProvider('matriksDashboard')]
public function test_matriks_akses_dashboard(bool $login, bool $json, int $status): void
{
    if ($login) {
        $this->actingAs($this->userBudi());
    }

    $request = $json ? $this->getJson('/dashboard') : $this->get('/dashboard');

    $request->assertStatus($status);
}

Dua baris pertama memperlihatkan perilaku ganda middleware auth: tamu web dialihkan ke halaman login (302), sedangkan request dengan header Accept: application/json dari getJson() menerima badan 401. Menambah kombinasi baru — misalnya user dengan role khusus — cukup menambah satu baris array.

Alur Login Lengkap dengan Kredensial #

Menguji login itu sendiri berarti mengirim kredensial persis seperti formulir sungguhan. Kegagalan harus membawa pesan error di session dan membiarkan status tetap tamu:

php
public function test_login_gagal_membawa_error_dan_tetap_guest(): void
{
    $this->userBudi();

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

    $this->assertGuest();
}

public function test_login_sukses_mengautentikasi_budi(): void
{
    $budi = $this->userBudi();

    $this->post('/login', [
        'email' => '[email protected]',
        'password' => 'rahasia-budi-123',
    ])->assertRedirect('/dashboard');

    $this->assertAuthenticatedAs($budi);
}

Controller login kita memakai Auth::attempt($kredensial, $request->boolean('remember')) — argumen kedua inilah yang mengaktifkan remember me.

Remember me dan Logout #

Cookie remember me selalu bernama remember_ diikuti nama guard dan hash, jadi kita memeriksanya dengan menyaring nama cookie yang terlampir di response:

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

$this->assertNotNull($namaCookie);
$this->assertSame('remember_web_', substr($namaCookie, 0, 13));

Suite berisi pasangan izinkan-tolak untuk aturan ini: test tanpa remember tidak ada cookie remember mengirim form tanpa centang dan memastikan $namaCookie bernilai null. Logout diuji dari response dan statusnya sekaligus — termasuk bukti bahwa dashboard benar-benar terkunci lagi setelahnya:

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

    $this->actingAs($budi);

    $this->post('/logout')->assertRedirect('/login');

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

Mengikuti Rantai Redirect #

Assertion assertRedirect memeriksa satu lompatan. Untuk membuktikan rantai lengkap — login berhasil, dialihkan ke dashboard, dan halaman itu benar-benar tampil — kita pakai followingRedirects() sebelum request:

php
public function test_follow_redirects_mengikuti_rantai_login(): void
{
    $this->userBudi();

    $respons = $this->followingRedirects()->post('/login', [
        'email' => '[email protected]',
        'password' => 'rahasia-budi-123',
    ]);

    $respons->assertOk()->assertSee('Ringkasan milik [email protected].');
}

Method ini membuat test client menelusuri setiap 302 sampai respons akhir, sehingga kita bisa meng-assert isi halaman tujuan tanpa request manual kedua.

Seluruh Suite Berjalan #

bash
php artisan test tests/Feature/AutentikasiMatrixTest.php

Output yang Dihasilkan:

text
  PASS  Tests\Feature\AutentikasiMatrixTest
  ✓  matriks akses dashboard with data set "tamu web dialihkan ke login"  0.15s
  ✓  matriks akses dashboard with data set "tamu json ditolak 401"        0.01s
  ✓  matriks akses dashboard with data set "user terautentikasi masuk"    0.02s
  ✓  matriks akses dashboard with data set "user terautentikasi via json…  0.01s
  ✓  login gagal membawa error dan tetap guest                            0.21s
  ✓  login sukses mengautentikasi budi                                    0.01s
  ✓  remember me mengantre cookie remember                                0.01s
  ✓  tanpa remember tidak ada cookie remember                             0.01s
  ✓  be menetapkan user tanpa rantai                                      0.01s
  ✓  logout mengembalikan status guest                                    0.01s
  ✓  follow redirects mengikuti rantai login                              0.01s
  ✓  acting as dengan guard web                                           0.01s

  Tests:    12 passed (30 assertions)
  Duration: 0.56s

Authentication menjawab “siapa Anda”, tetapi aplikasi nyata langsung bertanya lanjutan: “dan Anda boleh apa?”. Jawaban itu — gate, policy, dan matriks peran — kita uji di chapter Authorization Testing berikutnya. Rujukan assertion lengkapnya ada di dokumentasi HTTP Tests .