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:
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:
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:
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:
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:
$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:
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:
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 #
php artisan test tests/Feature/AutentikasiMatrixTest.phpOutput yang Dihasilkan:
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.56sAuthentication 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 .