Files
L-Ami-Fiduciaire/tests/Feature/Dashboard/PriorityAlertsPanelTest.php
Saad Ibn-Ezzoubayr 4807376c49 feat: implement Story 2.2 — Priority Alerts Panel with UI fixes
Add PriorityAlertsPanel component to the dashboard, update DashboardController
with alert logic, and apply misc UI fixes across sidebar, forms, and pages.
Includes epic-1 retrospective and sprint status update.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 12:33:27 +00:00

291 lines
8.9 KiB
PHP

<?php
use App\Enums\DeclarationStatus;
use App\Models\Client;
use App\Models\Declaration;
use App\Models\User;
use App\Models\Workspace;
use Illuminate\Support\Facades\Cache;
function setupAlertWorkspace(string $role = 'owner'): array
{
$user = User::factory()->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('overdue declarations appear as critical alerts with correct daysOverdue', function () {
[$user, $workspace, $client] = setupAlertWorkspace();
$declaration = Declaration::factory()->create([
'workspace_id' => $workspace->id,
'client_id' => $client->id,
'status' => DeclarationStatus::EnCours,
'due_date' => now()->subDays(5),
]);
$this->actingAs($user);
$response = $this->get(route('dashboard'));
$response->assertOk();
$response->assertInertia(fn ($page) => $page
->component('Dashboard')
->has('alerts', 1)
->where('alerts.0.severity', 'critical')
->where('alerts.0.clientName', $client->company_name)
->where('alerts.0.daysValue', 5)
->where('alerts.0.daysLabel', 'jours en retard')
->has('alerts.0.showUrl')
);
});
test('approaching deadline declarations appear as warning alerts', function () {
[$user, $workspace, $client] = setupAlertWorkspace();
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('alerts', 1)
->where('alerts.0.severity', 'warning')
->where('alerts.0.daysLabel', 'jours restants')
);
});
test('en_attente_client over 3 days appears as info alert', function () {
[$user, $workspace, $client] = setupAlertWorkspace();
Declaration::factory()->create([
'workspace_id' => $workspace->id,
'client_id' => $client->id,
'status' => DeclarationStatus::EnAttenteClient,
'due_date' => now()->addDays(10),
'updated_at' => now()->subDays(5),
]);
$this->actingAs($user);
$response = $this->get(route('dashboard'));
$response->assertOk();
$response->assertInertia(fn ($page) => $page
->component('Dashboard')
->where('alerts.0.severity', 'info')
->where('alerts.0.daysLabel', 'jours en attente')
);
});
test('en_attente_client 3 days or less does not appear as info alert', function () {
[$user, $workspace, $client] = setupAlertWorkspace();
Declaration::factory()->create([
'workspace_id' => $workspace->id,
'client_id' => $client->id,
'status' => DeclarationStatus::EnAttenteClient,
'due_date' => now()->addDays(10),
'updated_at' => now()->subDays(2),
]);
$this->actingAs($user);
$response = $this->get(route('dashboard'));
$response->assertOk();
$response->assertInertia(fn ($page) => $page
->component('Dashboard')
->has('alerts', 0)
);
});
test('alerts are capped at 20 items', function () {
[$user, $workspace, $client] = setupAlertWorkspace();
// Create 25 overdue declarations
for ($i = 1; $i <= 25; $i++) {
Declaration::factory()->create([
'workspace_id' => $workspace->id,
'client_id' => $client->id,
'status' => DeclarationStatus::EnCours,
'due_date' => now()->subDays($i),
]);
}
$this->actingAs($user);
$response = $this->get(route('dashboard'));
$response->assertOk();
$response->assertInertia(fn ($page) => $page
->component('Dashboard')
->has('alerts', 20)
);
});
test('alerts are sorted by severity: critical first, then warning, then info', function () {
[$user, $workspace, $client] = setupAlertWorkspace();
// Info alert (en_attente_client >3 days)
Declaration::factory()->create([
'workspace_id' => $workspace->id,
'client_id' => $client->id,
'status' => DeclarationStatus::EnAttenteClient,
'due_date' => now()->addDays(10),
'updated_at' => now()->subDays(5),
]);
// Warning alert (due in 2 days)
Declaration::factory()->create([
'workspace_id' => $workspace->id,
'client_id' => $client->id,
'status' => DeclarationStatus::EnCours,
'due_date' => now()->addDays(2),
]);
// Critical alert (overdue)
Declaration::factory()->create([
'workspace_id' => $workspace->id,
'client_id' => $client->id,
'status' => DeclarationStatus::EnCours,
'due_date' => now()->subDays(3),
]);
$this->actingAs($user);
$response = $this->get(route('dashboard'));
$response->assertOk();
$response->assertInertia(fn ($page) => $page
->component('Dashboard')
->has('alerts', 3)
->where('alerts.0.severity', 'critical')
->where('alerts.1.severity', 'warning')
->where('alerts.2.severity', 'info')
);
});
test('worker sees only alerts for assigned declarations', function () {
[$user, $workspace, $client] = setupAlertWorkspace('worker');
$otherUser = User::factory()->create();
$workspace->users()->attach($otherUser->id, ['role' => 'worker']);
// Overdue assigned to this worker (should appear)
Declaration::factory()->create([
'workspace_id' => $workspace->id,
'client_id' => $client->id,
'assigned_to' => $user->id,
'status' => DeclarationStatus::EnCours,
'due_date' => now()->subDays(2),
]);
// Overdue assigned to other worker (should NOT appear)
Declaration::factory()->create([
'workspace_id' => $workspace->id,
'client_id' => $client->id,
'assigned_to' => $otherUser->id,
'status' => DeclarationStatus::EnCours,
'due_date' => now()->subDays(3),
]);
$this->actingAs($user);
$response = $this->get(route('dashboard'));
$response->assertOk();
$response->assertInertia(fn ($page) => $page
->component('Dashboard')
->has('alerts', 1)
->where('alerts.0.severity', 'critical')
);
});
test('empty alerts array when no urgent items exist', function () {
[$user, $workspace, $client] = setupAlertWorkspace();
// Declaration far in the future (no alert)
Declaration::factory()->create([
'workspace_id' => $workspace->id,
'client_id' => $client->id,
'status' => DeclarationStatus::EnCours,
'due_date' => now()->addDays(30),
]);
$this->actingAs($user);
$response = $this->get(route('dashboard'));
$response->assertOk();
$response->assertInertia(fn ($page) => $page
->component('Dashboard')
->has('alerts', 0)
);
});
test('alerts are included in cached dashboard payload', function () {
[$user, $workspace, $client] = setupAlertWorkspace();
Declaration::factory()->create([
'workspace_id' => $workspace->id,
'client_id' => $client->id,
'status' => DeclarationStatus::EnCours,
'due_date' => now()->subDays(2),
]);
$this->actingAs($user);
$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)->toHaveKey('alerts')
->and($cached['alerts'])->toBeArray()
->and($cached['alerts'])->toHaveCount(1)
->and($cached['alerts'][0]['severity'])->toBe('critical');
});
test('excluded statuses do not generate alerts', function () {
[$user, $workspace, $client] = setupAlertWorkspace();
// Termine (excluded) - overdue
Declaration::factory()->create([
'workspace_id' => $workspace->id,
'client_id' => $client->id,
'status' => DeclarationStatus::Termine,
'due_date' => now()->subDays(5),
]);
// MiseEnDemeure (excluded) - overdue
Declaration::factory()->create([
'workspace_id' => $workspace->id,
'client_id' => $client->id,
'status' => DeclarationStatus::MiseEnDemeure,
'due_date' => now()->subDays(3),
]);
// Ferme (excluded) - overdue
Declaration::factory()->create([
'workspace_id' => $workspace->id,
'client_id' => $client->id,
'status' => DeclarationStatus::Ferme,
'due_date' => now()->subDays(1),
]);
$this->actingAs($user);
$response = $this->get(route('dashboard'));
$response->assertOk();
$response->assertInertia(fn ($page) => $page
->component('Dashboard')
->has('alerts', 0)
);
});