first
This commit is contained in:
175
tests/Feature/AttendanceModuleTest.php
Normal file
175
tests/Feature/AttendanceModuleTest.php
Normal file
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\DaerahMengundi;
|
||||
use App\Models\Election;
|
||||
use App\Models\ExportLog;
|
||||
use App\Models\Position;
|
||||
use App\Models\PusatMengundi;
|
||||
use App\Models\StaffAssignment;
|
||||
use App\Models\User;
|
||||
use Database\Seeders\DatabaseSeeder;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AttendanceModuleTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_ppm_can_record_attendance_for_own_pusat(): void
|
||||
{
|
||||
$this->seed(DatabaseSeeder::class);
|
||||
|
||||
$ppm = User::query()->where('email', 'ppm@prn.local')->firstOrFail();
|
||||
$pusat = PusatMengundi::query()->where('code', 'PM001')->firstOrFail();
|
||||
$this->activateAttendance($pusat->election);
|
||||
$assignment = StaffAssignment::query()
|
||||
->where('pusat_mengundi_id', $pusat->id)
|
||||
->where('status', 'active')
|
||||
->firstOrFail();
|
||||
|
||||
$this->actingAs($ppm)
|
||||
->post(route('ppm.attendance.store', $pusat), [
|
||||
'attendance' => [
|
||||
$assignment->id => [
|
||||
'status' => 'present',
|
||||
'check_in_time' => now()->format('Y-m-d H:i:s'),
|
||||
'note' => 'Hadir awal.',
|
||||
],
|
||||
],
|
||||
])
|
||||
->assertRedirect(route('ppm.attendance.show', $pusat));
|
||||
|
||||
$this->assertDatabaseHas('attendances', [
|
||||
'staff_assignment_id' => $assignment->id,
|
||||
'pusat_mengundi_id' => $pusat->id,
|
||||
'status' => 'present',
|
||||
'recorded_by_user_id' => $ppm->id,
|
||||
'note' => 'Hadir awal.',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_ppm_cannot_record_attendance_for_other_pusat(): void
|
||||
{
|
||||
$this->seed(DatabaseSeeder::class);
|
||||
|
||||
$ppm = User::query()->where('email', 'ppm@prn.local')->firstOrFail();
|
||||
$otherPusat = $this->otherPusat();
|
||||
$this->activateAttendance($otherPusat->election);
|
||||
$position = Position::query()->where('code', 'PAPM')->firstOrFail();
|
||||
$assignment = StaffAssignment::query()->create([
|
||||
'election_id' => $otherPusat->election_id,
|
||||
'position_id' => $position->id,
|
||||
'pusat_mengundi_id' => $otherPusat->id,
|
||||
'status' => 'active',
|
||||
'assigned_at' => now(),
|
||||
'source' => 'test',
|
||||
]);
|
||||
|
||||
$this->actingAs($ppm)
|
||||
->post(route('ppm.attendance.store', $otherPusat), [
|
||||
'attendance' => [
|
||||
$assignment->id => ['status' => 'present'],
|
||||
],
|
||||
])
|
||||
->assertSessionHasErrors('pusat_mengundi_id');
|
||||
|
||||
$this->assertDatabaseMissing('attendances', [
|
||||
'staff_assignment_id' => $assignment->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_attendance_recording_requires_active_attendance_module(): void
|
||||
{
|
||||
$this->seed(DatabaseSeeder::class);
|
||||
|
||||
$ppm = User::query()->where('email', 'ppm@prn.local')->firstOrFail();
|
||||
$pusat = PusatMengundi::query()->where('code', 'PM001')->firstOrFail();
|
||||
$assignment = StaffAssignment::query()
|
||||
->where('pusat_mengundi_id', $pusat->id)
|
||||
->where('status', 'active')
|
||||
->firstOrFail();
|
||||
|
||||
$this->actingAs($ppm)
|
||||
->post(route('ppm.attendance.store', $pusat), [
|
||||
'attendance' => [
|
||||
$assignment->id => ['status' => 'present'],
|
||||
],
|
||||
])
|
||||
->assertSessionHasErrors('attendance');
|
||||
}
|
||||
|
||||
public function test_admin_can_view_attendance_dashboard_and_detail(): void
|
||||
{
|
||||
$this->seed(DatabaseSeeder::class);
|
||||
|
||||
$admin = User::query()->where('email', 'admin@prn.local')->firstOrFail();
|
||||
$pusat = PusatMengundi::query()->where('code', 'PM001')->firstOrFail();
|
||||
$this->activateAttendance($pusat->election);
|
||||
|
||||
$this->actingAs($admin)
|
||||
->get(route('admin.attendance.index'))
|
||||
->assertOk()
|
||||
->assertSee($pusat->name);
|
||||
|
||||
$this->actingAs($admin)
|
||||
->get(route('admin.attendance.show', $pusat))
|
||||
->assertOk()
|
||||
->assertSee('Ringkasan Mengikut Jawatan');
|
||||
}
|
||||
|
||||
public function test_attendance_export_creates_export_log(): void
|
||||
{
|
||||
Storage::fake('local');
|
||||
$this->seed(DatabaseSeeder::class);
|
||||
|
||||
$admin = User::query()->where('email', 'admin@prn.local')->firstOrFail();
|
||||
$pusat = PusatMengundi::query()->where('code', 'PM001')->firstOrFail();
|
||||
|
||||
$this->actingAs($admin)
|
||||
->get(route('admin.attendance.export', $pusat))
|
||||
->assertOk();
|
||||
|
||||
$exportLog = ExportLog::query()->where('report_type', 'attendance_detail_by_pusat')->firstOrFail();
|
||||
|
||||
$this->assertSame($admin->id, $exportLog->generated_by_user_id);
|
||||
$this->assertSame($pusat->election_id, $exportLog->election_id);
|
||||
Storage::disk('local')->assertExists($exportLog->path);
|
||||
}
|
||||
|
||||
public function test_admin_kewangan_cannot_access_attendance_dashboard(): void
|
||||
{
|
||||
$this->seed(DatabaseSeeder::class);
|
||||
|
||||
$finance = User::query()->where('email', 'kewangan@prn.local')->firstOrFail();
|
||||
|
||||
$this->actingAs($finance)
|
||||
->get(route('admin.attendance.index'))
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
private function activateAttendance(Election $election): void
|
||||
{
|
||||
$election->settings()->update([
|
||||
'is_attendance_active' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
private function otherPusat(): PusatMengundi
|
||||
{
|
||||
$election = Election::query()->where('code', 'PRN2026')->firstOrFail();
|
||||
$daerah = DaerahMengundi::factory()->forElection($election)->create([
|
||||
'code' => 'D888',
|
||||
'name' => 'Daerah Attendance Lain',
|
||||
]);
|
||||
|
||||
return PusatMengundi::factory()->create([
|
||||
'election_id' => $election->id,
|
||||
'daerah_mengundi_id' => $daerah->id,
|
||||
'code' => 'PM888',
|
||||
'name' => 'Pusat Attendance Lain',
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user