etm-powersync-app/test/kpi_ratios_test.dart
Patrick Schurig 763df68a2a feat(bilan): deux grandeurs, deux phrases — les ratios de la box à côté de la journée
Les tuiles disent la JOURNÉE, par différence de compteurs sur la fenêtre publiée.
La nouvelle ligne dit ce que la BOX publie, qui part de la baseline — et elle ne
s'affiche QUE lorsque cette origine diffère du début de journée.

Le cas est arrivé de lui-même : `nymead` redémarré à 09:23, sonde à 09:26, et la
box publiait 100 % d'autoconsommation. Vrai sur trois minutes ; absurde intitulé
« aujourd'hui ». La ligne le rend lisible — « Instantané depuis 09:23 » — au lieu
de le laisser passer pour la journée.

Vérifié avec le MODÈLE de l'app et non à l'œil sur le JSON : `ratios_check.dart`
importe `EnergyRatiosSnapshot` (idiome de `measurement_check.dart`) et rend
`baselineRepriseEnJournee: true`, ratios couvrant 3 minutes. Le banc est passé en
Europe/Paris entre-temps, et `periodStartedAt` suit sans que le code bouge —
c'est l'intérêt d'une frontière publiée.

Quand les deux coïncident, rien n'est ajouté : une phrase permanente cesse d'être
lue, comme un avertissement permanent.

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

92 lines
3.9 KiB
Dart

/// **Deux grandeurs, deux phrases, aucune ne ment.**
///
/// Les tuiles disent la JOURNÉE — différence de compteurs sur `periodStartedAt → maintenant`.
/// La ligne des ratios dit ce que la BOX publie, qui part de la **baseline** et non du début
/// de journée.
///
/// Le cas est arrivé de lui-même le 2026-09-05 : `nymead` redémarré à 09:23, sonde à 09:26,
/// et la box publiait **100 % d'autoconsommation**. Vrai sur trois minutes ; absurde intitulé
/// « aujourd'hui ». C'est ce que le drapeau rend lisible — et c'est pour ça que la ligne ne
/// s'affiche QUE lorsque l'origine diffère : quand les deux coïncident, une phrase de plus
/// serait du bruit, et un texte permanent cesse d'être lu.
library;
import 'package:etm_powersync_app/features/dashboard/widgets/kpi_row.dart';
import 'package:etm_powersync_app/models/daily_balance.dart';
import 'package:etm_powersync_app/models/energy_data.dart';
import 'package:etm_powersync_app/models/energy_ratios_snapshot.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
/// Relevé `.75` du 2026-09-05 09:26, après le redémarrage de 09:23.
EnergyRatiosSnapshot _releve({int measuredSince = 1788592995}) =>
EnergyRatiosSnapshot.fromJson({
'autonomyRate': 28.570199887530475,
'selfConsumptionRate': 100,
'periodStartedAt': 1788559200,
'measuredSince': measuredSince,
'timeZone': 'Europe/Paris',
});
DailyBalance _bilan() => DailyBalance(
from: DateTime(2026, 9, 5, 0, 15),
to: DateTime(2026, 9, 5, 9, 26),
periodStart: DateTime(2026, 9, 5),
sampleCount: 37,
productionKwh: 8.0,
consumptionKwh: 12.0,
importKwh: 5.0,
exportKwh: 1.0,
);
Widget _harness({EnergyRatiosSnapshot? ratios}) => MaterialApp(
home: Scaffold(
body: SingleChildScrollView(
child: KpiRow(
data: const EnergyData(), balance: _bilan(), ratios: ratios),
),
),
);
void main() {
testWidgets('baseline reposée en journée : l\'origine est DITE', (tester) async {
await tester.binding.setSurfaceSize(const Size(1000, 2000));
addTearDown(() => tester.binding.setSurfaceSize(null));
await tester.pumpWidget(_harness(ratios: _releve()));
expect(find.textContaining('Instantané depuis 09:23'), findsOneWidget);
// Le 100 % est affiché — il est vrai — mais jamais sous le mot « aujourd'hui ».
expect(find.textContaining('autoconsommation 100 %'), findsOneWidget);
});
testWidgets('les tuiles restent la JOURNÉE, calculée sur la fenêtre de la box',
(tester) async {
await tester.binding.setSurfaceSize(const Size(1000, 2000));
addTearDown(() => tester.binding.setSurfaceSize(null));
await tester.pumpWidget(_harness(ratios: _releve()));
// Les anneaux animent leur valeur : sans laisser l'animation finir, ils affichent 0 —
// une absence qui se lirait comme un succès si on cherchait justement une absence.
await tester.pumpAndSettle();
expect(find.text('Aujourd\'hui'), findsOneWidget);
// 8 kWh produits, 1 exporté -> 87,5 % ; et surtout PAS le 100 % de la box.
expect(find.textContaining('88'), findsOneWidget);
});
testWidgets('origine confondue avec le début de journée : rien de plus',
(tester) async {
await tester.binding.setSurfaceSize(const Size(1000, 2000));
addTearDown(() => tester.binding.setSurfaceSize(null));
// Le cas normal : la baseline date du début de journée.
await tester.pumpWidget(_harness(ratios: _releve(measuredSince: 1788559200)));
expect(find.textContaining('Instantané depuis'), findsNothing);
});
testWidgets('box antérieure : aucune ligne, aucune supposition', (tester) async {
await tester.binding.setSurfaceSize(const Size(1000, 2000));
addTearDown(() => tester.binding.setSurfaceSize(null));
await tester.pumpWidget(_harness());
expect(find.textContaining('Instantané'), findsNothing);
});
}