120 lines
4.5 KiB
Dart
120 lines
4.5 KiB
Dart
import 'package:drift/native.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:glp1_companion/core/database/app_database.dart';
|
|
import 'package:glp1_companion/features/meal_planner/presentation/screens/meal_planner_screen.dart';
|
|
|
|
/// Regression tests for the desktop resize overflow (yellow/black hatched
|
|
/// stripes): the meal planner must reflow into scrollable layouts at short
|
|
/// window heights instead of overflowing a rigid `Column`.
|
|
///
|
|
/// RenderFlex overflows raise a [FlutterError] inside widget tests, so a
|
|
/// clean run also proves the stripes are gone.
|
|
void main() {
|
|
late AppDatabase database;
|
|
|
|
setUp(() {
|
|
database = AppDatabase.forTesting(NativeDatabase.memory());
|
|
});
|
|
|
|
tearDown(() => database.close());
|
|
|
|
Future<void> pumpScreen(
|
|
WidgetTester tester, {
|
|
required Size logicalSize,
|
|
}) async {
|
|
tester.view.physicalSize = logicalSize;
|
|
tester.view.devicePixelRatio = 1.0;
|
|
addTearDown(tester.view.resetPhysicalSize);
|
|
addTearDown(tester.view.resetDevicePixelRatio);
|
|
|
|
await tester.pumpWidget(
|
|
ProviderScope(
|
|
overrides: [appDatabaseProvider.overrideWithValue(database)],
|
|
child: const MaterialApp(home: MealPlannerScreen()),
|
|
),
|
|
);
|
|
// Let the initial drift loads (watch stream + microtask refresh) settle.
|
|
await tester.pump();
|
|
await tester.pump(const Duration(milliseconds: 50));
|
|
await tester.pump(const Duration(milliseconds: 50));
|
|
}
|
|
|
|
/// Unmounts the tree and flushes the zero-duration timer drift schedules
|
|
/// when its query streams are cancelled during container disposal
|
|
/// (`StreamQueryStore.markAsClosed`), which would otherwise trip the test
|
|
/// framework's pending-timers invariant.
|
|
Future<void> unmountAndFlushTimers(WidgetTester tester) async {
|
|
await tester.pumpWidget(const SizedBox());
|
|
await tester.pump(const Duration(milliseconds: 1));
|
|
}
|
|
|
|
testWidgets(
|
|
'short compact window collapses into a scrollable page without overflow',
|
|
(tester) async {
|
|
await pumpScreen(tester, logicalSize: const Size(480, 400));
|
|
|
|
expect(find.byType(MealPlannerScreen), findsOneWidget);
|
|
expect(find.text('Saved Recipes'), findsOneWidget);
|
|
expect(tester.takeException(), isNull);
|
|
|
|
// The whole page scrolls: drag upward and verify the content moved up.
|
|
final before = tester.getTopLeft(find.text('Saved Recipes')).dy;
|
|
await tester.drag(find.text('Saved Recipes'), const Offset(0, -200));
|
|
await tester.pump();
|
|
final after = tester.getTopLeft(find.text('Saved Recipes')).dy;
|
|
|
|
expect(after, lessThan(before),
|
|
reason: 'the page should scroll vertically when the window is short');
|
|
expect(tester.takeException(), isNull);
|
|
await unmountAndFlushTimers(tester);
|
|
});
|
|
|
|
testWidgets(
|
|
'short wide window keeps the 7-day grid with scrollable day columns',
|
|
(tester) async {
|
|
await pumpScreen(tester, logicalSize: const Size(1100, 420));
|
|
|
|
// Wide breakpoint: all seven weekday headers render at once.
|
|
for (final label in const [
|
|
'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday',
|
|
]) {
|
|
expect(find.textContaining(label), findsWidgets);
|
|
}
|
|
expect(tester.takeException(), isNull);
|
|
|
|
// The outer page scrolls so the calendar area is reachable when the
|
|
// window is shorter than the fixed top sections + calendar.
|
|
final before = tester.getTopLeft(find.text('Saved Recipes')).dy;
|
|
await tester.drag(find.text('Saved Recipes'), const Offset(0, -200));
|
|
await tester.pump();
|
|
expect(tester.getTopLeft(find.text('Saved Recipes')).dy, lessThan(before));
|
|
expect(tester.takeException(), isNull);
|
|
await unmountAndFlushTimers(tester);
|
|
});
|
|
|
|
testWidgets('tall window uses the pinned layout without overflow',
|
|
(tester) async {
|
|
await pumpScreen(tester, logicalSize: const Size(1000, 900));
|
|
|
|
expect(find.text('Saved Recipes'), findsOneWidget);
|
|
for (final label in const [
|
|
'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday',
|
|
]) {
|
|
expect(find.textContaining(label), findsWidgets);
|
|
}
|
|
expect(tester.takeException(), isNull);
|
|
await unmountAndFlushTimers(tester);
|
|
});
|
|
|
|
testWidgets('extremely short window still renders without overflow',
|
|
(tester) async {
|
|
await pumpScreen(tester, logicalSize: const Size(1280, 320));
|
|
|
|
expect(find.byType(MealPlannerScreen), findsOneWidget);
|
|
expect(tester.takeException(), isNull);
|
|
await unmountAndFlushTimers(tester);
|
|
});
|
|
}
|