127 خطوط
8.6 KiB
PHP
127 خطوط
8.6 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Manager;
|
|
|
|
use App\Models\User;
|
|
use App\Modules\Assessments\Domain\Assessment;
|
|
use App\Modules\Assessments\Domain\AssessmentAttempt;
|
|
use App\Modules\Assignments\Domain\Assignment;
|
|
use App\Modules\Courses\Domain\Course;
|
|
use App\Modules\Courses\Domain\CourseVersion;
|
|
use App\Modules\Courses\Domain\Enums\CourseVersionStatus;
|
|
use App\Modules\Identity\Domain\Enums\UserRole;
|
|
use App\Modules\Learner\Domain\LearningEvent;
|
|
use App\Modules\Teams\Domain\Team;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Str;
|
|
use Laravel\Sanctum\Sanctum;
|
|
use Tests\TestCase;
|
|
|
|
class ManagerWorkspaceTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
public function test_manager_workspace_only_aggregates_managed_team_data(): void
|
|
{
|
|
$manager = User::factory()->create(['role' => UserRole::Manager]);
|
|
$learner = User::factory()->create(['organization_id' => $manager->organization_id, 'role' => UserRole::Learner, 'name' => 'عضو تیم من']);
|
|
$otherManager = User::factory()->create(['organization_id' => $manager->organization_id, 'role' => UserRole::Manager]);
|
|
$outsider = User::factory()->create(['organization_id' => $manager->organization_id, 'role' => UserRole::Learner, 'name' => 'عضو تیم دیگر']);
|
|
$team = Team::query()->create(['organization_id' => $manager->organization_id, 'name' => 'عملیات', 'status' => 'active', 'created_by' => $manager->getKey()]);
|
|
$team->managers()->attach($manager);
|
|
$team->members()->attach($learner);
|
|
$otherTeam = Team::query()->create(['organization_id' => $manager->organization_id, 'name' => 'فروش', 'status' => 'active', 'created_by' => $otherManager->getKey()]);
|
|
$otherTeam->managers()->attach($otherManager);
|
|
$otherTeam->members()->attach($outsider);
|
|
[$version, $assessment] = $this->content($manager);
|
|
$assignment = Assignment::query()->create(['organization_id' => $manager->organization_id, 'assignable_type' => 'course', 'assignable_id' => $version->getKey(), 'target_type' => 'team', 'target_id' => $team->getKey(), 'status' => 'active', 'mandatory' => true, 'assigned_by' => $manager->getKey()]);
|
|
$assignment->users()->attach($learner, ['status' => 'in_progress', 'assigned_at' => now(), 'due_at' => now()->addDays(2), 'progress' => 25, 'created_at' => now(), 'updated_at' => now()]);
|
|
$otherAssignment = Assignment::query()->create(['organization_id' => $manager->organization_id, 'assignable_type' => 'course', 'assignable_id' => $version->getKey(), 'target_type' => 'team', 'target_id' => $otherTeam->getKey(), 'status' => 'active', 'mandatory' => true, 'assigned_by' => $otherManager->getKey()]);
|
|
$otherAssignment->users()->attach($outsider, ['status' => 'completed', 'assigned_at' => now(), 'completed_at' => now(), 'progress' => 100, 'created_at' => now(), 'updated_at' => now()]);
|
|
LearningEvent::query()->create(['organization_id' => $manager->organization_id, 'learner_id' => $learner->getKey(), 'client_event_id' => Str::uuid(), 'event_type' => 'lesson.started', 'assignment_id' => $assignment->getKey(), 'course_version_id' => $version->getKey(), 'payload' => [], 'occurred_at' => now(), 'received_at' => now()]);
|
|
LearningEvent::query()->create(['organization_id' => $manager->organization_id, 'learner_id' => $outsider->getKey(), 'client_event_id' => Str::uuid(), 'event_type' => 'course.completed', 'assignment_id' => $otherAssignment->getKey(), 'course_version_id' => $version->getKey(), 'payload' => [], 'occurred_at' => now()->addSecond(), 'received_at' => now()]);
|
|
AssessmentAttempt::query()->create(['organization_id' => $manager->organization_id, 'learner_id' => $learner->getKey(), 'course_version_id' => $version->getKey(), 'assessment_id' => $assessment->getKey(), 'attempt_number' => 1, 'status' => 'completed', 'score' => .8, 'started_at' => now()->subMinute(), 'completed_at' => now()]);
|
|
AssessmentAttempt::query()->create(['organization_id' => $manager->organization_id, 'learner_id' => $outsider->getKey(), 'course_version_id' => $version->getKey(), 'assessment_id' => $assessment->getKey(), 'attempt_number' => 1, 'status' => 'completed', 'score' => .95, 'started_at' => now()->subMinute(), 'completed_at' => now()]);
|
|
|
|
Sanctum::actingAs($manager);
|
|
$this->getJson('/api/v1/manager/workspace')->assertOk()
|
|
->assertJsonPath('data.overview.teamCount', 1)->assertJsonPath('data.overview.memberCount', 1)
|
|
->assertJsonPath('data.overview.activeLearners', 1)->assertJsonPath('data.overview.dueSoon', 1)
|
|
->assertJsonPath('data.overview.engagement', 100)->assertJsonPath('data.overview.assessment', 80)
|
|
->assertJsonPath('data.overview.atRisk', 1)->assertJsonPath('data.members.0.name', 'عضو تیم من')
|
|
->assertJsonPath('data.recentActivity.0.learner', 'عضو تیم من')
|
|
->assertJsonCount(1, 'data.assessments')
|
|
->assertJsonPath('data.assessments.0.learnerId', $learner->getKey())
|
|
->assertJsonMissing(['learner' => 'عضو تیم دیگر'])
|
|
->assertJsonMissing(['name' => 'عضو تیم دیگر']);
|
|
}
|
|
|
|
public function test_manager_endpoint_rejects_other_roles_and_manager_mutations_remain_forbidden(): void
|
|
{
|
|
$designer = User::factory()->create(['role' => UserRole::CourseDesigner]);
|
|
Sanctum::actingAs($designer);
|
|
$this->getJson('/api/v1/manager/workspace')->assertForbidden();
|
|
|
|
$manager = User::factory()->create(['organization_id' => $designer->organization_id, 'role' => UserRole::Manager]);
|
|
Sanctum::actingAs($manager);
|
|
$this->postJson('/api/v1/assignments', [])->assertForbidden();
|
|
$this->postJson('/api/v1/courses', [])->assertForbidden();
|
|
}
|
|
|
|
public function test_manager_can_view_only_learning_assigned_to_their_own_account(): void
|
|
{
|
|
$manager = User::factory()->create(['role' => UserRole::Manager]);
|
|
$teamMember = User::factory()->create(['organization_id' => $manager->organization_id, 'role' => UserRole::Learner]);
|
|
[$version] = $this->content($manager);
|
|
$managerAssignment = Assignment::query()->create([
|
|
'organization_id' => $manager->organization_id,
|
|
'assignable_type' => 'course',
|
|
'assignable_id' => $version->getKey(),
|
|
'target_type' => 'individual',
|
|
'target_id' => $manager->getKey(),
|
|
'status' => 'active',
|
|
'mandatory' => true,
|
|
'assigned_by' => $manager->getKey(),
|
|
]);
|
|
$managerAssignment->users()->attach($manager, [
|
|
'status' => 'assigned', 'assigned_at' => now(), 'progress' => 0,
|
|
'created_at' => now(), 'updated_at' => now(),
|
|
]);
|
|
$memberAssignment = Assignment::query()->create([
|
|
'organization_id' => $manager->organization_id,
|
|
'assignable_type' => 'course',
|
|
'assignable_id' => $version->getKey(),
|
|
'target_type' => 'individual',
|
|
'target_id' => $teamMember->getKey(),
|
|
'status' => 'active',
|
|
'mandatory' => true,
|
|
'assigned_by' => $manager->getKey(),
|
|
]);
|
|
$memberAssignment->users()->attach($teamMember, [
|
|
'status' => 'assigned', 'assigned_at' => now(), 'progress' => 0,
|
|
'created_at' => now(), 'updated_at' => now(),
|
|
]);
|
|
|
|
Sanctum::actingAs($manager);
|
|
|
|
$this->getJson('/api/v1/auth/me')
|
|
->assertOk()
|
|
->assertJsonFragment(['learning.personal.view']);
|
|
$this->getJson('/api/v1/learner/home')
|
|
->assertOk()
|
|
->assertJsonPath('data.summary.total', 1)
|
|
->assertJsonPath('data.assigned.0.id', $managerAssignment->getKey())
|
|
->assertJsonMissing(['id' => $memberAssignment->getKey()]);
|
|
$this->getJson('/api/v1/learner/assignments/'.$memberAssignment->getKey())->assertNotFound();
|
|
}
|
|
|
|
private function content(User $owner): array
|
|
{
|
|
$course = Course::query()->create(['organization_id' => $owner->organization_id, 'title' => 'ایمنی', 'slug' => 'manager-safety', 'status' => 'published', 'created_by' => $owner->getKey()]);
|
|
$version = CourseVersion::query()->create(['organization_id' => $owner->organization_id, 'course_id' => $course->getKey(), 'version_number' => 1, 'status' => CourseVersionStatus::Published, 'title' => 'ایمنی محیط کار', 'settings' => [], 'completion_rules' => [], 'published_at' => now()]);
|
|
$assessment = Assessment::query()->create(['organization_id' => $owner->organization_id, 'course_version_id' => $version->getKey(), 'title' => 'ارزیابی ایمنی', 'settings' => []]);
|
|
|
|
return [$version, $assessment];
|
|
}
|
|
}
|