+
+ {# Alpine logic — dictiaDashboard + sub-data functions pour les 6 modes #}
+
{# ===== INTÉGRATIONS ===== #}
diff --git a/tests/test_marketing_secondary_pages.py b/tests/test_marketing_secondary_pages.py
index 121c9e8..a124a45 100644
--- a/tests/test_marketing_secondary_pages.py
+++ b/tests/test_marketing_secondary_pages.py
@@ -132,10 +132,11 @@ def test_fonctionnalites_renders_6_bento_cards():
def test_fonctionnalites_how_it_works_reactor_section():
- """New 'Comment ça marche' interactive reactor section (post-6-features, pre-integrations).
+ """'Comment ça marche' interactive section — fidèle reproduction du composant
+ DashboardHolographique (Website-Sanity/dictai-narrative.tsx).
- Validates structure (heading + reactor + spec list + Mistral card), 6 cycling features,
- canonical content, and a11y signals (aria-labelledby + aria-live status panel).
+ Validates structure (phone container + 6 modes + IA Mistral card + 6 feature grid),
+ auto-cycle + manual click logic, canonical content, and a11y signals.
"""
client = app.test_client()
body = client.get('/fonctionnalites').data.decode('utf-8')
@@ -147,37 +148,58 @@ def test_fonctionnalites_how_it_works_reactor_section():
assert 'en temps réel' in body
assert 'Survolez une fonctionnalité pour voir la machine en action' in body
- # 6 cycling features (canonical names)
+ # 6 cycling features (canonical names — appears in FEATURES JS array)
for feat in ['Transcription', 'Diarisation', '99+ langues', 'Exports',
- 'Utilisateurs illimités', 'Partage & Classement']:
+ 'Utilisateurs illimités']:
assert feat in body, f"Missing cycling feature: {feat}"
+ # Partage & Classement (avec & littéral dans le JS)
+ assert "'Partage & Classement'" in body, "Missing Partage & Classement feature"
- # Reactor visual: rings, orbits, wordmark, Auto badge
- assert 'reactor-ring' in body and 'ring-outer' in body and 'ring-mid' in body and 'ring-inner' in body
- assert 'orbit orbit-1' in body and 'orbit orbit-8' in body, "Missing 8 orbital particles"
- assert '>DictIA<' in body, "Missing reactor centre wordmark"
+ # Phone container : Alpine root + features + Mic pulsing + DictIA logo
+ assert 'dictiaDashboard()' in body, "Missing dictiaDashboard Alpine root"
+ assert 'dictia-mic-pulse' in body, "Missing pulsing Mic animation class"
+ assert 'dictia-logo-nom.png' in body, "Missing DictIA logo image"
- # Mistral 7B IA intégrée card with 3 canonical bullets
+ # 6 modes uniques (chacun a son sub-data function ou sa signature unique)
+ assert 'trModeData()' in body, "Missing Mode 1 (Transcription) data function"
+ assert 'reunion-jan14.mp3' in body, "Missing transcription upload filename"
+ assert 'diaModeData()' in body, "Missing Mode 2 (Diarisation) data function"
+ assert 'Sophie' in body and 'Marc' in body and 'Julie' in body, "Missing diarisation speakers"
+ assert 'langModeData()' in body, "Missing Mode 3 (Langues) data function"
+ assert '99+ langues détectées' in body, "Missing langues subtitle"
+ assert 'expModeData()' in body, "Missing Mode 4 (Exports) data function"
+ assert 'usersModeData()' in body, "Missing Mode 5 (Users) data function"
+ assert 'iaModeData()' in body, "Missing Mode 0 (IA chat) data function"
+ assert 'MISTRAL 7B · LOCAL' in body, "Missing IA chat header label"
+
+ # Mode 6 (Share) : folders + tags + files
+ assert 'CR-Réunion-Jan14' in body, "Missing share file name"
+ assert '#Confidentiel' in body, "Missing share tag"
+ assert 'partage sécurisé' in body, "Missing share footer text"
+
+ # IA Mistral 7B premium card avec 3 bullets souveraineté
assert 'Mistral 7B' in body
assert 'IA intégrée' in body
assert 'Données hébergées sur VOS serveurs' in body
assert 'Zéro connexion OpenAI' in body
assert 'Inférence hors-ligne' in body
+ assert 'ia-ambient-glow' in body, "Missing IA ambient glow animation"
+ assert 'ia-brain-glow' in body, "Missing IA brain glow animation"
+ assert 'ia-local-badge' in body, "Missing LOCAL badge pulsing animation"
- # Alpine reactor data + auto-cycle + hover/focus stop logic
- assert "active: \"Transcription\"" in body
- assert 'isHovered' in body
- assert 'setActive(feat)' in body
- assert 'resumeCycle()' in body
- # Hover, focus + blur listeners on each list item
- assert '@mouseenter="setActive(feat)"' in body
- assert '@mouseleave="resumeCycle()"' in body
- assert '@focus="setActive(feat)"' in body
- assert '@blur="resumeCycle()"' in body
+ # Auto-cycle + manual select logic
+ assert 'startAutoCycle' in body, "Missing auto-cycle function"
+ assert 'handleManualSelect' in body, "Missing manual select handler"
+ assert '900' in body, "Missing 900ms cycle interval"
+ assert '4500' in body, "Missing 4500ms manual reset timer"
+ # Auto / Manual status text
+ assert 'Auto' in body, "Missing Auto status indicator"
+ assert 'Auto reprend bientôt' in body, "Missing manual mode hint"
# Accessibility: aria-live status panel, prefers-reduced-motion guard
assert 'aria-live="polite"' in body
assert 'prefers-reduced-motion' in body, "Reduced-motion guard missing"
+ assert 'aria-pressed' in body, "Missing aria-pressed on feature buttons"
def test_fonctionnalites_export_formats_section():