Files
unionflow-client-quarkus-pr…/src/test/java/dev/lions/unionflow/client/view/LiveFeedBeanTest.java
dahoud fcaac36a14 feat(sprint-15 web 2026-04-25): Live Activity Feed page (transparency operations)
Page consommant /api/audit-trail/recent avec auto-refresh PrimeFaces toutes les 10s.
Transparency opérationnelle UnionFlow — chaque utilisateur voit selon son scope.

REST client AuditTrailRestClient
- Nouvelle méthode recent(scope, orgId, userId, limit)

Bean LiveFeedBean (@ViewScoped)
- Polling pilote externe via p:poll interval=10
- 3 scopes : SELF (défaut, n'importe quel rôle), ORG (admin/officer), ALL (compliance/contrôleur)
- Helpers : couleurAction (8 mappings), couleurSod (3 cas), tempsRelatif (s/m/h/j/futur)
- Limit clamp [1, 500]
- Compteur de refresh visible dans l'UI (debug)

Page /pages/secure/conformite/live-feed.xhtml
- Panel scope avec selectOneMenu + p:ajax change → rafraîchir
- Conditional inputs : orgId si scope=ORG, userId si scope=SELF
- p:poll interval=10 listener=rafraichir autoStart=true
- DataTable opérations : index, "il y a Xs", acteur+rôle, action coloré, entité, description, SoD tag
- Tag refresh counter (visible feedback)

Centralisation
- ViewPaths.CONFORMITE_LIVE_FEED + getter ViewPathsBean
- menu.xhtml : entrée Live Feed sous sous-menu Conformité (icon pi-bolt)

Tests (13/13 verts)
- couleurAction × 4 (danger/success/info/autres)
- couleurSod
- tempsRelatif × 6 (null, secondes, minutes, heures, jours, futur)
- setLimit clamp × 4
- defaults
2026-04-25 16:10:41 +00:00

131 lines
4.4 KiB
Java

package dev.lions.unionflow.client.view;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.time.LocalDateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
class LiveFeedBeanTest {
private LiveFeedBean bean;
@BeforeEach
void setUp() {
bean = new LiveFeedBean();
}
// ── couleurAction (mêmes règles que AuditTrailViewerBean) ────────────
@Test
@DisplayName("couleurAction — DELETE/PAYMENT_FAILED → danger")
void couleurDanger() {
assertEquals("danger", bean.getCouleurAction("DELETE"));
assertEquals("danger", bean.getCouleurAction("PAYMENT_FAILED"));
}
@Test
@DisplayName("couleurAction — VALIDATE/PAYMENT_CONFIRMED/AID_REQUEST_APPROVED → success")
void couleurSuccess() {
assertEquals("success", bean.getCouleurAction("VALIDATE"));
assertEquals("success", bean.getCouleurAction("PAYMENT_CONFIRMED"));
assertEquals("success", bean.getCouleurAction("AID_REQUEST_APPROVED"));
}
@Test
@DisplayName("couleurAction — UPDATE/PAYMENT_INITIATED/BUDGET_APPROVED → info")
void couleurInfo() {
assertEquals("info", bean.getCouleurAction("UPDATE"));
assertEquals("info", bean.getCouleurAction("PAYMENT_INITIATED"));
assertEquals("info", bean.getCouleurAction("BUDGET_APPROVED"));
}
@Test
@DisplayName("couleurAction — CREATE → primary, EXPORT → warning, autres → secondary")
void couleurAutres() {
assertEquals("primary", bean.getCouleurAction("CREATE"));
assertEquals("warning", bean.getCouleurAction("EXPORT"));
assertEquals("secondary", bean.getCouleurAction(null));
assertEquals("secondary", bean.getCouleurAction("INCONNU"));
}
@Test
@DisplayName("couleurSod — true→success, false→danger, null→secondary")
void couleurSod() {
assertEquals("success", bean.getCouleurSod(true));
assertEquals("danger", bean.getCouleurSod(false));
assertEquals("secondary", bean.getCouleurSod(null));
}
// ── tempsRelatif ─────────────────────────────────────────────────────
@Test
@DisplayName("tempsRelatif — null → '—'")
void tempsRelatifNull() {
assertEquals("", bean.tempsRelatif(null));
}
@Test
@DisplayName("tempsRelatif — 30s ago → 'il y a 30s'")
void tempsRelatifSecondes() {
LocalDateTime past = LocalDateTime.now().minusSeconds(30);
assertTrue(bean.tempsRelatif(past).startsWith("il y a "));
assertTrue(bean.tempsRelatif(past).endsWith("s"));
}
@Test
@DisplayName("tempsRelatif — 5min ago → 'il y a 5m'")
void tempsRelatifMinutes() {
LocalDateTime past = LocalDateTime.now().minusMinutes(5);
assertEquals("il y a 5m", bean.tempsRelatif(past));
}
@Test
@DisplayName("tempsRelatif — 2h ago → 'il y a 2h'")
void tempsRelatifHeures() {
LocalDateTime past = LocalDateTime.now().minusHours(2);
assertEquals("il y a 2h", bean.tempsRelatif(past));
}
@Test
@DisplayName("tempsRelatif — 3 jours ago → 'il y a 3j'")
void tempsRelatifJours() {
LocalDateTime past = LocalDateTime.now().minusDays(3);
assertEquals("il y a 3j", bean.tempsRelatif(past));
}
@Test
@DisplayName("tempsRelatif — futur → 'à l'instant'")
void tempsRelatifFutur() {
LocalDateTime futur = LocalDateTime.now().plusMinutes(1);
assertEquals("à l'instant", bean.tempsRelatif(futur));
}
// ── Limit clamping ───────────────────────────────────────────────────
@Test
@DisplayName("setLimit clamp [1, 500]")
void setLimitClamp() {
bean.setLimit(0);
assertEquals(1, bean.getLimit());
bean.setLimit(1000);
assertEquals(500, bean.getLimit());
bean.setLimit(50);
assertEquals(50, bean.getLimit());
bean.setLimit(-100);
assertEquals(1, bean.getLimit());
}
// ── Defaults ─────────────────────────────────────────────────────────
@Test
@DisplayName("Defaults — scope=SELF, limit=50, compteur=0")
void defaults() {
assertEquals("SELF", bean.getScope());
assertEquals(50, bean.getLimit());
assertEquals(0, bean.getCompteur());
}
}