create(); $workspace = Workspace::factory()->create(); $workspace->users()->attach($worker->id, ['role' => 'worker']); $client = Client::factory()->create(['workspace_id' => $workspace->id]); session(['current_workspace_id' => $workspace->id]); return [$worker, $workspace, $client]; } test('worker sees only their assigned declarations in kpi counts', function () { [$worker, $workspace, $client] = setupWorkerWorkspace(); $otherUser = User::factory()->create(); $workspace->users()->attach($otherUser->id, ['role' => 'worker']); // Assigned to this worker — overdue Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $worker->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->subDays(3), ]); // Assigned to this worker — due this week Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $worker->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->addDays(2), ]); // Assigned to this worker — en attente client Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $worker->id, 'status' => DeclarationStatus::EnAttenteClient, 'due_date' => now()->addDays(10), ]); // Assigned to OTHER worker (should NOT count) 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($worker); $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', 2) ); }); test('worker does not see declarations assigned to other team members in kpi counts', function () { [$worker, $workspace, $client] = setupWorkerWorkspace(); $otherWorker = User::factory()->create(); $workspace->users()->attach($otherWorker->id, ['role' => 'worker']); // Only assigned to other worker Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $otherWorker->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->subDays(5), ]); Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $otherWorker->id, 'status' => DeclarationStatus::EnAttenteClient, 'due_date' => now()->addDays(2), ]); $this->actingAs($worker); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->where('stats.overdue', 0) ->where('stats.dueThisWeek', 0) ->where('stats.enAttenteClient', 0) ->where('stats.enCours', 0) ); }); test('worker sees only their assigned declarations in the urgent declarations table', function () { [$worker, $workspace, $client] = setupWorkerWorkspace(); $otherWorker = User::factory()->create(); $workspace->users()->attach($otherWorker->id, ['role' => 'worker']); // Assigned to this worker $myDeclaration = Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $worker->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->addDays(2), ]); // Assigned to other worker Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $otherWorker->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->addDays(1), ]); $this->actingAs($worker); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->has('declarations', 1) ->where('declarations.0.id', $myDeclaration->id) ); }); test('worker sees only their assigned declarations in priority alerts', function () { [$worker, $workspace, $client] = setupWorkerWorkspace(); $otherWorker = User::factory()->create(); $workspace->users()->attach($otherWorker->id, ['role' => 'worker']); // Overdue declaration assigned to this worker (generates critical alert) Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $worker->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->subDays(5), ]); // Overdue declaration assigned to other worker (should NOT appear) Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $otherWorker->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->subDays(3), ]); $this->actingAs($worker); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->has('alerts', 1) ->where('alerts.0.severity', 'critical') ); }); test('worker dashboard returns isWorker true in inertia props', function () { [$worker, $workspace, $client] = setupWorkerWorkspace(); $this->actingAs($worker); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->where('isWorker', true) ); }); test('worker with no assigned declarations gets zero counts and empty arrays', function () { [$worker, $workspace, $client] = setupWorkerWorkspace(); // Declarations exist but assigned to someone else $otherUser = User::factory()->create(); $workspace->users()->attach($otherUser->id, ['role' => 'worker']); 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($worker); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->where('stats.overdue', 0) ->where('stats.dueThisWeek', 0) ->where('stats.enAttenteClient', 0) ->where('stats.enCours', 0) ->where('declarations', []) ->where('alerts', []) ->where('isWorker', true) ); }); test('worker stat card hrefs include assignee scoping param', function () { [$worker, $workspace, $client] = setupWorkerWorkspace(); $this->actingAs($worker); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->has('statCards', 4) ->where('statCards.0.href', fn ($href) => str_contains($href, 'assignee='.$worker->id)) ->where('statCards.1.href', fn ($href) => str_contains($href, 'assignee='.$worker->id)) ->where('statCards.2.href', fn ($href) => str_contains($href, 'assignee='.$worker->id)) ->where('statCards.3.href', fn ($href) => str_contains($href, 'assignee='.$worker->id)) ); }); test('owner and manager dashboard returns isWorker false', function () { $ownerUser = User::factory()->create(); $managerUser = User::factory()->create(); $workspace = Workspace::factory()->create(); $workspace->users()->attach($ownerUser->id, ['role' => 'owner']); $workspace->users()->attach($managerUser->id, ['role' => 'manager']); session(['current_workspace_id' => $workspace->id]); // Owner $this->actingAs($ownerUser); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->where('isWorker', false) ); // Manager $this->actingAs($managerUser); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->where('isWorker', false) ); }); test('cached data is scoped per user with worker cache key including user id', function () { [$worker, $workspace, $client] = setupWorkerWorkspace(); $otherWorker = User::factory()->create(); $workspace->users()->attach($otherWorker->id, ['role' => 'worker']); // Declaration assigned to first worker Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $worker->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->subDays(1), ]); // Declaration assigned to second worker Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $otherWorker->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->subDays(2), ]); // First worker request $this->actingAs($worker); $this->get(route('dashboard'))->assertOk(); $workerCacheKey = "dashboard:{$workspace->id}:{$worker->id}"; $otherCacheKey = "dashboard:{$workspace->id}:{$otherWorker->id}"; expect(Cache::has($workerCacheKey))->toBeTrue(); expect(Cache::has($otherCacheKey))->toBeFalse(); $workerCached = Cache::get($workerCacheKey); expect($workerCached['overdue'])->toBe(1) ->and($workerCached['enCours'])->toBe(1); // Second worker request $this->actingAs($otherWorker); $this->get(route('dashboard'))->assertOk(); expect(Cache::has($otherCacheKey))->toBeTrue(); $otherCached = Cache::get($otherCacheKey); expect($otherCached['overdue'])->toBe(1) ->and($otherCached['enCours'])->toBe(1); });