diff --git a/app/Filament/Resources/Learning/ClassSessions/Actions/GenerateSessionsAction.php b/app/Filament/Resources/Learning/ClassSessions/Actions/GenerateSessionsAction.php index eb3560c..2d7df20 100644 --- a/app/Filament/Resources/Learning/ClassSessions/Actions/GenerateSessionsAction.php +++ b/app/Filament/Resources/Learning/ClassSessions/Actions/GenerateSessionsAction.php @@ -22,6 +22,7 @@ protected function setUp(): void parent::setUp(); $this->label('Generate Sesi') + ->visible(fn () => auth()->user()->can('Create:ClassSession')) ->color(Color::Orange) ->requiresConfirmation() ->modalHeading('Generate Sesi Pembelajaran') diff --git a/tests/Feature/ClassSessionTest.php b/tests/Feature/ClassSessionTest.php new file mode 100644 index 0000000..3212e44 --- /dev/null +++ b/tests/Feature/ClassSessionTest.php @@ -0,0 +1,196 @@ +value); + Role::findOrCreate(RoleEnum::Kosma->value); + Role::findOrCreate(RoleEnum::Student->value); + + $permissions = [ + 'ViewAny:ClassSession', + 'View:ClassSession', + 'Create:ClassSession', + 'Update:ClassSession', + 'Delete:ClassSession', + ]; + + foreach ($permissions as $permission) { + Permission::findOrCreate($permission); + } +}); + +describe('Class Session Authorization', function () { + it('restricts actions to Developer and Kosma only, while allowing all to view', function () { + $developer = User::factory()->create(); + $developer->assignRole(RoleEnum::Developer); + $developer->givePermissionTo(['ViewAny:ClassSession', 'View:ClassSession', 'Create:ClassSession']); + + $kosma = User::factory()->create(); + $kosma->assignRole(RoleEnum::Kosma); + $kosma->givePermissionTo(['ViewAny:ClassSession', 'View:ClassSession', 'Create:ClassSession']); + + $regularStudent = User::factory()->create(); + $regularStudent->assignRole(RoleEnum::Student); + $regularStudent->givePermissionTo(['ViewAny:ClassSession', 'View:ClassSession']); + + $course = Course::factory()->create(['semester' => app(GeneralSettings::class)->current_semester]); + + // All can view the list (dashboard) + $this->actingAs($developer); + Livewire::test(ManageClassSessions::class)->assertSuccessful(); + + $this->actingAs($kosma); + Livewire::test(ManageClassSessions::class)->assertSuccessful(); + + $this->actingAs($regularStudent); + Livewire::test(ManageClassSessions::class)->assertSuccessful(); + + // Check actions on ListCourseSessions page + $this->actingAs($developer); + Livewire::test(ListCourseSessions::class, ['courseId' => $course->id]) + ->assertActionVisible('generateSessions'); + + $this->actingAs($kosma); + Livewire::test(ListCourseSessions::class, ['courseId' => $course->id]) + ->assertActionVisible('generateSessions'); + + $this->actingAs($regularStudent); + Livewire::test(ListCourseSessions::class, ['courseId' => $course->id]) + ->assertActionHidden('generateSessions'); + }); +}); + +describe('Class Session Model', function () { + it('has necessary relationships', function () { + $session = ClassSession::factory()->create(); + + expect($session->course)->toBeInstanceOf(Course::class); + expect($session->attendances())->toBeInstanceOf(HasMany::class); + expect($session->materials())->toBeInstanceOf(HasMany::class); + expect($session->assignments())->toBeInstanceOf(HasMany::class); + }); + + it('supports Soft Deletes', function () { + $session = ClassSession::factory()->create(); + $session->delete(); + + expect($session->trashed())->toBeTrue(); + expect(ClassSession::find($session->id))->toBeNull(); + }); +}); + +describe('Class Session Special Features', function () { + beforeEach(function () { + $user = User::factory()->create(); + $user->assignRole(RoleEnum::Developer); + $user->givePermissionTo(['ViewAny:ClassSession', 'View:ClassSession', 'Update:ClassSession', 'Create:ClassSession', 'Delete:ClassSession']); + $this->actingAs($user); + $this->currentSemester = app(GeneralSettings::class)->current_semester; + }); + + it('can generate sessions automatically', function () { + $course = Course::factory()->create(['semester' => $this->currentSemester]); + + // Need a schedule to generate sessions + CourseSchedule::factory()->create([ + 'course_id' => $course->id, + 'start_time' => '08:00', + 'end_time' => '10:00', + ]); + + Livewire::test(ListCourseSessions::class, ['courseId' => $course->id]) + ->callAction('generateSessions', [ + 'total_sessions' => 2, + 'start_date' => now()->toDateString(), + ]) + ->assertHasNoActionErrors(); + + expect($course->classSessions()->count())->toBe(2); + + $this->assertDatabaseHas('class_sessions', [ + 'course_id' => $course->id, + 'session_number' => 1, + 'start_time' => now()->format('Y-m-d').' 08:00:00', + 'end_time' => now()->format('Y-m-d').' 10:00:00', + ]); + }); + + it('can update a session', function () { + $course = Course::factory()->create(['semester' => $this->currentSemester]); + $session = ClassSession::factory()->create(['course_id' => $course->id, 'session_number' => 1]); + + Livewire::test(ListCourseSessions::class, ['courseId' => $course->id]) + ->callAction('editSession', [ + 'session_number' => 5, + 'date' => now()->toDateString(), + 'start_time' => '13:00', + 'end_time' => '15:00', + ], ['session' => $session->id]) + ->assertHasNoActionErrors(); + + expect($session->refresh()->session_number)->toBe(5); + }); + + it('can share attendance information', function () { + $course = Course::factory()->create(['semester' => $this->currentSemester]); + $session = ClassSession::factory()->create(['course_id' => $course->id]); + + Livewire::test(ListCourseSessions::class, ['courseId' => $course->id]) + ->callAction('shareAttendance', [], ['session' => $session->id]) + ->assertHasNoActionErrors(); + }); + + it('can share assignment information', function () { + $course = Course::factory()->create(['semester' => $this->currentSemester]); + $session = ClassSession::factory()->create(['course_id' => $course->id]); + + Livewire::test(ListCourseSessions::class, ['courseId' => $course->id]) + ->callAction('shareAssignment', [], ['session' => $session->id]) + ->assertHasNoActionErrors(); + }); + + it('can show modals for attendance, materials and assignments', function () { + $course = Course::factory()->create(['semester' => $this->currentSemester]); + $session = ClassSession::factory()->create(['course_id' => $course->id]); + + Livewire::test(ListCourseSessions::class, ['courseId' => $course->id]) + ->assertActionVisible('viewAttendance') + ->assertActionVisible('viewMaterials') + ->assertActionVisible('viewAssignments'); + }); +}); + +describe('Search and Dashboard Filter', function () { + beforeEach(function () { + $user = User::factory()->create(); + $user->assignRole(RoleEnum::Developer); + $user->givePermissionTo(['ViewAny:ClassSession']); + $this->actingAs($user); + $this->currentSemester = app(GeneralSettings::class)->current_semester; + }); + + it('can search courses in the session dashboard', function () { + $target = Course::factory()->create(['name' => 'Session Specific Course', 'semester' => $this->currentSemester]); + $other = Course::factory()->create(['name' => 'Other Course', 'semester' => $this->currentSemester]); + + Livewire::test(ManageClassSessions::class) + ->set('search', 'Session Specific Course') + ->assertSee($target->name) + ->assertDontSee($other->name); + }); +});