sispace/tests/Feature/MaterialTest.php

249 lines
8.8 KiB
PHP

<?php
use App\Enums\RoleEnum;
use App\Filament\Resources\Learning\Materials\Pages\ManageMaterials;
use App\Models\ClassSession;
use App\Models\Course;
use App\Models\Material;
use App\Models\User;
use App\Settings\GeneralSettings;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Livewire\Livewire;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
/**
* Setup necessary roles and permissions
*/
beforeEach(function () {
Role::findOrCreate(RoleEnum::Developer->value);
Role::findOrCreate(RoleEnum::Kosma->value);
Role::findOrCreate(RoleEnum::Student->value);
$permissions = [
'ViewAny:Material',
'Create:Material',
'View:Material',
'Update:Material',
'Delete:Material',
'Restore:Material',
'ForceDelete:Material',
'RestoreAny:Material',
'ForceDeleteAny:Material',
];
foreach ($permissions as $permission) {
Permission::findOrCreate($permission);
}
Storage::fake('public');
});
describe('Material Authorization', function () {
it('allows all roles to view the list but restricts actions to Developer and Kosma', function () {
$developer = User::factory()->create();
$developer->assignRole(RoleEnum::Developer);
$developer->givePermissionTo(['ViewAny:Material', 'Create:Material']);
$kosma = User::factory()->create();
$kosma->assignRole(RoleEnum::Kosma);
$kosma->givePermissionTo(['ViewAny:Material', 'Create:Material']);
$regularStudent = User::factory()->create();
$regularStudent->assignRole(RoleEnum::Student);
$regularStudent->givePermissionTo('ViewAny:Material');
$this->actingAs($developer);
Livewire::test(ManageMaterials::class)->assertSuccessful()
->assertActionVisible('createMaterial');
$this->actingAs($kosma);
Livewire::test(ManageMaterials::class)->assertSuccessful()
->assertActionVisible('createMaterial');
$this->actingAs($regularStudent);
Livewire::test(ManageMaterials::class)->assertSuccessful()
->assertActionHidden('createMaterial');
});
});
describe('Material Model', function () {
it('has relationships with Course and ClassSession', function () {
$material = Material::factory()->create();
expect($material->course)->toBeInstanceOf(Course::class);
expect($material->classSession)->toBeInstanceOf(ClassSession::class);
});
it('supports Soft Deletes', function () {
$material = Material::factory()->create();
$material->delete();
expect($material->trashed())->toBeTrue();
expect(Material::find($material->id))->toBeNull();
});
});
describe('Material CRUD', function () {
beforeEach(function () {
$user = User::factory()->create();
$user->assignRole(RoleEnum::Developer);
$user->givePermissionTo(['ViewAny:Material', 'Create:Material', 'Update:Material', 'Delete:Material']);
$this->actingAs($user);
$this->currentSemester = app(GeneralSettings::class)->current_semester;
});
it('can create a material', function () {
$course = Course::factory()->create(['semester' => $this->currentSemester]);
$file = UploadedFile::fake()->create('test.pdf', 100, 'application/pdf');
Livewire::test(ManageMaterials::class)
->callAction('createMaterial', [
'course_id' => $course->id,
'title' => 'Introduction to PHP',
'description' => 'Basics of PHP programming.',
'pdf' => [$file],
])
->assertHasNoActionErrors();
$this->assertDatabaseHas('materials', [
'course_id' => $course->id,
'title' => 'Introduction to PHP',
]);
});
it('can update material data', function () {
$material = Material::factory()->create(['class_session_id' => null]);
$material->course->update(['semester' => $this->currentSemester]);
$file = UploadedFile::fake()->create('updated.pdf', 100, 'application/pdf');
Livewire::test(ManageMaterials::class)
->callTableAction('editMaterial', $material, [
'title' => 'Updated Title',
'course_id' => $material->course_id,
'pdf' => [$file],
])
->assertHasNoTableActionErrors();
expect($material->refresh()->title)->toBe('Updated Title');
});
it('can delete a material', function () {
$material = Material::factory()->create();
$material->course->update(['semester' => $this->currentSemester]);
Livewire::test(ManageMaterials::class)
->callTableAction('delete', $material);
expect(Material::find($material->id))->toBeNull();
});
});
describe('Material Restoration and Bulk Actions', function () {
beforeEach(function () {
$user = User::factory()->create();
$user->assignRole(RoleEnum::Developer);
$user->givePermissionTo(['ViewAny:Material', 'Restore:Material', 'RestoreAny:Material']);
$this->actingAs($user);
$this->currentSemester = app(GeneralSettings::class)->current_semester;
});
it('can restore a deleted material', function () {
$material = Material::factory()->create();
$material->course->update(['semester' => $this->currentSemester]);
$material->delete();
Livewire::test(ManageMaterials::class)
->filterTable('trashed', 'only')
->callTableAction('restore', $material);
expect($material->refresh()->trashed())->toBeFalse();
});
it('can perform bulk actions (Delete & Restore)', function () {
$materials = Material::factory()->count(3)->create();
foreach ($materials as $m) {
$m->course->update(['semester' => $this->currentSemester]);
}
// Bulk Delete
Livewire::test(ManageMaterials::class)
->callTableBulkAction('delete', $materials);
foreach ($materials as $material) {
expect($material->refresh()->trashed())->toBeTrue();
}
// Bulk Restore
Livewire::test(ManageMaterials::class)
->filterTable('trashed', 'only')
->callTableBulkAction('restore', $materials);
foreach ($materials as $material) {
expect($material->refresh()->trashed())->toBeFalse();
}
});
});
describe('Search, Sorting, and Filters', function () {
beforeEach(function () {
$user = User::factory()->create();
$user->assignRole(RoleEnum::Developer);
$user->givePermissionTo(['ViewAny:Material']);
$this->actingAs($user);
$this->currentSemester = app(GeneralSettings::class)->current_semester;
});
it('can search materials by title', function () {
$target = Material::factory()->create(['title' => 'Specific Material Title']);
$target->course->update(['semester' => $this->currentSemester]);
$other = Material::factory()->create(['title' => 'Generic Title']);
$other->course->update(['semester' => $this->currentSemester]);
Livewire::test(ManageMaterials::class)
->searchTable('Specific Material Title')
->assertCanSeeTableRecords([$target])
->assertCanNotSeeTableRecords([$other]);
});
it('can filter materials by course', function () {
$course1 = Course::factory()->create(['semester' => $this->currentSemester]);
$course2 = Course::factory()->create(['semester' => $this->currentSemester]);
$m1 = Material::factory()->create(['course_id' => $course1->id]);
$m1->course->update(['semester' => $this->currentSemester]);
$m2 = Material::factory()->create(['course_id' => $course2->id]);
$m2->course->update(['semester' => $this->currentSemester]);
Livewire::test(ManageMaterials::class)
->filterTable('course_id', $course1->id)
->assertCanSeeTableRecords([$m1])
->assertCanNotSeeTableRecords([$m2]);
});
});
describe('Material View Actions', function () {
beforeEach(function () {
$user = User::factory()->create();
$user->assignRole(RoleEnum::Developer);
$user->givePermissionTo(['ViewAny:Material', 'View:Material']);
$this->actingAs($user);
$this->currentSemester = app(GeneralSettings::class)->current_semester;
});
it('can see viewMaterial action when media exists', function () {
$material = Material::factory()->create();
$material->course->update(['semester' => $this->currentSemester]);
$material->addMedia(UploadedFile::fake()->create('lecture.pdf', 100))
->toMediaCollection('materials');
expect($material->hasMedia('materials'))->toBeTrue();
Livewire::test(ManageMaterials::class)
->assertTableActionVisible('viewMaterial', $material);
});
});