test: add feature tests for Material management and create factories for Material and ClassSession models
This commit is contained in:
parent
a37ccd64df
commit
7b1d547f11
28
database/factories/ClassSessionFactory.php
Normal file
28
database/factories/ClassSessionFactory.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\Course;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\ClassSession>
|
||||
*/
|
||||
class ClassSessionFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'course_id' => Course::factory(),
|
||||
'session_number' => fake()->unique(true)->numberBetween(1, 16),
|
||||
'date' => fake()->date(),
|
||||
'start_time' => '08:00',
|
||||
'end_time' => '10:00',
|
||||
];
|
||||
}
|
||||
}
|
||||
28
database/factories/MaterialFactory.php
Normal file
28
database/factories/MaterialFactory.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Models\ClassSession;
|
||||
use App\Models\Course;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\Material>
|
||||
*/
|
||||
class MaterialFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'course_id' => Course::factory(),
|
||||
'class_session_id' => ClassSession::factory(),
|
||||
'title' => fake()->sentence(3),
|
||||
'description' => fake()->paragraph(),
|
||||
];
|
||||
}
|
||||
}
|
||||
248
tests/Feature/MaterialTest.php
Normal file
248
tests/Feature/MaterialTest.php
Normal file
@ -0,0 +1,248 @@
|
||||
<?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);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user