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('owner sees workspace-wide activity in activities prop', function () { [$owner, $workspace, $client] = setupActivityWorkspace('owner'); $otherUser = User::factory()->create(); $workspace->users()->attach($otherUser->id, ['role' => 'worker']); // Act as owner BEFORE creating declaration so Spatie logs the causer $this->actingAs($owner); Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $otherUser->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->addDays(10), ]); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->has('activities') ->where('activities.0.actorName', $owner->name) ); }); test('worker sees only activity related to their assigned declarations', function () { [$worker, $workspace, $client] = setupActivityWorkspace('worker'); $otherWorker = User::factory()->create(); $workspace->users()->attach($otherWorker->id, ['role' => 'worker']); // Declaration assigned to THIS worker — should appear in feed $assignedDeclaration = Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $worker->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->addDays(10), ]); // 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()->addDays(5), ]); $this->actingAs($worker); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->has('activities') ); // Verify the worker only sees activities for their own declarations $activitiesData = $response->original->getData()['page']['props']['activities']; expect(count($activitiesData))->toBeGreaterThan(0); // All activities should relate to the worker's assigned client collect($activitiesData)->each(function ($a) use ($client) { expect($a['description'])->toContain($client->company_name); }); }); test('activity entries contain expected fields', function () { [$owner, $workspace, $client] = setupActivityWorkspace('owner'); Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $owner->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->addDays(10), ]); $this->actingAs($owner); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->has('activities.0', fn ($activity) => $activity ->has('id') ->has('actorName') ->has('actorInitials') ->has('description') ->has('targetUrl') ->has('targetLabel') ->has('timestamp') ->has('eventType') ) ); }); test('feed is limited to 20 most recent events', function () { [$owner, $workspace, $client] = setupActivityWorkspace('owner'); // Create 25 declarations to generate 25 activity log entries for ($i = 0; $i < 25; $i++) { Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $owner->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->addDays($i + 1), ]); } $this->actingAs($owner); $response = $this->get(route('dashboard')); $response->assertOk(); $activitiesData = $response->original->getData()['page']['props']['activities']; expect(count($activitiesData))->toBeLessThanOrEqual(20); }); test('empty activity returns empty array', function () { $user = User::factory()->create(); $workspace = Workspace::factory()->create(); $workspace->users()->attach($user->id, ['role' => 'owner']); session(['current_workspace_id' => $workspace->id]); // No declarations or activity created $this->actingAs($user); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->where('activities', []) ); }); test('activity with deleted subject does not cause errors', function () { [$owner, $workspace, $client] = setupActivityWorkspace('owner'); // Create a declaration (logs activity), then soft-delete it $declaration = Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $owner->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->addDays(10), ]); $declaration->delete(); $this->actingAs($owner); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->has('activities') ); }); test('manager sees workspace-wide activity same as owner', function () { [$manager, $workspace, $client] = setupActivityWorkspace('manager'); $worker = User::factory()->create(); $workspace->users()->attach($worker->id, ['role' => 'worker']); // Create a declaration by the worker $this->actingAs($worker); Declaration::factory()->create([ 'workspace_id' => $workspace->id, 'client_id' => $client->id, 'assigned_to' => $worker->id, 'status' => DeclarationStatus::EnCours, 'due_date' => now()->addDays(10), ]); $this->actingAs($manager); $response = $this->get(route('dashboard')); $response->assertOk(); $response->assertInertia(fn ($page) => $page ->component('Dashboard') ->has('activities') ); $activitiesData = $response->original->getData()['page']['props']['activities']; expect(count($activitiesData))->toBeGreaterThan(0); });