etm-powersync-app/test/energy_flow_cons_test.dart
Patrick Schurig 12c3e912b0 fix(flux): les détails ne fabriquent plus de décomposition
Signalé sur banc, et les deux vues détaillées inventaient.

CONSOMMATION — PAC = 38 % de la maison, eau chaude = 18 %, autres = 22 %. Des
ratios posés à la maquette, marqués « estimé »… et affichés tels quels le
2026-09-06 alors que les compteurs ECS et PAC publiaient `{powerW: 0, source:
meter}`. Un compteur à zéro dit « rien ne chauffe » ; l'écran répondait 720 W.

La mention « estimé » était le problème autant que le remède : sous un nombre
inventé, elle le rend acceptable. Les branches viennent désormais de
`GetLoadTelemetry.measurement`, par domaine, et une charge sans mesure publiée
affiche « non publié ». « Autres » disparaît — c'était un reste calculé sur des
parts inventées, donc inventé lui aussi : sans mesure exhaustive, il n'y a pas de
reste connu.

PRODUCTION — « Onduleur 1 » et « Onduleur 2 » portaient chacun la MOITIÉ de la
production, avec l'état `ok`, donc sans même la marque « estimé » des branches de
consommation. Deux appareils qui n'existent nulle part : le banc n'a qu'un seul
compteur de production. La vue dit maintenant « détail par source non publié par
cette box ».

Et un débordement introduit en chemin, attrapé en test : « non publié » ne tient
pas dans un nœud dimensionné pour « 1.2 kW » — 7 px de trop, donc du texte coupé
sur l'appareil. `FittedBox(scaleDown)`, comme pour l'étiquette des tuiles.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
2026-09-06 13:05:43 +02:00

128 lines
5.2 KiB
Dart

/// La vue « consommation » du Sankey — ce qui est mesuré, et ce qui ne l'est pas.
///
/// Trois de ses quatre branches sont des **ratios en dur** posés à la maquette : PAC = 38 %
/// de la consommation maison, eau chaude = 18 %, autres = 22 %. Un seul nœud (« Autres »)
/// portait le cercle pointillé ; les deux autres se lisaient comme des mesures. Et la
/// voiture affichait 3,6 kW en permanence, véhicule débranché — la valeur par défaut de
/// `EnergyData.chargingPower`, supprimée le 2026-08-28.
///
/// Ces tests figent le marquage. Ils ne valident pas les ratios : les remplacer par
/// `measuredW` de `GetLoadTelemetry` est un lot à part.
library;
import 'package:etm_powersync_app/features/dashboard/widgets/energy_flow_card.dart';
import 'package:etm_powersync_app/models/energy_data.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
/// Largeur contrainte : le schéma est un carré, et en pleine largeur de la fenêtre de test
/// (800 px) il déborde des 600 px de haut — le nœud « Maison » se retrouve hors écran et
/// aucune touche ne l'atteint.
Widget _harness({double? evChargerPowerW, Map<String, double?>? mesures}) =>
MediaQuery(
data: const MediaQueryData(disableAnimations: true),
child: MaterialApp(
home: Scaffold(
body: Center(
child: SizedBox(
width: 340,
child: EnergyFlowCard(
data: const EnergyData(homePower: 4000, pvPower: 5000),
evChargerPowerW: evChargerPowerW,
mesuresParDomaine: mesures ?? const {},
),
),
),
),
),
);
/// `pumpAndSettle` est inutilisable ici : les particules du schéma tournent en boucle
/// (`repeat()`), et `disableAnimations` ne change que la valeur lue, pas le contrôleur. On
/// avance donc d'un nombre fini de trames.
Future<void> _poser(WidgetTester tester) async {
for (var i = 0; i < 6; i++) {
await tester.pump(const Duration(milliseconds: 120));
}
}
/// Ouvre le détail de consommation — il n'est atteignable qu'en touchant « Maison ».
///
/// Le `_poser` AVANT la touche n'est pas décoratif : les nœuds entrent en `ScaleTransition`
/// et, sur la première trame, leur échelle vaut zéro — la touche traverse sans rien
/// atteindre, silencieusement.
Future<void> _ouvrirConso(WidgetTester tester) async {
await _poser(tester);
await tester.tap(find.text('Maison'));
await _poser(tester);
}
void main() {
testWidgets('la vue d\'ensemble ne parle pas d\'estimation — tout y est mesuré',
(tester) async {
await tester.pumpWidget(_harness());
await _poser(tester);
expect(find.textContaining('Répartition estimée'), findsNothing);
});
testWidgets('un compteur a 0 W affiche 0 W, pas 18 % de la maison',
(tester) async {
// Le cas exact du 2026-09-06 : ECS et PAC publiaient {powerW: 0, source: meter}
// pendant que l'ecran montrait des parts de la consommation du foyer.
await tester.pumpWidget(_harness(mesures: {'ecs': 0.0, 'heating': 0.0}));
await _ouvrirConso(tester);
expect(find.text('0.0 kW'), findsNWidgets(2));
// 18 % et 38 % de 4 000 W : les deux nombres qui ne doivent plus exister.
expect(find.textContaining('0.7'), findsNothing);
expect(find.textContaining('1.5'), findsNothing);
});
testWidgets('un domaine sans mesure publiee dit non publie', (tester) async {
await tester.pumpWidget(_harness(mesures: {'ecs': 1200.0}));
await _ouvrirConso(tester);
expect(find.text('1.2 kW'), findsOneWidget);
expect(find.text('non publié'), findsOneWidget);
});
testWidgets('la note ne parle plus d estimation, il n y a plus rien d estime',
(tester) async {
// La mention « estimé » etait le probleme autant que le remede : sous un nombre
// invente, elle le rend acceptable. L'enlever oblige a ne montrer que du vrai.
await tester.pumpWidget(_harness(mesures: {'ecs': 1200.0}));
await _ouvrirConso(tester);
expect(find.textContaining('Répartition estimée'), findsNothing);
expect(find.textContaining('parts types'), findsNothing);
expect(find.textContaining('non publié'), findsWidgets);
});
testWidgets('Autres a disparu : un reste calcule sur des parts inventees',
(tester) async {
await tester.pumpWidget(_harness(mesures: {'ecs': 1200.0, 'heating': 800.0}));
await _ouvrirConso(tester);
expect(find.text('Autres'), findsNothing);
});
testWidgets('sans borne, la voiture affiche « non lu » — jamais 0,0 kW',
(tester) async {
// 3,6 kW en dur vivait ici, voiture débranchée, sur le premier écran de l'app.
// Le remplacer par un zéro aurait échangé une fiction contre une autre : « rien ne
// charge » n'est pas « je ne mesure rien ».
await tester.pumpWidget(_harness());
await _ouvrirConso(tester);
expect(find.text('non lu'), findsOneWidget);
expect(find.textContaining('3.6'), findsNothing);
});
testWidgets('avec une borne, elle affiche la puissance mesurée', (tester) async {
await tester.pumpWidget(_harness(evChargerPowerW: 3907));
await _ouvrirConso(tester);
expect(find.text('3.9 kW'), findsOneWidget);
expect(find.text('non lu'), findsNothing);
});
}