diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 93146e09..35bb9666 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,7 +17,7 @@ on: workflow_dispatch: env: - flutter_version: "2.10.x" + flutter_version: "3.0.x" flutter_channel: "stable" java_version: "12.x" diff --git a/docs/README.md b/docs/README.md index 9d2c6903..0d696740 100644 --- a/docs/README.md +++ b/docs/README.md @@ -73,6 +73,14 @@ To generate the OpenSource licenses dart file via [flutter_oss_licenses](https:/ >Note: Run `flutter format .` once [oss_licenses.dart](../lib/presentation/licenses/oss_licenses.dart) is created. +## Running tests and generating Test Report + +- Step 1: Just for the 1st time, to make sure that all files are included, run ```./.github/scripts/coverage_gen.sh``` to generate a report for the whole project. +- Step 2: Run ```flutter test --coverage```. This will generate the report locally. +- Step 3: Run ```genhtml coverage/lcov.info -o coverage```. +- Step 4: Run ``` firefox coverage/index.html``` (or run ```coverage/index.html``` to any of your web browser). +#### You should see the coverage of your tests line-wise in Codecov. + ## Getting Started with Flutter A few resources to get you started if this is your first Flutter project: diff --git a/lib/domain/user/user.dart b/lib/domain/user/user.dart index 5f119ff1..4a978c80 100644 --- a/lib/domain/user/user.dart +++ b/lib/domain/user/user.dart @@ -10,7 +10,7 @@ class User with _$User { @visibleForTesting // ignore: avoid_positional_boolean_parameters static Future getAnonymousIdToken([bool forceRefresh = false]) => - Future.value(null); + Future.value(); static const User anonymous = User( id: 'anonymous', diff --git a/lib/presentation/home/home_screen.dart b/lib/presentation/home/home_screen.dart index 0ea7ead7..214e1755 100644 --- a/lib/presentation/home/home_screen.dart +++ b/lib/presentation/home/home_screen.dart @@ -19,7 +19,7 @@ class _HomePageState extends State { @override void initState() { super.initState(); - WidgetsBinding.instance?.addPostFrameCallback((_) { + WidgetsBinding.instance.addPostFrameCallback((_) { checkAndMaybeShowOnboarding(); }); } diff --git a/lib/presentation/shared_widgets/photo_selector.dart b/lib/presentation/shared_widgets/photo_selector.dart index 9acb55e7..395a4ee8 100644 --- a/lib/presentation/shared_widgets/photo_selector.dart +++ b/lib/presentation/shared_widgets/photo_selector.dart @@ -121,7 +121,7 @@ class _PhotoSelectorState extends State { final _compression = 100; Future _cropImage(XFile image) async { - final File? croppedFile = await ImageCropper.cropImage( + final CroppedFile? croppedFile = await ImageCropper().cropImage( sourcePath: image.path, aspectRatio: const CropAspectRatio(ratioX: 1, ratioY: 1), aspectRatioPresets: [CropAspectRatioPreset.square], @@ -129,21 +129,23 @@ class _PhotoSelectorState extends State { maxWidth: 1023, maxHeight: 1023, compressQuality: _compression, - androidUiSettings: const AndroidUiSettings( - toolbarTitle: 'Profile Photo', - toolbarColor: kAccentColor, - toolbarWidgetColor: Colors.white, - lockAspectRatio: true, - ), - iosUiSettings: const IOSUiSettings( - minimumAspectRatio: 1.0, - aspectRatioLockEnabled: true, - title: 'Profile Photo', - ), + uiSettings: [ + AndroidUiSettings( + toolbarTitle: 'Profile Photo', + toolbarColor: kAccentColor, + toolbarWidgetColor: Colors.white, + lockAspectRatio: true, + ), + IOSUiSettings( + minimumAspectRatio: 1.0, + aspectRatioLockEnabled: true, + title: 'Profile Photo', + ), + ], ); if (widget.onSelected != null && croppedFile != null) { - widget.onSelected!(croppedFile); + widget.onSelected!(File(croppedFile.path)); } } diff --git a/pubspec.lock b/pubspec.lock index a7808764..07283c54 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,28 +7,28 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "31.0.0" + version: "38.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "2.8.0" + version: "3.4.1" archive: dependency: transitive description: name: archive url: "https://pub.dartlang.org" source: hosted - version: "3.1.6" + version: "3.3.0" args: dependency: transitive description: name: args url: "https://pub.dartlang.org" source: hosted - version: "2.3.0" + version: "2.3.1" async: dependency: transitive description: @@ -42,14 +42,14 @@ packages: name: auto_route url: "https://pub.dartlang.org" source: hosted - version: "3.2.4" + version: "4.0.1" auto_route_generator: dependency: "direct dev" description: name: auto_route_generator url: "https://pub.dartlang.org" source: hosted - version: "3.2.3" + version: "4.0.0" bloc: dependency: "direct main" description: @@ -77,7 +77,7 @@ packages: name: build url: "https://pub.dartlang.org" source: hosted - version: "2.2.1" + version: "2.3.0" build_config: dependency: transitive description: @@ -91,7 +91,7 @@ packages: name: build_daemon url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.1.0" build_resolvers: dependency: transitive description: @@ -105,7 +105,7 @@ packages: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "2.1.7" + version: "2.1.11" build_runner_core: dependency: transitive description: @@ -126,14 +126,14 @@ packages: name: built_value url: "https://pub.dartlang.org" source: hosted - version: "8.1.3" + version: "8.3.3" cached_network_image: dependency: "direct main" description: name: cached_network_image url: "https://pub.dartlang.org" source: hosted - version: "3.2.0" + version: "3.2.1" cached_network_image_platform_interface: dependency: transitive description: @@ -169,13 +169,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.1" - cli_util: - dependency: transitive - description: - name: cli_util - url: "https://pub.dartlang.org" - source: hosted - version: "0.3.5" clock: dependency: transitive description: @@ -196,21 +189,21 @@ packages: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0" + version: "1.16.0" convert: dependency: transitive description: name: convert url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.2" country_codes: dependency: "direct main" description: name: country_codes url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.2.0" country_icons: dependency: "direct main" description: @@ -224,42 +217,42 @@ packages: name: coverage url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.3.2" cross_file: dependency: transitive description: name: cross_file url: "https://pub.dartlang.org" source: hosted - version: "0.3.2" + version: "0.3.3+1" crypto: dependency: transitive description: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.2" csslib: dependency: transitive description: name: csslib url: "https://pub.dartlang.org" source: hosted - version: "0.17.1" + version: "0.17.2" cupertino_icons: dependency: "direct main" description: name: cupertino_icons url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "1.0.5" dart_pubspec_licenses: dependency: transitive description: name: dart_pubspec_licenses url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "2.0.2" dart_style: dependency: transitive description: @@ -287,7 +280,7 @@ packages: name: dots_indicator url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" + version: "2.1.0" email_validator: dependency: "direct main" description: @@ -308,21 +301,21 @@ packages: name: expandable_page_view url: "https://pub.dartlang.org" source: hosted - version: "1.0.13" + version: "1.0.14" fake_async: dependency: transitive description: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.0" ffi: dependency: transitive description: name: ffi url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.2.1" file: dependency: transitive description: @@ -336,28 +329,28 @@ packages: name: firebase_analytics url: "https://pub.dartlang.org" source: hosted - version: "9.1.8" + version: "9.1.10" firebase_analytics_platform_interface: dependency: transitive description: name: firebase_analytics_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "3.1.6" + version: "3.1.8" firebase_analytics_web: dependency: transitive description: name: firebase_analytics_web url: "https://pub.dartlang.org" source: hosted - version: "0.4.0+13" + version: "0.4.0+15" firebase_auth: dependency: "direct main" description: name: firebase_auth url: "https://pub.dartlang.org" source: hosted - version: "3.3.18" + version: "3.3.20" firebase_auth_mocks: dependency: "direct dev" description: @@ -371,77 +364,77 @@ packages: name: firebase_auth_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "6.2.6" + version: "6.2.8" firebase_auth_web: dependency: transitive description: name: firebase_auth_web url: "https://pub.dartlang.org" source: hosted - version: "3.3.15" + version: "3.3.17" firebase_core: dependency: "direct main" description: name: firebase_core url: "https://pub.dartlang.org" source: hosted - version: "1.17.0" + version: "1.18.0" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "4.4.0" + version: "4.4.1" firebase_core_web: dependency: transitive description: name: firebase_core_web url: "https://pub.dartlang.org" source: hosted - version: "1.6.4" + version: "1.6.5" firebase_crashlytics: dependency: "direct main" description: name: firebase_crashlytics url: "https://pub.dartlang.org" source: hosted - version: "2.8.0" + version: "2.8.2" firebase_crashlytics_platform_interface: dependency: transitive description: name: firebase_crashlytics_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "3.2.6" + version: "3.2.8" firebase_remote_config: dependency: "direct main" description: name: firebase_remote_config url: "https://pub.dartlang.org" source: hosted - version: "2.0.7" + version: "2.0.9" firebase_remote_config_platform_interface: dependency: transitive description: name: firebase_remote_config_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.1.6" + version: "1.1.8" firebase_remote_config_web: dependency: transitive description: name: firebase_remote_config_web url: "https://pub.dartlang.org" source: hosted - version: "1.0.12" + version: "1.0.14" fixnum: dependency: transitive description: name: fixnum url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" flutter: dependency: "direct main" description: flutter @@ -481,21 +474,21 @@ packages: name: flutter_launcher_icons url: "https://pub.dartlang.org" source: hosted - version: "0.9.2" + version: "0.9.3" flutter_oss_licenses: dependency: "direct dev" description: name: flutter_oss_licenses url: "https://pub.dartlang.org" source: hosted - version: "1.1.4" + version: "2.0.1" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.0.6" flutter_test: dependency: "direct dev" description: flutter @@ -512,21 +505,21 @@ packages: name: freezed url: "https://pub.dartlang.org" source: hosted - version: "0.15.1+1" + version: "2.0.3+1" freezed_annotation: dependency: "direct main" description: name: freezed_annotation url: "https://pub.dartlang.org" source: hosted - version: "0.15.0" + version: "2.0.3" frontend_server_client: dependency: transitive description: name: frontend_server_client url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.3" get_it: dependency: "direct main" description: @@ -540,7 +533,7 @@ packages: name: glob url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.1.0" graphs: dependency: transitive description: @@ -568,28 +561,42 @@ packages: name: http_multi_server url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.2.1" http_parser: dependency: transitive description: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "4.0.1" image: dependency: "direct main" description: name: image url: "https://pub.dartlang.org" source: hosted - version: "3.1.3" + version: "3.2.0" image_cropper: dependency: "direct main" description: name: image_cropper url: "https://pub.dartlang.org" source: hosted - version: "1.4.1" + version: "2.0.3" + image_cropper_for_web: + dependency: transitive + description: + name: image_cropper_for_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.4" + image_cropper_platform_interface: + dependency: transitive + description: + name: image_cropper_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" image_picker: dependency: "direct main" description: @@ -603,14 +610,14 @@ packages: name: image_picker_android url: "https://pub.dartlang.org" source: hosted - version: "0.8.4+13" + version: "0.8.5+1" image_picker_for_web: dependency: transitive description: name: image_picker_for_web url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.8" image_picker_ios: dependency: transitive description: @@ -624,7 +631,7 @@ packages: name: image_picker_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.4.1" + version: "2.5.0" injectable: dependency: "direct main" description: @@ -638,7 +645,7 @@ packages: name: injectable_generator url: "https://pub.dartlang.org" source: hosted - version: "1.5.2" + version: "1.5.3" intl: dependency: "direct main" description: @@ -659,21 +666,21 @@ packages: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.3" + version: "0.6.4" json_annotation: dependency: "direct main" description: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.4.0" + version: "4.5.0" json_serializable: dependency: "direct dev" description: name: json_serializable url: "https://pub.dartlang.org" source: hosted - version: "6.1.3" + version: "6.2.0" lint: dependency: "direct dev" description: @@ -701,7 +708,7 @@ packages: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" + version: "0.1.4" meta: dependency: "direct main" description: @@ -715,21 +722,21 @@ packages: name: mime url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.0.2" mockito: dependency: "direct dev" description: name: mockito url: "https://pub.dartlang.org" source: hosted - version: "5.0.17" + version: "5.2.0" mocktail: dependency: "direct main" description: name: mocktail url: "https://pub.dartlang.org" source: hosted - version: "0.2.0" + version: "0.3.0" nested: dependency: transitive description: @@ -743,7 +750,7 @@ packages: name: network_image_mock url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.1.0" node_preamble: dependency: transitive description: @@ -764,21 +771,21 @@ packages: name: package_config url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.1.0" package_info_plus: dependency: "direct main" description: name: package_info_plus url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.4.2" package_info_plus_linux: dependency: transitive description: name: package_info_plus_linux url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.0.5" package_info_plus_macos: dependency: transitive description: @@ -799,49 +806,49 @@ packages: name: package_info_plus_web url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "1.0.5" package_info_plus_windows: dependency: transitive description: name: package_info_plus_windows url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "1.0.5" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.8.1" path_provider: dependency: transitive description: name: path_provider url: "https://pub.dartlang.org" source: hosted - version: "2.0.10" + version: "2.0.11" path_provider_android: dependency: transitive description: name: path_provider_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.14" + version: "2.0.16" path_provider_ios: dependency: transitive description: name: path_provider_ios url: "https://pub.dartlang.org" source: hosted - version: "2.0.9" + version: "2.0.10" path_provider_linux: dependency: transitive description: name: path_provider_linux url: "https://pub.dartlang.org" source: hosted - version: "2.1.4" + version: "2.1.7" path_provider_macos: dependency: transitive description: @@ -855,14 +862,14 @@ packages: name: path_provider_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "2.0.4" path_provider_windows: dependency: transitive description: name: path_provider_windows url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "2.0.7" pedantic: dependency: transitive description: @@ -876,7 +883,7 @@ packages: name: petitparser url: "https://pub.dartlang.org" source: hosted - version: "4.4.0" + version: "5.0.0" phone_number: dependency: "direct main" description: @@ -897,14 +904,14 @@ packages: name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.1.2" pool: dependency: transitive description: name: pool url: "https://pub.dartlang.org" source: hosted - version: "1.5.0" + version: "1.5.1" process: dependency: transitive description: @@ -918,14 +925,14 @@ packages: name: provider url: "https://pub.dartlang.org" source: hosted - version: "6.0.1" + version: "6.0.3" pub_semver: dependency: transitive description: name: pub_semver url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" pubspec_parse: dependency: transitive description: @@ -939,56 +946,56 @@ packages: name: rive url: "https://pub.dartlang.org" source: hosted - version: "0.8.4" + version: "0.9.0" rxdart: dependency: "direct main" description: name: rxdart url: "https://pub.dartlang.org" source: hosted - version: "0.27.3" + version: "0.27.4" share_plus: dependency: "direct main" description: name: share_plus url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "4.0.10" share_plus_linux: dependency: transitive description: name: share_plus_linux url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "3.0.0" share_plus_macos: dependency: transitive description: name: share_plus_macos url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "3.0.1" share_plus_platform_interface: dependency: transitive description: name: share_plus_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.1" + version: "3.0.3" share_plus_web: dependency: transitive description: name: share_plus_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "3.0.1" share_plus_windows: dependency: transitive description: name: share_plus_windows url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "3.0.1" shared_preferences: dependency: "direct main" description: @@ -1002,28 +1009,28 @@ packages: name: shared_preferences_android url: "https://pub.dartlang.org" source: hosted - version: "2.0.9" + version: "2.0.12" shared_preferences_ios: dependency: transitive description: name: shared_preferences_ios url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" + version: "2.1.1" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.1.1" shared_preferences_macos: dependency: transitive description: name: shared_preferences_macos url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.0.4" shared_preferences_platform_interface: dependency: transitive description: @@ -1037,42 +1044,42 @@ packages: name: shared_preferences_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "2.0.4" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.1.1" shelf: dependency: transitive description: name: shelf url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.1" shelf_packages_handler: dependency: transitive description: name: shelf_packages_handler url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" shelf_static: dependency: transitive description: name: shelf_static url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" shelf_web_socket: dependency: transitive description: name: shelf_web_socket url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.0.2" shimmer: dependency: "direct main" description: @@ -1091,14 +1098,14 @@ packages: name: source_gen url: "https://pub.dartlang.org" source: hosted - version: "1.2.1" + version: "1.2.2" source_helper: dependency: transitive description: name: source_helper url: "https://pub.dartlang.org" source: hosted - version: "1.3.1" + version: "1.3.2" source_map_stack_trace: dependency: transitive description: @@ -1119,7 +1126,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" sqflite: dependency: transitive description: @@ -1182,21 +1189,21 @@ packages: name: test url: "https://pub.dartlang.org" source: hosted - version: "1.19.5" + version: "1.20.2" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.8" + version: "0.4.9" test_core: dependency: transitive description: name: test_core url: "https://pub.dartlang.org" source: hosted - version: "0.4.9" + version: "0.4.11" timing: dependency: transitive description: @@ -1210,7 +1217,7 @@ packages: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.1" universal_html: dependency: transitive description: @@ -1231,56 +1238,56 @@ packages: name: url_launcher url: "https://pub.dartlang.org" source: hosted - version: "6.1.2" + version: "6.1.4" url_launcher_android: dependency: transitive description: name: url_launcher_android url: "https://pub.dartlang.org" source: hosted - version: "6.0.13" + version: "6.0.17" url_launcher_ios: dependency: transitive description: name: url_launcher_ios url: "https://pub.dartlang.org" source: hosted - version: "6.0.13" + version: "6.0.17" url_launcher_linux: dependency: transitive description: name: url_launcher_linux url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "3.0.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "3.0.1" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "2.0.4" + version: "2.1.0" url_launcher_web: dependency: transitive description: name: url_launcher_web url: "https://pub.dartlang.org" source: hosted - version: "2.0.5" + version: "2.0.12" url_launcher_windows: dependency: transitive description: name: url_launcher_windows url: "https://pub.dartlang.org" source: hosted - version: "2.0.2" + version: "3.0.1" uuid: dependency: transitive description: @@ -1294,14 +1301,14 @@ packages: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "2.1.2" vm_service: dependency: transitive description: name: vm_service url: "https://pub.dartlang.org" source: hosted - version: "7.5.0" + version: "8.3.0" watcher: dependency: transitive description: @@ -1315,14 +1322,14 @@ packages: name: web_socket_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.2.0" webkit_inspection_protocol: dependency: transitive description: name: webkit_inspection_protocol url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.1.0" webview_flutter: dependency: "direct main" description: @@ -1336,49 +1343,49 @@ packages: name: webview_flutter_android url: "https://pub.dartlang.org" source: hosted - version: "2.8.8" + version: "2.8.14" webview_flutter_platform_interface: dependency: transitive description: name: webview_flutter_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.9.1" webview_flutter_wkwebview: dependency: transitive description: name: webview_flutter_wkwebview url: "https://pub.dartlang.org" source: hosted - version: "2.7.5" + version: "2.8.1" win32: dependency: transitive description: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "2.3.3" + version: "2.6.1" xdg_directories: dependency: transitive description: name: xdg_directories url: "https://pub.dartlang.org" source: hosted - version: "0.2.0" + version: "0.2.0+1" xml: dependency: transitive description: name: xml url: "https://pub.dartlang.org" source: hosted - version: "5.3.1" + version: "6.1.0" yaml: dependency: transitive description: name: yaml url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "3.1.1" sdks: - dart: ">=2.16.0 <3.0.0" - flutter: ">=2.8.1" + dart: ">=2.17.0 <3.0.0" + flutter: ">=3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 13a46a25..9635e1cf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,7 +21,7 @@ environment: sdk: ">=2.12.0 <3.0.0" dependencies: - auto_route: ^3.2.2 + auto_route: ^4.0.1 bloc: ^8.0.2 cached_network_image: ^3.2.0 country_codes: ^2.1.1 @@ -41,37 +41,37 @@ dependencies: sdk: flutter flutter_bloc: ^8.0.1 flutter_dotenv: ^5.0.2 - freezed_annotation: ^0.15.0 + freezed_annotation: ^2.0.3 get_it: ^7.2.0 http: ^0.13.4 image: ^3.1.1 - image_cropper: ^1.4.1 + image_cropper: ^2.0.3 image_picker: ^0.8.4+7 injectable: ^1.5.3 intl: ^0.17.0 json_annotation: ^4.4.0 meta: ^1.7.0 - mocktail: ^0.2.0 + mocktail: ^0.3.0 package_info_plus: ^1.3.0 phone_number: ^0.12.0+1 - rive: ^0.8.1 + rive: ^0.9.0 rxdart: ^0.27.3 - share_plus: ^3.0.4 + share_plus: ^4.0.10 shared_preferences: ^2.0.13 shimmer: ^2.0.0 url_launcher: ^6.0.18 webview_flutter: ^3.0.0 dev_dependencies: - auto_route_generator: ^3.2.1 + auto_route_generator: ^4.0.0 bloc_test: ^9.0.2 build_runner: ^2.1.7 firebase_auth_mocks: ^0.8.2 flutter_launcher_icons: ^0.9.2 - flutter_oss_licenses: ^1.1.1 + flutter_oss_licenses: ^2.0.1 flutter_test: sdk: flutter - freezed: ^0.15.1+1 + freezed: ^2.0.3+1 injectable_generator: ^1.5.2 json_serializable: ^6.1.3 lint: ^1.8.2 diff --git a/test/application/auth/auth_bloc_tests.dart b/test/application/auth/auth_bloc_tests.dart deleted file mode 100644 index d65efcd2..00000000 --- a/test/application/auth/auth_bloc_tests.dart +++ /dev/null @@ -1,113 +0,0 @@ -import 'package:bloc_test/bloc_test.dart'; -import 'package:collaction_app/application/auth/auth_bloc.dart'; -import 'package:collaction_app/domain/auth/auth_failures.dart'; -import 'package:collaction_app/domain/auth/auth_success.dart'; -import 'package:collaction_app/domain/auth/i_auth_repository.dart'; -import 'package:collaction_app/domain/user/i_user_repository.dart'; -import 'package:dartz/dartz.dart'; -import 'package:mocktail/mocktail.dart'; -// ignore: depend_on_referenced_packages -import 'package:test/test.dart'; - -class MockAuthRepository extends Mock implements IAuthRepository {} - -void main() { - group('Authentication BLoC', () { - test('Initial auth state', () { - final bloc = AuthBloc(MockAuthRepository()); - expect(bloc.state, const AuthState.initial()); - }); - - const verificationId = 'verificationId'; - const smsCode = '123456'; - - registerFallbackValue( - const Credential(verificationId: verificationId, smsCode: smsCode), - ); - - final userRepository = MockAuthRepository(); - - { - when( - () => userRepository.verifyPhone( - phoneNumber: any(named: 'phoneNumber'), - ), - ).thenAnswer( - (_) => Stream.fromIterable([ - right( - const AuthSuccess.codeSent( - credential: Credential( - verificationId: verificationId, - ), - ), - ), - ]), - ); - - when( - () => userRepository.signInWithPhone( - authCredentials: any(named: 'authCredentials'), - ), - ).thenAnswer((_) => Future.value(right(true))); - - blocTest( - '"Happy path" transition coverage', - build: () => AuthBloc(userRepository), - act: (AuthBloc bloc) { - bloc.add(const AuthEvent.verifyPhone('+1234567890')); - }, - expect: () => [ - const AuthState.awaitingVerification(), - const AuthState.smsCodeSent(), - ], - ); - - blocTest( - 'SMS Submission', - build: () => AuthBloc(userRepository), - act: (AuthBloc bloc) async { - bloc.add(const AuthEvent.verifyPhone('+1234567890')); - await Future.delayed(const Duration(seconds: 2)); - bloc.add(const AuthEvent.signInWithPhone(smsCode)); - }, - expect: () => [ - const AuthState.awaitingVerification(), - const AuthState.smsCodeSent(), - const AuthState.signingInUser(), - const AuthState.loggedIn(isNewUser: true), - ], - ); - } - - { - final userRepository = MockAuthRepository(); - const error = AuthFailure.verificationFailed(); - when( - () => userRepository.verifyPhone( - phoneNumber: any(named: 'phoneNumber'), - ), - ).thenAnswer((_) => Stream.fromIterable([left(error)])); - - blocTest( - 'Error auth states', - build: () => AuthBloc(userRepository), - act: (AuthBloc bloc) { - bloc.add(const AuthEvent.verifyPhone('+1234567890')); - }, - expect: () => [ - const AuthState.awaitingVerification(), - const AuthState.authError(error) - ], - ); - } - - blocTest( - 'Reset to initial auth state', - build: () => AuthBloc(MockAuthRepository()), - act: (AuthBloc bloc) { - bloc.add(const AuthEvent.reset()); - }, - expect: () => [const AuthState.initial()], - ); - }); -} diff --git a/test/application/user/avatar_bloc_fixtures.dart b/test/application/user/avatar_bloc_fixtures.dart index 6d8f01f0..ec0ee26c 100644 --- a/test/application/user/avatar_bloc_fixtures.dart +++ b/test/application/user/avatar_bloc_fixtures.dart @@ -1,15 +1,9 @@ -import 'dart:io'; - import 'package:collaction_app/application/user/avatar/avatar_bloc.dart'; -import 'package:collaction_app/infrastructure/user/avatar_repository.dart'; -import 'package:mocktail/mocktail.dart'; - -class MockAvatarRepo extends Mock implements AvatarRepository {} -class MockAvatarFile extends Mock implements File {} +import '../../test_utilities.dart'; -final avatarRepo = MockAvatarRepo(); -final avatarRepo2 = MockAvatarRepo(); +final avatarRepo = MockAvatarRepository(); +final avatarRepo2 = MockAvatarRepository(); final tAvatarBloc = AvatarBloc(avatarRepo); final tAvatarFile = MockAvatarFile(); final tUri = Uri.parse('testAvatarUploadUri'); diff --git a/test/application/user/avatar_bloc_test.dart b/test/application/user/avatar_bloc_test.dart index c95de6ca..57a9bcea 100644 --- a/test/application/user/avatar_bloc_test.dart +++ b/test/application/user/avatar_bloc_test.dart @@ -4,7 +4,7 @@ import 'package:collaction_app/domain/user/upload_failures.dart'; import 'package:dartz/dartz.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; - +import '../../test_utilities.dart'; import 'avatar_bloc_fixtures.dart'; void main() { @@ -19,7 +19,7 @@ void main() { }); { - final avatarRepo1 = MockAvatarRepo(); + final avatarRepo1 = MockAvatarRepository(); when(() => avatarRepo1.getAvatarUploadPath()).thenAnswer( (_) => Future.value( left(const UploadPathFailure.unexpected()), @@ -39,7 +39,7 @@ void main() { } { - final avatarRepo2 = MockAvatarRepo(); + final avatarRepo2 = MockAvatarRepository(); when(() => avatarRepo2.getAvatarUploadPath()).thenAnswer( (_) => Future.value(right(tUri)), @@ -62,7 +62,7 @@ void main() { ); } { - final avatarRepo3 = MockAvatarRepo(); + final avatarRepo3 = MockAvatarRepository(); when(() => avatarRepo3.getAvatarUploadPath()).thenAnswer( (_) => Future.value(right(tUri)), ); diff --git a/test/application/user/profile/profile_bloc_test.dart b/test/application/user/profile/profile_bloc_test.dart new file mode 100644 index 00000000..cd92dfee --- /dev/null +++ b/test/application/user/profile/profile_bloc_test.dart @@ -0,0 +1,21 @@ +import 'package:collaction_app/application/user/profile/profile_bloc.dart'; +import 'package:dartz/dartz.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; + +import 'profile_fixtures.dart'; + +void main() { + group('Testing Profile BLoC initial state', () { + test('Testing initial state', () { + expect(tProfileBloc.state, ProfileState.initial()); + }); + + { + final tProfileRepository1 = tProfileRepository; + when(() => tProfileRepository1.getUserProfile()).thenAnswer( + (_) => Future.value(right(tUserProfile)), + ); + } + }); +} diff --git a/test/application/user/profile/profile_fixtures.dart b/test/application/user/profile/profile_fixtures.dart new file mode 100644 index 00000000..07449d69 --- /dev/null +++ b/test/application/user/profile/profile_fixtures.dart @@ -0,0 +1,13 @@ +import 'package:collaction_app/application/user/profile/profile_bloc.dart'; +import 'package:collaction_app/domain/profile/profile.dart'; +import 'package:collaction_app/domain/profile/user_profile.dart'; +import 'package:collaction_app/domain/user/user.dart'; + +import '../../../test_utilities.dart'; + +final tProfileRepository = MockProfileRepository(); +final tAvatarRepository = MockAvatarRepository(); +const tUser = User(id: 'tId', getIdToken: getAnonymousIdToken); +const tProfile = Profile(bio: 'tBio'); +const tUserProfile = UserProfile(user: tUser, profile: tProfile); +final tProfileBloc = ProfileBloc(tProfileRepository, tAvatarRepository); diff --git a/test/application/user_details/user_details_bloc_test.dart b/test/application/user_details/user_details_bloc_test.dart new file mode 100644 index 00000000..ee58ad00 --- /dev/null +++ b/test/application/user_details/user_details_bloc_test.dart @@ -0,0 +1,37 @@ +import 'dart:async'; + +import 'package:bloc_test/bloc_test.dart'; +import 'package:collaction_app/application/user_details/user_details_bloc.dart'; +import 'package:collaction_app/domain/user/user.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; + +import 'user_details_fixtures.dart'; + +void main() { + group('test User Details BLoC', () { + final UserDetailsBloc tUserBloc = UserDetailsBloc(tUserRepo); + + test('testing Initial UserDetails BLoC State', () { + expect(tUserBloc.state, const UserDetailsState.initial()); + }); + + when(() => tUserRepo.observeUser()).thenAnswer((_) { + final x = StreamController(); + x.add(tUser); + return x.stream.distinct(); + }); + + blocTest( + 'testing fetchDetails event', + build: () => tUserBloc, + act: (UserDetailsBloc bloc) { + bloc.add(const UserDetailsEvent.fetchDetails()); + }, + expect: () => [ + const UserDetailsState.fetchingDetails(), + const UserDetailsState.fetchingDetailsFailed(), + ], + ); + }); +} diff --git a/test/application/user_details/user_details_fixtures.dart b/test/application/user_details/user_details_fixtures.dart new file mode 100644 index 00000000..e5584bd8 --- /dev/null +++ b/test/application/user_details/user_details_fixtures.dart @@ -0,0 +1,17 @@ +import 'package:collaction_app/domain/user/i_user_repository.dart'; +import 'package:collaction_app/domain/user/user.dart'; + +import 'package:mocktail/mocktail.dart'; + +class MockUserRepository extends Mock implements IUserRepository {} + +final IUserRepository tUserRepo = MockUserRepository(); + +// ignore: avoid_positional_boolean_parameters +Future testGetAnonymousTokenId([bool forceRefresh = false]) => + Future.value(); + +const User tUser = User( + id: 'tId', + getIdToken: testGetAnonymousTokenId, +); diff --git a/test/domain/auth/auth_fixtures.dart b/test/domain/auth/auth_fixtures.dart new file mode 100644 index 00000000..3ee5d1bf --- /dev/null +++ b/test/domain/auth/auth_fixtures.dart @@ -0,0 +1,9 @@ +const invalidEmail = 'akdjsfhcaksd'; +const validEmail = 'test@test.com'; +const emptyUsername = ''; +const shortUsername = 'abc'; +const longUsername = 'abcdefghijklmnopqrstuvwxyz'; +const invalidUsername = '\$1234'; +const validUsername = 'collaction'; +const invalidPhone = '256778914357'; +const validPhone = '256 778914357'; diff --git a/test/domain/auth/value_objects_test.dart b/test/domain/auth/value_objects_test.dart new file mode 100644 index 00000000..3479f019 --- /dev/null +++ b/test/domain/auth/value_objects_test.dart @@ -0,0 +1,19 @@ +import 'package:collaction_app/domain/auth/value_objects.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'auth_fixtures.dart'; + +void main() { + test('Testing PhoneNumber instance', () { + expect(PhoneNumber(validPhone).value.isRight(), true); + expect(PhoneNumber(invalidPhone).value.isLeft(), true); + }); + test('Testing EmailAddress instance', () { + expect(EmailAddress(validEmail).value.isRight(), true); + expect(EmailAddress(invalidEmail).value.isLeft(), true); + }); + test('Testing Username instance', () { + expect(Username(invalidUsername).value.isLeft(), true); + expect(Username(validUsername).value.isRight(), true); + }); +} diff --git a/test/domain/auth/value_validators_test.dart b/test/domain/auth/value_validators_test.dart new file mode 100644 index 00000000..5813046f --- /dev/null +++ b/test/domain/auth/value_validators_test.dart @@ -0,0 +1,65 @@ +import 'package:collaction_app/domain/auth/value_validators.dart'; +import 'package:collaction_app/domain/core/value_failures.dart'; +import 'package:dartz/dartz.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'auth_fixtures.dart'; + +void main() { + group("Auth Value validators", () { + test('Validate Phone number with valid number returns right', () { + final validation = validatePhone(validPhone); + + expect(validation.isRight(), true); + }); + + test('Validate Phone number with invalid number returns left', () { + final validation = validatePhone(invalidPhone); + + expect(validation.isLeft(), true); + }); + + test('Testing validateEmailAddress() method', () { + final invalidEmailResponse = validateEmailAddress(invalidEmail); + expect( + invalidEmailResponse, + left( + const ValueFailure.invalidEmail(failedValue: invalidEmail), + ), + ); + + final validEmailResponse = validateEmailAddress(validEmail); + expect( + validEmailResponse, + right(validEmail), + ); + }); + + test('Testing validateUsername() method', () { + expect( + validateUsername(emptyUsername), + left(const ValueFailure.empty(failedValue: emptyUsername)), + ); + expect( + validateUsername(shortUsername), + left(const ValueFailure.shortUsername(failedValue: shortUsername)), + ); + expect( + validateUsername(longUsername), + left(const ValueFailure.longUsername(failedValue: longUsername)), + ); + expect( + validateUsername(invalidUsername), + left( + const ValueFailure.notStartWithLetter( + failedValue: invalidUsername, + ), + ), + ); + expect( + validateUsername(validUsername), + right(validUsername), + ); + }); + }); +} diff --git a/test/domain/auth/value_validators_tests.dart b/test/domain/auth/value_validators_tests.dart deleted file mode 100644 index e7059ffe..00000000 --- a/test/domain/auth/value_validators_tests.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:collaction_app/domain/auth/value_validators.dart'; -// ignore: depend_on_referenced_packages -import 'package:test/test.dart'; - -void main() { - group("Auth Value validators", () { - test('validate Phone number with valid number returns right', () { - const phone = "256 778914357"; - - final validation = validatePhone(phone); - - expect(validation.isRight(), true); - }); - - test('validate Phone number with invalid number returns left', () { - const phone = "256778914357"; - - final validation = validatePhone(phone); - - expect(validation.isLeft(), true); - }); - }); -} diff --git a/test/domain/core/core_fixtures.dart b/test/domain/core/core_fixtures.dart new file mode 100644 index 00000000..18e89ca5 --- /dev/null +++ b/test/domain/core/core_fixtures.dart @@ -0,0 +1,17 @@ +import 'package:collaction_app/domain/core/value_failures.dart'; +import 'package:collaction_app/domain/core/value_objects.dart'; +import 'package:dartz/dartz.dart'; + +class MockValueObjects extends ValueObject { + const MockValueObjects(this.value); + @override + final Either, String> value; +} + +const inputEmptyString = ''; +const inputString = 'testString'; + +const explanation = + "Encountered an error at an unrecoverable point.Terminating."; + +const failure = ValueFailure.invalidEmail(failedValue: 'inValidEmail'); diff --git a/test/domain/core/errors_test.dart b/test/domain/core/errors_test.dart new file mode 100644 index 00000000..15f8fba0 --- /dev/null +++ b/test/domain/core/errors_test.dart @@ -0,0 +1,14 @@ +import 'package:collaction_app/domain/core/errors.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'core_fixtures.dart'; + +void main() { + final unexpectedValueError = UnExpectedValueError(failure); + test('Testing errors ', () { + expect( + unexpectedValueError.toString(), + Error.safeToString('$explanation Failure was: $failure'), + ); + }); +} diff --git a/test/domain/core/value_objects_test.dart b/test/domain/core/value_objects_test.dart new file mode 100644 index 00000000..1b264e37 --- /dev/null +++ b/test/domain/core/value_objects_test.dart @@ -0,0 +1,45 @@ +import 'package:collaction_app/domain/core/value_failures.dart'; +import 'package:dartz/dartz.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'core_fixtures.dart'; + +void main() { + final mockValueObjectS = MockValueObjects(right(inputString)); + final mockValueObjectF = + MockValueObjects(left(const ValueFailure.empty(failedValue: ''))); + + test('Testing getOrCrash() method Success', () { + final response = mockValueObjectS.getOrCrash(); + expect(response, 'testString'); + }); + + test('Testing isValid function', () { + expect(mockValueObjectS.isValid(), true); + expect(mockValueObjectF.isValid(), false); + }); + + test('Testing failureOrUnit method', () { + expect(mockValueObjectS.failureOrUnit, right(unit)); + expect( + mockValueObjectF.failureOrUnit, + left(const ValueFailure.empty(failedValue: '')), + ); + }); + + test('Testing prop() function', () { + expect(mockValueObjectS.props, [right(inputString)]); + expect( + mockValueObjectF.props, + [left(const ValueFailure.empty(failedValue: ''))], + ); + }); + + test('Testing toString() function', () { + expect(mockValueObjectS.toString(), 'Value(${right(inputString)})'); + expect( + mockValueObjectF.toString(), + 'Value(${left(const ValueFailure.empty(failedValue: ''))})', + ); + }); +} diff --git a/test/domain/core/value_validators_test.dart b/test/domain/core/value_validators_test.dart new file mode 100644 index 00000000..8f31721c --- /dev/null +++ b/test/domain/core/value_validators_test.dart @@ -0,0 +1,17 @@ +import 'package:collaction_app/domain/core/value_failures.dart'; +import 'package:collaction_app/domain/core/value_validators.dart'; +import 'package:dartz/dartz.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'core_fixtures.dart'; + +void main() { + test('Testing validate string when string EMPTY', () { + final response = validateStringNotEmpty(inputEmptyString); + expect(response, left(const ValueFailure.empty(failedValue: ''))); + }); + test('Testing validate string when string is NOT EMPTY', () { + final response = validateStringNotEmpty(inputString); + expect(response, right(inputString)); + }); +} diff --git a/test/domain/profile/user_profile_test.dart b/test/domain/profile/user_profile_test.dart index 26fcd463..35429c03 100644 --- a/test/domain/profile/user_profile_test.dart +++ b/test/domain/profile/user_profile_test.dart @@ -7,7 +7,7 @@ import 'profile_fixture.dart'; void main() { group('Tests covering UserProfile', () { Future _getAnonymousIdToken([bool forceRefresh = false]) => - Future.value(null); + Future.value(); const cAnonUser = User.anonymous; final cUser = User(id: 'test', getIdToken: _getAnonymousIdToken); final cUserProfile = UserProfile(user: cUser, profile: cProfileFromJson); diff --git a/test/test_utilities.dart b/test/test_utilities.dart index 5acbad44..0bff8711 100644 --- a/test/test_utilities.dart +++ b/test/test_utilities.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:collaction_app/domain/auth/i_auth_repository.dart'; import 'package:collaction_app/domain/contact_form/contact_form_dto.dart'; import 'package:collaction_app/domain/contact_form/i_contact_form_api.dart'; @@ -5,6 +7,8 @@ import 'package:collaction_app/domain/core/i_settings_repository.dart'; import 'package:collaction_app/domain/crowdaction/crowdaction.dart'; import 'package:collaction_app/domain/crowdaction/crowdaction_status.dart'; import 'package:collaction_app/domain/crowdaction/i_crowdaction_repository.dart'; +import 'package:collaction_app/domain/user/i_avatar_repository.dart'; +import 'package:collaction_app/domain/user/i_profile_repository.dart'; import 'package:collaction_app/domain/user/i_user_repository.dart'; import 'package:collaction_app/domain/user/user.dart'; import 'package:dartz/dartz.dart'; @@ -24,6 +28,16 @@ class MockSettingsRepository extends Mock implements ISettingsRepository {} class MockContactFormApi extends Mock implements IContactFormApi {} +class MockAvatarRepository extends Mock implements IAvatarRepository {} + +class MockAvatarFile extends Mock implements File {} + +class MockProfileRepository extends Mock implements IProfileRepository {} + +// ignore: avoid_positional_boolean_parameters +Future getAnonymousIdToken([bool forceRefresh = false]) => + Future.value(); + // ignore: avoid_classes_with_only_static_members class TestUtilities { static void mockUser(Stream userStream) {