import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:relationship_saver/core/auth/in_memory_token_store.dart'; import 'package:relationship_saver/core/config/app_theme.dart'; import 'package:relationship_saver/features/auth/sign_in_view.dart'; import 'package:relationship_saver/features/dashboard/dashboard_view.dart'; import 'package:relationship_saver/features/home/app_shell.dart'; import 'package:relationship_saver/features/ideas/ideas_view.dart'; import 'package:relationship_saver/features/local/storage/local_data_store_in_memory.dart'; import 'package:relationship_saver/features/local/storage/local_data_store_provider.dart'; import 'package:relationship_saver/features/moments/moments_view.dart'; import 'package:relationship_saver/features/people/people_view.dart'; import 'package:relationship_saver/features/reminders/reminders_view.dart'; import 'package:relationship_saver/features/settings/settings_view.dart'; import 'package:relationship_saver/features/signals/signals_view.dart'; import 'package:relationship_saver/features/sync/storage/sync_state_store_in_memory.dart'; import 'package:relationship_saver/features/sync/storage/sync_state_store_provider.dart'; import 'package:relationship_saver/features/sync/sync_view.dart'; import 'package:relationship_saver/integrations/backend/backend_gateway_fake.dart'; import 'package:relationship_saver/integrations/backend/backend_gateway_provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; void main() { final List breakpoints = [ const Breakpoint('iphone-se', Size(320, 568)), const Breakpoint('iphone-pro-max', Size(430, 932)), const Breakpoint('ipad-portrait', Size(768, 1024)), const Breakpoint('web-desktop', Size(1280, 800)), ]; setUp(() { SharedPreferences.setMockInitialValues({}); }); for (final Breakpoint breakpoint in breakpoints) { testWidgets('AppShell renders across breakpoint: ${breakpoint.name}', ( WidgetTester tester, ) async { await pumpResponsive( tester, size: breakpoint.size, child: const AppShell(), wrapInScaffold: false, ); expect(find.byType(AppShell), findsOneWidget); assertNoFlutterExceptions( tester, context: 'AppShell at ${breakpoint.name} (${breakpoint.size.width}x${breakpoint.size.height})', ); }); testWidgets( 'All primary views render across breakpoint: ${breakpoint.name}', (WidgetTester tester) async { final List views = [ const SignInView(), const DashboardView(), const PeopleView(), const MomentsView(), const IdeasView(), const RemindersView(), const SignalsView(), const SyncView(), const SettingsView(), ]; for (final Widget view in views) { await pumpResponsive(tester, size: breakpoint.size, child: view); assertNoFlutterExceptions( tester, context: '${view.runtimeType} at ${breakpoint.name} (${breakpoint.size.width}x${breakpoint.size.height})', ); } }, ); } } class Breakpoint { const Breakpoint(this.name, this.size); final String name; final Size size; } Future pumpResponsive( WidgetTester tester, { required Size size, required Widget child, bool wrapInScaffold = true, }) async { await tester.binding.setSurfaceSize(size); addTearDown(() => tester.binding.setSurfaceSize(null)); final Widget home = wrapInScaffold ? Scaffold(body: child) : child; await tester.pumpWidget( ProviderScope( overrides: [ tokenStoreProvider.overrideWithValue(InMemoryTokenStore()), backendGatewayProvider.overrideWithValue(BackendGatewayFake()), localDataStoreProvider.overrideWithValue(InMemoryLocalDataStore()), syncStateStoreProvider.overrideWithValue(InMemorySyncStateStore()), ], child: MaterialApp(theme: AppTheme.light(), home: home), ), ); await tester.pumpAndSettle(const Duration(milliseconds: 300)); } void assertNoFlutterExceptions(WidgetTester tester, {required String context}) { Object? error; final List errors = []; while ((error = tester.takeException()) != null) { errors.add(error!); } expect( errors, isEmpty, reason: 'Found Flutter exceptions for $context: $errors', ); }