diet-guard/app/test/widgets/body/body_widgets_test.dart
Krzysztof kuhy Rudnicki bda76b495d
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
file-length / file length <= 250 lines (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (mypy, mypy, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (pylint, pylint, ) (push) Waiting to run
pre-commit / pre-commit (${{ matrix.group }}) (rest, , mypy,pylint) (push) Waiting to run
Tests / test (push) Waiting to run
release-apk / release (APK) (push) Waiting to run
repo-contract / repo contract (push) Waiting to run
Ideal weight: drop Broca family and Hamwi
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-11-01 18:54:38 +01:00

174 lines
5.4 KiB
Dart

import 'package:diet_guard_app/services/activity_kcal.dart';
import 'package:diet_guard_app/services/body_calc.dart';
import 'package:diet_guard_app/services/week_plan.dart';
import 'package:diet_guard_app/widgets/body/activity_card.dart';
import 'package:diet_guard_app/widgets/body/body_stats_cards.dart';
import 'package:diet_guard_app/widgets/body/week_plan_card.dart';
import 'package:diet_guard_app/widgets/body/weight_chart.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
Future<void> _pump(WidgetTester tester, Widget child) async {
tester.view.physicalSize = const Size(1200, 4000);
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.reset);
await tester.pumpWidget(
MaterialApp(
home: Scaffold(body: SingleChildScrollView(child: child)),
),
);
await tester.pumpAndSettle();
}
const _short = Biometrics(
weightKg: 50,
heightCm: 150,
ageYears: 17,
isMale: false,
);
void main() {
group('helpers', () {
test('halfUp rounds half away from banker', () {
expect(halfUp(2.5), 3);
expect(halfUp(0.125, 2), 0.13);
});
test('ageOn counts completed years', () {
final birth = DateTime(1995, 3, 1);
expect(ageOn(birth, DateTime(2026, 2, 28)), 30);
expect(ageOn(birth, DateTime(2026, 3, 1)), 31);
expect(ageOn(birth, DateTime(2026, 3, 2)), 31);
expect(ageOn(DateTime(1995, 3, 15), DateTime(2026, 3, 2)), 30);
});
test('weekStart is the local Monday', () {
expect(weekStart(DateTime(2026, 10, 4, 18)), DateTime(2026, 9, 28));
});
test('an unknown session kind uses the generic MET', () {
const s = Session(
day: '2026-09-27',
kind: 'yoga',
minutes: 60,
km: null,
label: 'yoga',
source: '',
);
expect(metFor(s), 4);
});
test('seriesInRange keeps the last N days', () {
final series = [('2026-01-01', 80.0), ('2026-09-20', 79.0)];
final today = DateTime(2026, 9, 27);
expect(seriesInRange(series, 30, today), [('2026-09-20', 79.0)]);
expect(seriesInRange(series, null, today), series);
});
});
testWidgets('a short teenager sees n/a formulas and the age note', (
tester,
) async {
await _pump(
tester,
const Column(
children: [BmiCard(bio: _short), IdealWeightCard(bio: _short)],
),
);
expect(find.text('n/a'), findsNWidgets(3));
expect(find.textContaining('undefined below 152.4 cm'), findsOneWidget);
expect(find.text('adult categories do not apply under 20'), findsOneWidget);
});
testWidgets('activity card states', (tester) async {
await _pump(
tester,
const ActivityCard(sessions: [], weightKg: null, exercise: null),
);
expect(find.textContaining('Enter your weight'), findsOneWidget);
await _pump(
tester,
const ActivityCard(
sessions: [],
weightKg: 80,
exercise: {'MET': 0, 'ACSM': 0, 'Per-km': 0},
),
);
expect(find.textContaining('No workouts in the last 28 days'), findsOne);
expect(find.text('0 kcal/day'), findsNWidgets(3));
var tapped = false;
await _pump(
tester,
ActivityCard(
sessions: null,
weightKg: null,
exercise: null,
steps: const {'2026-09-26': 3000, '2026-09-27': 12000},
stepsKcal: 20,
onConnectSteps: () => tapped = true,
),
);
expect(find.textContaining('No activity data yet'), findsNothing);
expect(
find.textContaining('12000 on 2026-09-27; above 4000/day they add 20'),
findsOneWidget,
);
await tester.tap(find.text('Connect Health Connect steps'));
expect(tapped, isTrue);
});
testWidgets('the chart plots two weigh-ins and switches range', (
tester,
) async {
await _pump(
tester,
WeightChart(
series: const [('2026-06-01', 82.0), ('2026-09-20', 79.5)],
today: DateTime(2026, 9, 27),
),
);
expect(find.text('Need two readings for a graph.'), findsOneWidget);
await tester.tap(find.text('All'));
await tester.pumpAndSettle();
expect(find.byType(LineChart), findsOneWidget);
});
testWidgets('the week planner fills logged days and honours typing', (
tester,
) async {
await _pump(
tester,
WeekPlanCard(
defaultTarget: 2000,
logged: const {'2026-09-28': 2500},
today: DateTime(2026, 9, 30),
),
);
// Mon logged, Tue unlogged: (14000 - 2500) / 6 = 1917.
expect(find.textContaining('2500 kcal (logged)'), findsOneWidget);
expect(find.textContaining('(not logged -- type it)'), findsOneWidget);
expect(find.textContaining('Eat 1917 kcal'), findsOneWidget);
final dayFields = find.widgetWithText(TextField, 'ate…');
await tester.enterText(dayFields.at(1), '1800');
await tester.pumpAndSettle();
expect(find.textContaining('1800 kcal (typed)'), findsOneWidget);
expect(find.textContaining('Eat 1940 kcal'), findsOneWidget);
await tester.enterText(
find.widgetWithText(TextField, 'Weekly average target (kcal/day)'),
'900',
);
await tester.pumpAndSettle();
expect(find.textContaining('below the 1200 kcal floor'), findsOneWidget);
for (var i = 0; i < 7; i++) {
await tester.enterText(dayFields.at(i), '2000');
}
await tester.pumpAndSettle();
expect(find.textContaining('Every day is known'), findsOneWidget);
});
}