diff --git a/flutter/.dart_tool/flutter_build/dart_plugin_registrant.dart b/flutter/.dart_tool/flutter_build/dart_plugin_registrant.dart new file mode 100644 index 00000000..51977a77 --- /dev/null +++ b/flutter/.dart_tool/flutter_build/dart_plugin_registrant.dart @@ -0,0 +1,142 @@ +// +// Generated file. Do not edit. +// This file is generated from template in file `flutter_tools/lib/src/flutter_plugins.dart`. +// + +// @dart = 3.3 + +import 'dart:io'; // flutter_ignore: dart_io_import. +import 'package:file_picker/file_picker.dart' as file_picker; +import 'package:shared_preferences_android/shared_preferences_android.dart' as shared_preferences_android; +import 'package:file_picker/file_picker.dart' as file_picker; +import 'package:shared_preferences_foundation/shared_preferences_foundation.dart' as shared_preferences_foundation; +import 'package:file_picker/file_picker.dart' as file_picker; +import 'package:path_provider_linux/path_provider_linux.dart' as path_provider_linux; +import 'package:shared_preferences_linux/shared_preferences_linux.dart' as shared_preferences_linux; +import 'package:file_picker/file_picker.dart' as file_picker; +import 'package:shared_preferences_foundation/shared_preferences_foundation.dart' as shared_preferences_foundation; +import 'package:file_picker/file_picker.dart' as file_picker; +import 'package:path_provider_windows/path_provider_windows.dart' as path_provider_windows; +import 'package:shared_preferences_windows/shared_preferences_windows.dart' as shared_preferences_windows; + +@pragma('vm:entry-point') +class _PluginRegistrant { + + @pragma('vm:entry-point') + static void register() { + if (Platform.isAndroid) { + try { + file_picker.FilePickerIO.registerWith(); + } catch (err) { + print( + '`file_picker` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + try { + shared_preferences_android.SharedPreferencesAndroid.registerWith(); + } catch (err) { + print( + '`shared_preferences_android` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + } else if (Platform.isIOS) { + try { + file_picker.FilePickerIO.registerWith(); + } catch (err) { + print( + '`file_picker` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + try { + shared_preferences_foundation.SharedPreferencesFoundation.registerWith(); + } catch (err) { + print( + '`shared_preferences_foundation` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + } else if (Platform.isLinux) { + try { + file_picker.FilePickerLinux.registerWith(); + } catch (err) { + print( + '`file_picker` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + try { + path_provider_linux.PathProviderLinux.registerWith(); + } catch (err) { + print( + '`path_provider_linux` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + try { + shared_preferences_linux.SharedPreferencesLinux.registerWith(); + } catch (err) { + print( + '`shared_preferences_linux` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + } else if (Platform.isMacOS) { + try { + file_picker.FilePickerMacOS.registerWith(); + } catch (err) { + print( + '`file_picker` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + try { + shared_preferences_foundation.SharedPreferencesFoundation.registerWith(); + } catch (err) { + print( + '`shared_preferences_foundation` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + } else if (Platform.isWindows) { + try { + file_picker.FilePickerWindows.registerWith(); + } catch (err) { + print( + '`file_picker` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + try { + path_provider_windows.PathProviderWindows.registerWith(); + } catch (err) { + print( + '`path_provider_windows` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + try { + shared_preferences_windows.SharedPreferencesWindows.registerWith(); + } catch (err) { + print( + '`shared_preferences_windows` threw an error: $err. ' + 'The app may not function as expected until you remove this plugin from pubspec.yaml' + ); + } + + } + } +} diff --git a/flutter/Dockerfile b/flutter/Dockerfile index 0fab7212..de548d2e 100644 --- a/flutter/Dockerfile +++ b/flutter/Dockerfile @@ -11,6 +11,9 @@ COPY . . # Generate localizations (ARB -> Dart) before the main build. RUN flutter gen-l10n +# Run tests +RUN flutter test + # Inject API base URL at build time via --dart-define. # Default to same-origin /api to avoid mixed-content in HTTPS deployments. ARG API_BASE_URL=/api diff --git a/flutter/build/native_assets/windows/native_assets.json b/flutter/build/native_assets/windows/native_assets.json new file mode 100644 index 00000000..523bfc7c --- /dev/null +++ b/flutter/build/native_assets/windows/native_assets.json @@ -0,0 +1 @@ +{"format-version":[1,0,0],"native-assets":{}} \ No newline at end of file diff --git a/flutter/build/unit_test_assets/AssetManifest.bin b/flutter/build/unit_test_assets/AssetManifest.bin new file mode 100644 index 00000000..86d111f0 Binary files /dev/null and b/flutter/build/unit_test_assets/AssetManifest.bin differ diff --git a/flutter/build/unit_test_assets/FontManifest.json b/flutter/build/unit_test_assets/FontManifest.json new file mode 100644 index 00000000..3abf18c4 --- /dev/null +++ b/flutter/build/unit_test_assets/FontManifest.json @@ -0,0 +1 @@ +[{"family":"MaterialIcons","fonts":[{"asset":"fonts/MaterialIcons-Regular.otf"}]}] \ No newline at end of file diff --git a/flutter/build/unit_test_assets/NOTICES.Z b/flutter/build/unit_test_assets/NOTICES.Z new file mode 100644 index 00000000..ee7a19af Binary files /dev/null and b/flutter/build/unit_test_assets/NOTICES.Z differ diff --git a/flutter/build/unit_test_assets/NativeAssetsManifest.json b/flutter/build/unit_test_assets/NativeAssetsManifest.json new file mode 100644 index 00000000..523bfc7c --- /dev/null +++ b/flutter/build/unit_test_assets/NativeAssetsManifest.json @@ -0,0 +1 @@ +{"format-version":[1,0,0],"native-assets":{}} \ No newline at end of file diff --git a/flutter/build/unit_test_assets/fonts/MaterialIcons-Regular.otf b/flutter/build/unit_test_assets/fonts/MaterialIcons-Regular.otf new file mode 100644 index 00000000..8c992661 Binary files /dev/null and b/flutter/build/unit_test_assets/fonts/MaterialIcons-Regular.otf differ diff --git a/flutter/build/unit_test_assets/shaders/ink_sparkle.frag b/flutter/build/unit_test_assets/shaders/ink_sparkle.frag new file mode 100644 index 00000000..794ba24a Binary files /dev/null and b/flutter/build/unit_test_assets/shaders/ink_sparkle.frag differ diff --git a/flutter/build/unit_test_assets/shaders/stretch_effect.frag b/flutter/build/unit_test_assets/shaders/stretch_effect.frag new file mode 100644 index 00000000..c014a194 Binary files /dev/null and b/flutter/build/unit_test_assets/shaders/stretch_effect.frag differ diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index 2ff8347e..5e163e19 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -26,6 +26,7 @@ dev_dependencies: sdk: flutter flutter_lints: ^4.0.0 build_runner: ^2.4.9 + mockito: ^5.4.4 flutter: uses-material-design: true diff --git a/flutter/test/features/profile/data/profile_repository_test.dart b/flutter/test/features/profile/data/profile_repository_test.dart new file mode 100644 index 00000000..ac7b2753 --- /dev/null +++ b/flutter/test/features/profile/data/profile_repository_test.dart @@ -0,0 +1,59 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/mockito.dart'; +import 'package:recipe_flutter/core/api/api_client.dart'; +import 'package:recipe_flutter/core/api/api_exception.dart'; +import 'package:recipe_flutter/features/profile/data/profile_repository.dart'; + +class MockApiClient extends Mock implements ApiClient {} + +void main() { + group('ProfileRepository', () { + late ProfileRepository profileRepository; + late MockApiClient mockApiClient; + + setUp(() { + mockApiClient = MockApiClient(); + profileRepository = ProfileRepository(mockApiClient); + }); + + group('getProfile', () { + test('should return profile data when API call is successful', () async { + final expectedProfile = {'username': 'testuser', 'email': 'test@example.com'}; + when(mockApiClient.getJson('/api/profile')).thenAnswer((_) async => expectedProfile); + + final result = await profileRepository.getProfile(); + + expect(result, expectedProfile); + verify(mockApiClient.getJson('/api/profile')).called(1); + }); + + test('should throw ApiException when API call fails', () async { + when(mockApiClient.getJson('/api/profile')).thenThrow(ApiException('Failed to fetch profile')); + + expect(() => profileRepository.getProfile(), throwsA(isA())); + verify(mockApiClient.getJson('/api/profile')).called(1); + }); + }); + + group('updateProfile', () { + test('should return updated profile data when API call is successful', () async { + final profileData = {'username': 'newuser', 'email': 'new@example.com'}; + final expectedProfile = {'username': 'newuser', 'email': 'new@example.com'}; + when(mockApiClient.patchJson('/api/profile', profileData)).thenAnswer((_) async => expectedProfile); + + final result = await profileRepository.updateProfile(profileData); + + expect(result, expectedProfile); + verify(mockApiClient.patchJson('/api/profile', profileData)).called(1); + }); + + test('should throw ApiException when API call fails', () async { + final profileData = {'username': 'newuser', 'email': 'new@example.com'}; + when(mockApiClient.patchJson('/api/profile', profileData)).thenThrow(ApiException('Failed to update profile')); + + expect(() => profileRepository.updateProfile(profileData), throwsA(isA())); + verify(mockApiClient.patchJson('/api/profile', profileData)).called(1); + }); + }); + }); +} \ No newline at end of file