create(); $workspace = Workspace::factory()->create(); $workspace->users()->attach($user->id, ['role' => $role]); $client = Client::factory()->create(['workspace_id' => $workspace->id]); session(['current_workspace_id' => $workspace->id]); return [$user, $workspace, $client]; } test('unauthenticated user is redirected to login', function () { $response = $this->get(route('dashboard')); $response->assertRedirect(route('login')); }); test('user without workspace sees admin view', function () { $user = User::factory()->create(); $this->actingAs($user); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->where('workspaceName', null) ->where('stats', null) ->where('statCards', []) ->where('declarations', []) ); }); test('owner sees all workspace declarations in kpi counts', function () { [$user, $workspace, $client] = setupWorkspaceWithRole('owner'); $otherUser = User::factory()->create(); $workspace->users()->attach($otherUser->id, ['role' => 'worker']); // Overdue declaration (assigned to other user) Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $otherUser->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->subDays(5), ]); // Due this week (assigned to current user) Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $user->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->addDays(3), ]); // En attente client Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $otherUser->id, 'status' => DeclarationStatus::EnAttenteClient, 'due_date' => now()->addDays(10), ]); // En cours Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $user->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->addDays(15), ]); // Ferme (should be excluded) Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'status' => DeclarationStatus::Ferme, 'due_date' => now()->subDays(1), ]); // Termine (should be excluded) Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'status' => DeclarationStatus::Termine, 'due_date' => now()->subDays(1), ]); // Mise en demeure (should be excluded) Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'status' => DeclarationStatus::MiseEnDemeure, 'due_date' => now()->subDays(1), ]); $this->actingAs($user); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->where('stats.overdue', 1) ->where('stats.dueThisWeek', 1) ->where('stats.enAttenteClient', 1) ->where('stats.enCours', 3) ->has('statCards', 4) ->where('workspaceName', $workspace->name) ); }); test('manager sees all workspace declarations in kpi counts', function () { [$user, $workspace, $client] = setupWorkspaceWithRole('manager'); $worker = User::factory()->create(); $workspace->users()->attach($worker->id, ['role' => 'worker']); // Declaration assigned to the worker (manager should still see it) Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $worker->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->subDays(2), ]); $this->actingAs($user); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->where('stats.overdue', 1) ); }); test('worker sees only assigned declarations', function () { [$user, $workspace, $client] = setupWorkspaceWithRole('worker'); $otherUser = User::factory()->create(); $workspace->users()->attach($otherUser->id, ['role' => 'worker']); // Assigned to this worker Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $user->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->subDays(1), ]); // Assigned to other worker (should NOT be visible) Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $otherUser->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->subDays(1), ]); $this->actingAs($user); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->where('stats.overdue', 1) ->where('stats.enCours', 1) ->has('declarations', 1) ); }); test('dashboard data uses cache with correct key and ttl', function () { [$user, $workspace, $client] = setupWorkspaceWithRole('owner'); Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->addDays(2), ]); $this->actingAs($user); // First request populates cache $this->get(route('dashboard'))->assertOk(); $cacheKey = "dashboard:{$workspace->id}:{$user->id}"; expect(Cache::has($cacheKey))->toBeTrue(); $cached = Cache::get($cacheKey); expect($cached)->toBeArray() ->and($cached)->toHaveKeys(['overdue', 'dueThisWeek', 'enAttenteClient', 'enCours']); }); test('dashboard excludes archived declarations', function () { [$user, $workspace, $client] = setupWorkspaceWithRole('owner'); // Active declaration Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->addDays(2), 'archived_at' => null, ]); // Archived declaration (should NOT be counted) Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->addDays(2), 'archived_at' => now()->subDay(), ]); $this->actingAs($user); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->where('stats.enCours', 1) ->has('declarations', 1) ); }); test('dashboard returns declarations sorted by due date ascending', function () { [$user, $workspace, $client] = setupWorkspaceWithRole('owner'); $later = Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->addDays(10), ]); $sooner = Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->addDays(2), ]); $this->actingAs($user); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->has('declarations', 2) ->where('declarations.0.id', $sooner->id) ->where('declarations.1.id', $later->id) ); }); test('dashboard limits declarations to 15 rows', function () { [$user, $workspace, $client] = setupWorkspaceWithRole('owner'); // Create 20 declarations for ($i = 0; $i < 20; $i++) { Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->addDays($i), ]); } $this->actingAs($user); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->has('declarations', 15) ); }); test('stat cards have correct filter hrefs', function () { [$user, $workspace, $client] = setupWorkspaceWithRole('owner'); $this->actingAs($user); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->has('statCards', 4) ->where('statCards.0.status', 'danger') ->where('statCards.1.status', 'warning') ->where('statCards.2.status', 'info') ->where('statCards.3.status', 'success') ); }); test('declaration rows include show url and assignee name', function () { [$user, $workspace, $client] = setupWorkspaceWithRole('owner'); $assignee = User::factory()->create(['name' => 'Ahmed Test']); Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $assignee->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->addDays(2), ]); $this->actingAs($user); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->has('declarations', 1) ->where('declarations.0.assigneeName', 'Ahmed Test') ->where('declarations.0.clientName', $client->company_name) ->has('declarations.0.showUrl') ); });