diff --git a/.github/workflows/codecov.yaml b/.github/workflows/codecov.yaml index 5ab17c02..10bae2f0 100644 --- a/.github/workflows/codecov.yaml +++ b/.github/workflows/codecov.yaml @@ -43,7 +43,12 @@ jobs: lcov --remove ./coverage/lcov.info \ "**/*.config.dart" \ "**/base_entity_*.dart" \ - "base_entity.dart" \ + "**/base_entity.dart" \ + "**/network_client.dart" \ + "**/request_data.dart" \ + "**/response_data.dart" \ + "**/base_network_injector.dart" \ + "**/result.dart" \ "**/stadata_flutter_sdk.dart" \ "**/register_module.dart" \ "**/http_*.dart" \ @@ -52,8 +57,10 @@ jobs: "**/*.g.dart" \ "**/*.freezed.dart" \ "**/*_serializer.dart" \ + "**/*_converter.dart" \ "**/service_locator.dart" \ "**/env.dart" \ + "**/api_config.dart" \ "**/usecase.dart" \ "**/injector.dart" \ "**/*_injector.dart" \ diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 262f0be1..78993b63 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -27,4 +27,4 @@ jobs: working_directory: packages/stadata_flutter_sdk flutter_channel: stable min_coverage: 80 - coverage_excludes: "**/*.config.dart **/base_entity_*.dart **/base_entity.dart **/stadata_flutter_sdk.dart **/register_module.dart **/http_*.dart **/*_http_module.dart **/*_log_*.dart **/*.g.dart **/*.freezed.dart **/*_serializer.dart **/service_locator.dart **/env.dart **/usecase.dart **/injector.dart **/*_injector.dart" + coverage_excludes: "**/*.config.dart **/base_entity_*.dart **/base_entity.dart **/stadata_flutter_sdk.dart **/register_module.dart **/http_*.dart **/*_http_module.dart **/*_log_*.dart **/*.g.dart **/*.freezed.dart **/*_serializer.dart **/*_converter.dart **/service_locator.dart **/env.dart **/usecase.dart **/injector.dart **/*_injector.dart **/network_client.dart **/request_data.dart **/response_data.dart **/api_config.dart **/base_network_injector.dart **/result.dart" diff --git a/app/example/lib/app/modules/static_table_detail/views/static_table_detail_view.dart b/app/example/lib/app/modules/static_table_detail/views/static_table_detail_view.dart index c5ac931b..27a8b197 100644 --- a/app/example/lib/app/modules/static_table_detail/views/static_table_detail_view.dart +++ b/app/example/lib/app/modules/static_table_detail/views/static_table_detail_view.dart @@ -1,11 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_widget_from_html/flutter_widget_from_html.dart'; - import 'package:get/get.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:stadata_example/app/utils/date_formatter.dart'; - import '../controllers/static_table_detail_controller.dart'; class StaticTableDetailView extends GetView { diff --git a/app/example/pubspec.lock b/app/example/pubspec.lock index f0782075..fe20dbd8 100644 --- a/app/example/pubspec.lock +++ b/app/example/pubspec.lock @@ -226,10 +226,10 @@ packages: dependency: transitive description: name: csslib - sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" + sha256: "831883fb353c8bdc1d71979e5b342c7d88acfbc643113c14ae51e2442ea0f20f" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "0.17.3" cupertino_icons: dependency: "direct main" description: @@ -254,38 +254,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.10" - dio: - dependency: transitive - description: - name: dio - sha256: "5598aa796bbf4699afd5c67c0f5f6e2ed542afc956884b9cd58c306966efc260" - url: "https://pub.dev" - source: hosted - version: "5.7.0" - dio_cache_interceptor: - dependency: transitive - description: - name: dio_cache_interceptor - sha256: fb7905c0d12075d8786a6b63bffd64ae062d053f682cfaf28d145a2686507308 - url: "https://pub.dev" - source: hosted - version: "3.5.0" - dio_smart_retry: - dependency: transitive - description: - name: dio_smart_retry - sha256: "3d71450c19b4d91ef4c7d726a55a284bfc11eb3634f1f25006cdfab3f8595653" - url: "https://pub.dev" - source: hosted - version: "6.0.0" - dio_web_adapter: - dependency: transitive - description: - name: dio_web_adapter - sha256: "33259a9276d6cea88774a0000cfae0d861003497755969c92faa223108620dc8" - url: "https://pub.dev" - source: hosted - version: "2.0.0" drop_shadow: dependency: "direct main" description: @@ -330,10 +298,10 @@ packages: dependency: "direct main" description: name: extended_image - sha256: "69d4299043334ecece679996e47d0b0891cd8c29d8da0034868443506f1d9a78" + sha256: "278a62de62c96204035b68e98d6cef3cc047e8de5e43c9d859ccfb071e42188f" url: "https://pub.dev" source: hosted - version: "8.3.1" + version: "9.0.5" extended_image_library: dependency: transitive description: @@ -387,14 +355,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.4.1" + flutter_html: + dependency: "direct main" + description: + name: flutter_html + sha256: "02ad69e813ecfc0728a455e4bf892b9379983e050722b1dce00192ee2e41d1ee" + url: "https://pub.dev" + source: hosted + version: "3.0.0-beta.2" flutter_lints: dependency: "direct dev" description: name: flutter_lints - sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" + sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "5.0.0" flutter_screenutil: dependency: "direct main" description: @@ -403,54 +379,6 @@ packages: url: "https://pub.dev" source: hosted version: "5.9.3" - flutter_secure_storage: - dependency: transitive - description: - name: flutter_secure_storage - sha256: "165164745e6afb5c0e3e3fcc72a012fb9e58496fb26ffb92cf22e16a821e85d0" - url: "https://pub.dev" - source: hosted - version: "9.2.2" - flutter_secure_storage_linux: - dependency: transitive - description: - name: flutter_secure_storage_linux - sha256: "4d91bfc23047422cbcd73ac684bc169859ee766482517c22172c86596bf1464b" - url: "https://pub.dev" - source: hosted - version: "1.2.1" - flutter_secure_storage_macos: - dependency: transitive - description: - name: flutter_secure_storage_macos - sha256: "1693ab11121a5f925bbea0be725abfcfbbcf36c1e29e571f84a0c0f436147a81" - url: "https://pub.dev" - source: hosted - version: "3.1.2" - flutter_secure_storage_platform_interface: - dependency: transitive - description: - name: flutter_secure_storage_platform_interface - sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8 - url: "https://pub.dev" - source: hosted - version: "1.1.2" - flutter_secure_storage_web: - dependency: transitive - description: - name: flutter_secure_storage_web - sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - flutter_secure_storage_windows: - dependency: transitive - description: - name: flutter_secure_storage_windows - sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709 - url: "https://pub.dev" - source: hosted - version: "3.1.2" flutter_svg: dependency: transitive description: @@ -481,18 +409,18 @@ packages: dependency: "direct main" description: name: flutter_widget_from_html - sha256: "22c911b6ccf82b83e0c457d987bac4e703440fea0fc88dab24f4dfe995a5f33f" + sha256: "9e2a6201c4d2eb910b6b3ebb2a9f5c490fc61c9a1aa35eafdde38f0fc659cf4c" url: "https://pub.dev" source: hosted - version: "0.14.11" + version: "0.15.2" flutter_widget_from_html_core: dependency: transitive description: name: flutter_widget_from_html_core - sha256: cc1d9be3d187ce668ee02091cd5442dfb050cdaf98e0ab9a4d12ad008f966979 + sha256: b1048fd119a14762e2361bd057da608148a895477846d6149109b2151d2f7abf url: "https://pub.dev" source: hosted - version: "0.14.12" + version: "0.15.2" frontend_server_client: dependency: transitive description: @@ -521,10 +449,10 @@ packages: dependency: transitive description: name: fwfh_just_audio - sha256: "209cf9644599e37b0edb6961c4f30ce80d156f5a53a50355f75fb4a22f9fdb0a" + sha256: "38dc2c55803bd3cef33042c473e0c40b891ad4548078424641a32032f6a1245f" url: "https://pub.dev" source: hosted - version: "0.14.3" + version: "0.15.2" fwfh_svg: dependency: transitive description: @@ -545,10 +473,10 @@ packages: dependency: transitive description: name: fwfh_webview - sha256: b828bb5ddd4361a866cdb8f1b0de4f3348f332915ecf2f4215ba17e46c656adc + sha256: f67890bc0d6278da98bd197469ae9511c859f7db327e92299fe0ea0cf46c4057 url: "https://pub.dev" source: hosted - version: "0.14.8" + version: "0.15.2" get: dependency: "direct main" description: @@ -577,10 +505,18 @@ packages: dependency: transitive description: name: html - sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" + sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" + url: "https://pub.dev" + source: hosted + version: "0.15.4" + html_unescape: + dependency: "direct main" + description: + name: html_unescape + sha256: "15362d7a18f19d7b742ef8dcb811f5fd2a2df98db9f80ea393c075189e0b61e3" url: "https://pub.dev" source: hosted - version: "0.15.5" + version: "2.0.0" http: dependency: transitive description: @@ -617,10 +553,10 @@ packages: dependency: "direct main" description: name: intl - sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf url: "https://pub.dev" source: hosted - version: "0.18.1" + version: "0.19.0" io: dependency: transitive description: @@ -697,10 +633,18 @@ packages: dependency: transitive description: name: lints - sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "5.0.0" + list_counter: + dependency: transitive + description: + name: list_counter + sha256: c447ae3dfcd1c55f0152867090e67e219d42fe6d4f2807db4bbe8b8d69912237 + url: "https://pub.dev" + source: hosted + version: "1.0.2" logger: dependency: transitive description: @@ -969,10 +913,10 @@ packages: dependency: "direct main" description: name: skeletonizer - sha256: ff4c36e826efd5288d7a84e7619a6e9be8185d3064cecf101a9133762f3b401b + sha256: "3b202e4fa9c49b017d368fb0e570d4952bcd19972b67b2face071bdd68abbfae" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "1.4.2" sky_engine: dependency: transitive description: flutter diff --git a/app/example/pubspec.yaml b/app/example/pubspec.yaml index e0b97d5e..38a13a92 100644 --- a/app/example/pubspec.yaml +++ b/app/example/pubspec.yaml @@ -6,29 +6,31 @@ environment: sdk: ">=3.1.1 <4.0.0" dependencies: - animate_do: ^3.1.2 - cupertino_icons: ^1.0.2 + animate_do: ^3.3.4 + cupertino_icons: ^1.0.8 drop_shadow: ^0.1.0 easy_debounce: ^2.0.3 - envied: ^0.5.1 - extended_image: ^8.1.1 + envied: ^0.5.4+1 + extended_image: ^9.0.5 flutter: sdk: flutter - flutter_screenutil: ^5.9.0 + flutter_html: ^3.0.0-beta.2 + flutter_screenutil: ^5.9.3 flutter_switch: ^0.3.2 - flutter_widget_from_html: ^0.14.6 + flutter_widget_from_html: ^0.15.2 get: ^4.6.6 - intl: ^0.18.1 - number_paginator: ^0.4.0 + html_unescape: ^2.0.0 + intl: ^0.19.0 + number_paginator: ^0.4.1 reading_time: ^2.0.0 - skeletonizer: ^0.8.0 + skeletonizer: ^1.4.2 stadata_flutter_sdk: path: ../../packages/stadata_flutter_sdk dev_dependencies: - build_runner: ^2.4.6 - envied_generator: ^0.5.1 - flutter_lints: ^3.0.1 + build_runner: ^2.4.13 + envied_generator: ^0.5.4+1 + flutter_lints: ^5.0.0 flutter_test: sdk: flutter diff --git a/packages/stadata_flutter_sdk/lib/src/core/di/injector.dart b/packages/stadata_flutter_sdk/lib/src/core/di/injector.dart index d274fb9b..944b60ef 100644 --- a/packages/stadata_flutter_sdk/lib/src/core/di/injector.dart +++ b/packages/stadata_flutter_sdk/lib/src/core/di/injector.dart @@ -23,23 +23,22 @@ class Injector { ..registerLazySingleton( ApiConfig.new, ) - ..factory( + ..registerLazySingleton(Log.new) + ..factory(registerModule.logger) + ..registerLazySingleton( + StadataListImpl.new, + ) + ..factory( + registerModule.httpClient, + ) + ..factory( registerModule.listHttpClient, instanceName: 'listClient', ) - ..factory( + ..factory( registerModule.viewHttpClient, instanceName: 'viewClient', ) - ..registerLazySingleton(Log.new) - ..factory(registerModule.httpClient) - ..factory(registerModule.logger) - ..registerLazySingleton(StadataHttpModule.new) - ..registerLazySingleton(StadataListHttpModule.new) - ..registerLazySingleton(StadataViewHttpModule.new) - ..registerLazySingleton( - StadataListImpl.new, - ) ..registerLazySingleton( StadataViewImpl.new, ); diff --git a/packages/stadata_flutter_sdk/lib/src/core/di/register_module.dart b/packages/stadata_flutter_sdk/lib/src/core/di/register_module.dart index 821f065e..82e25f1e 100644 --- a/packages/stadata_flutter_sdk/lib/src/core/di/register_module.dart +++ b/packages/stadata_flutter_sdk/lib/src/core/di/register_module.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; import 'package:logger/logger.dart'; import 'package:stadata_flutter_sdk/src/config/config.dart'; import 'package:stadata_flutter_sdk/src/core/core.dart'; @@ -18,24 +19,30 @@ abstract class RegisterModule { ), ); - HttpClient get httpClient => HttpClient.init( - HttpSetting( - baseUrl: Env.apiBaseUrl, - interceptors: [AuthenticationInterceptor()], - ), + NetworkClient get httpClient => NetworkClient( + baseUrl: Env.apiBaseUrl, + interceptors: [ + if (kDebugMode) LoggingInterceptor(), + AuthInterceptor(), + RetryInterceptor(), + ], ); - HttpClient get listHttpClient => HttpClient.init( - HttpSetting( - baseUrl: '${Env.apiBaseUrl}list/', - interceptors: [AuthenticationInterceptor()], - ), + NetworkClient get listHttpClient => NetworkClient( + baseUrl: '${Env.apiBaseUrl}list/', + interceptors: [ + if (kDebugMode) LoggingInterceptor(), + AuthInterceptor(), + RetryInterceptor(), + ], ); - HttpClient get viewHttpClient => HttpClient.init( - HttpSetting( - baseUrl: '${Env.apiBaseUrl}view/', - interceptors: [AuthenticationInterceptor()], - ), + NetworkClient get viewHttpClient => NetworkClient( + baseUrl: '${Env.apiBaseUrl}view/', + interceptors: [ + if (kDebugMode) LoggingInterceptor(), + AuthInterceptor(), + RetryInterceptor(), + ], ); } diff --git a/packages/stadata_flutter_sdk/lib/src/core/exceptions/exceptions.dart b/packages/stadata_flutter_sdk/lib/src/core/exceptions/exceptions.dart index cc01353b..a072c141 100644 --- a/packages/stadata_flutter_sdk/lib/src/core/exceptions/exceptions.dart +++ b/packages/stadata_flutter_sdk/lib/src/core/exceptions/exceptions.dart @@ -1,3 +1,15 @@ +// Custom exception for handling API errors +class ApiException implements Exception { + final String message; + final int? statusCode; + + ApiException(this.message, [this.statusCode]); + + @override + String toString() => + 'ApiException: $message${statusCode != null ? ' (Status: $statusCode)' : ''}'; +} + class StadataException implements Exception { const StadataException({required this.message}); diff --git a/packages/stadata_flutter_sdk/lib/src/core/network/base_network_interceptor.dart b/packages/stadata_flutter_sdk/lib/src/core/network/base_network_interceptor.dart new file mode 100644 index 00000000..d1b90754 --- /dev/null +++ b/packages/stadata_flutter_sdk/lib/src/core/network/base_network_interceptor.dart @@ -0,0 +1,11 @@ +import 'dart:async'; + +import 'package:stadata_flutter_sdk/src/core/network/request_data.dart'; +import 'package:stadata_flutter_sdk/src/core/network/response_data.dart'; + +abstract class BaseNetworkInterceptor { + FutureOr onRequest(RequestData request) => request; + FutureOr onResponse(ResponseData response) => response; + FutureOr onError(Object error, StackTrace stackTrace) => + Future.error(error, stackTrace); +} diff --git a/packages/stadata_flutter_sdk/lib/src/core/network/http/http.dart b/packages/stadata_flutter_sdk/lib/src/core/network/http/http.dart deleted file mode 100644 index 89cdd2e1..00000000 --- a/packages/stadata_flutter_sdk/lib/src/core/network/http/http.dart +++ /dev/null @@ -1,5 +0,0 @@ -export 'http_client.dart'; -export 'http_module.dart'; -export 'http_setting.dart'; -export 'interceptors/interceptors.dart'; -export 'modules/modules.dart'; diff --git a/packages/stadata_flutter_sdk/lib/src/core/network/http/http_client.dart b/packages/stadata_flutter_sdk/lib/src/core/network/http/http_client.dart deleted file mode 100644 index cf1a92ac..00000000 --- a/packages/stadata_flutter_sdk/lib/src/core/network/http/http_client.dart +++ /dev/null @@ -1,57 +0,0 @@ -import 'dart:developer' as dev; -import 'dart:math' as math; - -import 'package:dio/dio.dart'; -import 'package:dio/io.dart'; -import 'package:dio_smart_retry/dio_smart_retry.dart'; -import 'package:flutter/foundation.dart'; -import 'package:stadata_flutter_sdk/src/config/env.dart'; -import 'package:stadata_flutter_sdk/src/core/network/http/http_setting.dart'; -import 'package:stadata_flutter_sdk/src/core/network/http/interceptors/logging_interceptor.dart'; - -class HttpClient extends DioMixin { - HttpClient._(HttpSetting setting) { - options = BaseOptions( - baseUrl: setting.baseUrl, - contentType: setting.contentType, - connectTimeout: Duration(milliseconds: setting.timeout.connectTimeout), - sendTimeout: Duration(milliseconds: setting.timeout.sendTimeout), - receiveTimeout: Duration(milliseconds: setting.timeout.receiveTimeout), - ); - - httpClientAdapter = IOHttpClientAdapter(); - final retryInterceptor = RetryInterceptor( - dio: this, - logPrint: dev.log, - retries: 7, - retryDelays: List.generate( - 7, - (index) => Duration( - milliseconds: math.min( - (3 ^ (index + 1)) + (index * 1000 + math.Random().nextInt(1000)), - 5000, - ), - ), - ), - ); - - interceptors - ..add(retryInterceptor) - ..addAll(defaultInterceptors) - ..addAll( - setting.interceptors ?? [], - ); - } - - // ignore: prefer_constructors_over_static_methods - static HttpClient init([HttpSetting? setting]) => HttpClient._( - setting ?? - const HttpSetting( - baseUrl: Env.apiBaseUrl, - ), - ); - - static List defaultInterceptors = [ - if (kDebugMode) LoggingInterceptor(), - ]; -} diff --git a/packages/stadata_flutter_sdk/lib/src/core/network/http/http_module.dart b/packages/stadata_flutter_sdk/lib/src/core/network/http/http_module.dart deleted file mode 100644 index f214b9a7..00000000 --- a/packages/stadata_flutter_sdk/lib/src/core/network/http/http_module.dart +++ /dev/null @@ -1,204 +0,0 @@ -// ignore_for_file: inference_failure_on_function_invocation - -import 'dart:async'; -import 'dart:convert'; - -import 'package:dio/dio.dart'; -import 'package:dio_cache_interceptor/dio_cache_interceptor.dart'; -import 'package:flutter/material.dart'; -import 'package:stadata_flutter_sdk/src/core/core.dart'; - -abstract class HttpModule { - HttpModule(HttpClient client) { - _client = client; - } - - @protected - late HttpClient _client; - - final Log _log = injector.get(); - - @protected - Log get log => _log; - - Future get authorizationToken => Future.value(''); - - Future get apiKeyParam async { - final token = await authorizationToken; - return '&key=$token'; - } - - JSON get headers => { - 'Content-Type': 'application/json', - }; - - JSON responseParser(Response response) { - var data = {}; - - try { - data = jsonDecode(response.toString()) as JSON; - log.console('Response: $data'); - } catch (e) { - log - ..console('Parse Error', type: LogType.fatal) - ..console( - "Response format isn't as expected | ${response.realUri}", - type: LogType.fatal, - ); - } - - return data; - } - - Future _safeCallApi(Future> call) async { - try { - final response = await call; - return responseParser(response); - } on DioException catch (error) { - await log.console('Dio Error: ${error.type}', type: LogType.fatal); - await log.console(error.message ?? '', type: LogType.fatal); - - final dioTimeout = [ - DioExceptionType.connectionTimeout, - DioExceptionType.receiveTimeout, - DioExceptionType.sendTimeout, - ]; - - if (dioTimeout.any((element) => error.type == element)) { - throw TimeoutException(error.message); - } - - throw StadataException( - message: error.message ?? 'Network Error', - ); - } on FormatException catch (e) { - await log.console('FormateException: $e', type: LogType.fatal); - throw const StadataException( - message: 'There is something wrong while trying to parse the data!', - ); - } catch (e) { - await log.console('Exception: $e', type: LogType.fatal); - rethrow; - } - } - - Future get( - String endpoint, { - JSON? param, - bool needAuthorization = true, - bool cache = false, - void Function(int, int)? onReceiveProgress, - }) async { - late Options options; - - options = cache - ? CacheOptions( - store: MemCacheStore(), - maxStale: const Duration(days: 1), - ).toOptions() - : Options(); - - final response = await _safeCallApi( - _client.get( - endpoint, - queryParameters: param, - options: options, - onReceiveProgress: onReceiveProgress, - ), - ); - - return response; - } - - Future post( - String endpoint, { - Object? body, - JSON? param, - bool needAuthorization = true, - void Function(int, int)? onSendProgress, - void Function(int, int)? onReceiveProgress, - }) async { - final options = Options(); - - final response = await _safeCallApi( - _client.post( - endpoint, - queryParameters: param, - data: body, - onReceiveProgress: onReceiveProgress, - options: options, - onSendProgress: onSendProgress, - ), - ); - - return response; - } - - Future put( - String endpoint, { - Object? body, - JSON? param, - bool needAuthorization = true, - void Function(int, int)? onSendProgress, - void Function(int, int)? onReceiveProgress, - }) async { - final options = Options(); - - final response = await _safeCallApi( - _client.put( - endpoint, - queryParameters: param, - data: body, - onReceiveProgress: onReceiveProgress, - options: options, - onSendProgress: onSendProgress, - ), - ); - - return response; - } - - Future patch( - String endpoint, { - Object? body, - JSON? param, - bool needAuthorization = true, - void Function(int, int)? onSendProgress, - void Function(int, int)? onReceiveProgress, - }) async { - final options = Options(); - - final response = await _safeCallApi( - _client.patch( - endpoint, - queryParameters: param, - data: body, - onReceiveProgress: onReceiveProgress, - options: options, - onSendProgress: onSendProgress, - ), - ); - - return response; - } - - Future delete( - String endpoint, { - Object? body, - JSON? param, - bool needAuthorization = true, - }) async { - final options = Options(); - - final response = await _safeCallApi( - _client.delete( - endpoint, - queryParameters: param, - data: body, - options: options, - ), - ); - - return response; - } -} diff --git a/packages/stadata_flutter_sdk/lib/src/core/network/http/http_setting.dart b/packages/stadata_flutter_sdk/lib/src/core/network/http/http_setting.dart deleted file mode 100644 index 86f1fab6..00000000 --- a/packages/stadata_flutter_sdk/lib/src/core/network/http/http_setting.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:dio/dio.dart'; - -class HttpSetting { - const HttpSetting({ - required this.baseUrl, - this.interceptors, - this.useHttp2 = false, - this.contentType = 'application/json', - this.timeout = const HttpTimeout(), - }); - final bool useHttp2; - final String baseUrl; - final String contentType; - final HttpTimeout timeout; - final List? interceptors; -} - -class HttpTimeout { - const HttpTimeout({ - this.connectTimeout = 30000, - this.sendTimeout = 20000, - this.receiveTimeout = 20000, - }); - final int connectTimeout; - final int sendTimeout; - final int receiveTimeout; -} diff --git a/packages/stadata_flutter_sdk/lib/src/core/network/http/interceptors/authentication_interceptor.dart b/packages/stadata_flutter_sdk/lib/src/core/network/http/interceptors/authentication_interceptor.dart deleted file mode 100644 index 3877935c..00000000 --- a/packages/stadata_flutter_sdk/lib/src/core/network/http/interceptors/authentication_interceptor.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:dio/dio.dart'; -import 'package:stadata_flutter_sdk/src/config/config.dart'; -import 'package:stadata_flutter_sdk/src/core/core.dart'; - -class AuthenticationInterceptor extends Interceptor { - ApiConfig get apiConfig => injector.get(); - - @override - Future onRequest( - RequestOptions options, - RequestInterceptorHandler handler, - ) async { - final apiKey = apiConfig.apiKey; - - options.queryParameters.addAll({'key': apiKey}); - - super.onRequest(options, handler); - } -} diff --git a/packages/stadata_flutter_sdk/lib/src/core/network/http/interceptors/interceptors.dart b/packages/stadata_flutter_sdk/lib/src/core/network/http/interceptors/interceptors.dart deleted file mode 100644 index 01b0cf12..00000000 --- a/packages/stadata_flutter_sdk/lib/src/core/network/http/interceptors/interceptors.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'authentication_interceptor.dart'; -export 'logging_interceptor.dart'; diff --git a/packages/stadata_flutter_sdk/lib/src/core/network/http/interceptors/logging_interceptor.dart b/packages/stadata_flutter_sdk/lib/src/core/network/http/interceptors/logging_interceptor.dart deleted file mode 100644 index 724bbefa..00000000 --- a/packages/stadata_flutter_sdk/lib/src/core/network/http/interceptors/logging_interceptor.dart +++ /dev/null @@ -1,99 +0,0 @@ -// ignore_for_file: cascade_invocations -import 'package:dio/dio.dart'; -import 'package:stadata_flutter_sdk/src/core/di/injector.dart'; -import 'package:stadata_flutter_sdk/src/core/log/log.dart'; - -class LoggingInterceptor extends Interceptor { - Log get log => injector.get(); - - @override - void onRequest(RequestOptions options, RequestInterceptorHandler handler) { - log - ..console('HTTP REQUEST') - ..console('==============================') - ..console( - '${options.method.toUpperCase()} ${(options.baseUrl) + options.path}', - ) - ..console('Headers:'); - options.headers.forEach( - (k, v) => log.console('$k: $v'), - ); - - log.console('Query Parameters:'); - options.queryParameters.forEach( - (k, v) => log.console('$k: $v'), - ); - - if (options.data != null) { - log.console('Body: ${options.data}'); - } - - return super.onRequest(options, handler); - } - - @override - void onResponse( - Response response, - ResponseInterceptorHandler handler, - ) { - log.console('HTTP RESPONSE'); - log.console('=============================='); - - log.console( - '${response.statusCode} (${response.statusMessage}) ' - '${response.requestOptions.baseUrl + response.requestOptions.path}', - ); - - log.console('Headers:'); - response.headers.forEach( - (k, v) => log.console('$k: $v'), - ); - - log.console('Body: ${response.data}'); - - return super.onResponse(response, handler); - } - - @override - void onError( - DioException err, - ErrorInterceptorHandler handler, - ) { - log.console( - 'HTTP ERROR', - type: LogType.error, - ); - log.console('==============================', type: LogType.error); - - final request = err.requestOptions; - - if (err.response != null) { - final response = err.response!; - log.console( - '${err.response!.statusCode} (${err.response!.statusMessage}) ' - '${request.baseUrl}${request.path}', - type: LogType.error, - ); - - log.console('Body: ${response.data}', type: LogType.error); - } else { - log.console( - '${err.error} (${err.type}) ' - '${request.baseUrl}${request.path}', - type: LogType.error, - ); - } - - if (err.response != null) { - return handler.resolve(err.response!); - } - - return handler.resolve( - Response( - requestOptions: request, - statusCode: 1000, - statusMessage: err.message, - ), - ); - } -} diff --git a/packages/stadata_flutter_sdk/lib/src/core/network/http/modules/modules.dart b/packages/stadata_flutter_sdk/lib/src/core/network/http/modules/modules.dart deleted file mode 100644 index 3f46e5df..00000000 --- a/packages/stadata_flutter_sdk/lib/src/core/network/http/modules/modules.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'stadata_http_module.dart'; -export 'stadata_list_http_module.dart'; -export 'stadata_view_http_module.dart'; diff --git a/packages/stadata_flutter_sdk/lib/src/core/network/http/modules/stadata_http_module.dart b/packages/stadata_flutter_sdk/lib/src/core/network/http/modules/stadata_http_module.dart deleted file mode 100644 index 77a8cf03..00000000 --- a/packages/stadata_flutter_sdk/lib/src/core/network/http/modules/stadata_http_module.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'package:stadata_flutter_sdk/src/core/core.dart'; - -class StadataHttpModule extends HttpModule { - StadataHttpModule() : super(injector.get()); -} diff --git a/packages/stadata_flutter_sdk/lib/src/core/network/http/modules/stadata_list_http_module.dart b/packages/stadata_flutter_sdk/lib/src/core/network/http/modules/stadata_list_http_module.dart deleted file mode 100644 index de717b40..00000000 --- a/packages/stadata_flutter_sdk/lib/src/core/network/http/modules/stadata_list_http_module.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:stadata_flutter_sdk/src/core/core.dart'; - -class StadataListHttpModule extends HttpModule { - StadataListHttpModule() - : super(injector.get(instanceName: 'listClient')); -} diff --git a/packages/stadata_flutter_sdk/lib/src/core/network/http/modules/stadata_view_http_module.dart b/packages/stadata_flutter_sdk/lib/src/core/network/http/modules/stadata_view_http_module.dart deleted file mode 100644 index 742d289b..00000000 --- a/packages/stadata_flutter_sdk/lib/src/core/network/http/modules/stadata_view_http_module.dart +++ /dev/null @@ -1,6 +0,0 @@ -import 'package:stadata_flutter_sdk/src/core/core.dart'; - -class StadataViewHttpModule extends HttpModule { - StadataViewHttpModule() - : super(injector.get(instanceName: 'viewClient')); -} diff --git a/packages/stadata_flutter_sdk/lib/src/core/network/interceptors/auth_interceptor.dart b/packages/stadata_flutter_sdk/lib/src/core/network/interceptors/auth_interceptor.dart new file mode 100644 index 00000000..33e3c37d --- /dev/null +++ b/packages/stadata_flutter_sdk/lib/src/core/network/interceptors/auth_interceptor.dart @@ -0,0 +1,26 @@ +import 'dart:async'; + +import 'package:stadata_flutter_sdk/src/config/config.dart'; +import 'package:stadata_flutter_sdk/src/core/di/di.dart'; +import 'package:stadata_flutter_sdk/src/core/network/base_network_interceptor.dart'; +import 'package:stadata_flutter_sdk/src/core/network/request_data.dart'; + +class AuthInterceptor extends BaseNetworkInterceptor { + final _apiConfig = injector.get(); + + @override + FutureOr onRequest(RequestData request) async { + final apiKey = _apiConfig.apiKey; + + final newQueries = Map.from(request.uri.queryParameters); + newQueries['key'] = apiKey; + + return super.onRequest( + request.copyWith( + uri: request.uri.replace( + queryParameters: newQueries, + ), + ), + ); + } +} diff --git a/packages/stadata_flutter_sdk/lib/src/core/network/interceptors/interceptors.dart b/packages/stadata_flutter_sdk/lib/src/core/network/interceptors/interceptors.dart new file mode 100644 index 00000000..f8f44559 --- /dev/null +++ b/packages/stadata_flutter_sdk/lib/src/core/network/interceptors/interceptors.dart @@ -0,0 +1,3 @@ +export 'auth_interceptor.dart'; +export 'logging_interceptor.dart'; +export 'retry_interceptor.dart'; diff --git a/packages/stadata_flutter_sdk/lib/src/core/network/interceptors/logging_interceptor.dart b/packages/stadata_flutter_sdk/lib/src/core/network/interceptors/logging_interceptor.dart new file mode 100644 index 00000000..f72d50e4 --- /dev/null +++ b/packages/stadata_flutter_sdk/lib/src/core/network/interceptors/logging_interceptor.dart @@ -0,0 +1,76 @@ +import 'dart:async'; + +import 'package:stadata_flutter_sdk/src/core/core.dart'; +import 'package:stadata_flutter_sdk/src/core/network/base_network_interceptor.dart'; + +class LoggingInterceptor extends BaseNetworkInterceptor { + Log get log => injector.get(); + + @override + FutureOr onRequest(RequestData request) { + log + ..console('HTTP REQUEST') + ..console('==============================') + ..console( + '${request.method.toUpperCase()} ${(request.uri.host) + request.uri.path}', + ) + ..console('Headers:'); + request.headers.forEach( + (k, v) => log.console('$k: $v'), + ); + + log.console('Query Parameters:'); + request.uri.queryParameters.forEach( + (k, v) => log.console('$k: $v'), + ); + + if (request.body != null) { + log.console('Body: ${request.body}'); + } + + return super.onRequest(request); + } + + @override + FutureOr onResponse(ResponseData response) { + log + ..console('HTTP RESPONSE') + ..console('==============================') + ..console( + '(${response.statusCode}) ' + '${response.request.uri.toString().split('?').first}', + ) + ..console('Headers:'); + response.headers.forEach( + (k, v) => log.console('$k: $v'), + ); + + if (response.request.uri.queryParameters.isNotEmpty) { + log.console('Query:'); + response.request.uri.queryParameters.forEach( + (k, v) { + if (k != 'key') { + log.console('$k: $v'); + } + }, + ); + } + + log.console('Body: ${response.body}'); + + return super.onResponse(response); + } + + @override + FutureOr onError(Object error, StackTrace stackTrace) { + log + ..console( + 'HTTP ERROR', + type: LogType.error, + ) + ..console('==============================', type: LogType.error) + ..console('$error', type: LogType.error); + + return super.onError(error, stackTrace); + } +} diff --git a/packages/stadata_flutter_sdk/lib/src/core/network/interceptors/retry_interceptor.dart b/packages/stadata_flutter_sdk/lib/src/core/network/interceptors/retry_interceptor.dart new file mode 100644 index 00000000..4d6e9485 --- /dev/null +++ b/packages/stadata_flutter_sdk/lib/src/core/network/interceptors/retry_interceptor.dart @@ -0,0 +1,33 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:stadata_flutter_sdk/src/core/core.dart'; +import 'package:stadata_flutter_sdk/src/core/network/base_network_interceptor.dart'; + +class RetryInterceptor extends BaseNetworkInterceptor { + final int maxRetries; + final Duration delay; + int _retryCount = 0; + + final _log = injector.get(); + + RetryInterceptor({ + this.maxRetries = 3, + this.delay = const Duration(seconds: 1), + }); + + @override + FutureOr onError(Object error, StackTrace stackTrace) async { + if (_retryCount < maxRetries && error is SocketException) { + _retryCount++; + await _log.console( + '🔄 Retrying request (Attempt $_retryCount of $maxRetries)', + type: LogType.info, + ); + await Future.delayed(delay * _retryCount); + return Future.error(error, stackTrace); + } + _retryCount = 0; + return Future.error(error, stackTrace); + } +} diff --git a/packages/stadata_flutter_sdk/lib/src/core/network/network.dart b/packages/stadata_flutter_sdk/lib/src/core/network/network.dart index 1ac0bb76..5b2d7493 100644 --- a/packages/stadata_flutter_sdk/lib/src/core/network/network.dart +++ b/packages/stadata_flutter_sdk/lib/src/core/network/network.dart @@ -1,2 +1,5 @@ export 'api_endpoint.dart'; -export 'http/http.dart'; +export 'interceptors/interceptors.dart'; +export 'network_client.dart'; +export 'request_data.dart'; +export 'response_data.dart'; diff --git a/packages/stadata_flutter_sdk/lib/src/core/network/network_client.dart b/packages/stadata_flutter_sdk/lib/src/core/network/network_client.dart new file mode 100644 index 00000000..4b5f75f4 --- /dev/null +++ b/packages/stadata_flutter_sdk/lib/src/core/network/network_client.dart @@ -0,0 +1,187 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:stadata_flutter_sdk/src/core/exceptions/exceptions.dart'; +import 'package:stadata_flutter_sdk/src/core/network/base_network_interceptor.dart'; +import 'package:stadata_flutter_sdk/src/core/network/request_data.dart'; +import 'package:stadata_flutter_sdk/src/core/network/response_data.dart'; + +class NetworkClient { + final String baseUrl; + final Duration timeout; + final List interceptors; + + NetworkClient({ + required this.baseUrl, + this.timeout = const Duration(seconds: 30), + this.interceptors = const [], + }); + + Future> _getHeaders() async => { + 'Content-Type': 'application/json', + }; + + Future get( + String path, { + Map? queryParams, + T Function(Map)? responseConverter, + }) async { + return _sendRequest( + 'GET', + path, + queryParams: queryParams, + responseConverter: responseConverter, + ); + } + + Future post( + String path, { + Map? body, + Map? queryParams, + T Function(Map)? responseConverter, + }) async { + return _sendRequest( + 'POST', + path, + body: body, + queryParams: queryParams, + responseConverter: responseConverter, + ); + } + + Future put( + String path, { + Map? body, + Map? queryParams, + T Function(Map)? responseConverter, + }) async { + return _sendRequest( + 'PUT', + path, + body: body, + queryParams: queryParams, + responseConverter: responseConverter, + ); + } + + Future delete( + String path, { + Map? queryParams, + T Function(Map)? responseConverter, + }) async { + return _sendRequest( + 'DELETE', + path, + queryParams: queryParams, + responseConverter: responseConverter, + ); + } + + Future _sendRequest( + String method, + String path, { + Map? body, + Map? queryParams, + T Function(Map)? responseConverter, + }) async { + final client = HttpClient(); + HttpClientRequest? request; + HttpClientResponse? response; + + try { + // Prepare initial request data + final uri = Uri.parse(baseUrl + path).replace( + queryParameters: queryParams?.map( + (key, value) => MapEntry(key, value.toString()), + ), + ); + + final headers = await _getHeaders(); + var requestData = RequestData( + method: method, + uri: uri, + headers: headers, + body: body, + ); + + // Apply request interceptors + for (final interceptor in interceptors) { + requestData = await interceptor.onRequest(requestData); + } + + // Create and send request + request = await client.openUrl(requestData.method, requestData.uri); + + requestData.headers.forEach((key, value) { + request?.headers.add(key, value); + }); + + if (requestData.body != null) { + final jsonBody = json.encode(requestData.body); + request.write(jsonBody); + } + + response = await request.close(); + final responseBody = await response.transform(utf8.decoder).join(); + + // Prepare response data + final responseHeaders = {}; + + response.headers.forEach( + (key, values) => responseHeaders.putIfAbsent( + key, + () => values.join('; '), + ), + ); + + var responseData = ResponseData( + statusCode: response.statusCode, + request: requestData, + headers: responseHeaders, + body: responseBody.isNotEmpty ? json.decode(responseBody) : null, + ); + + // Apply response interceptors + for (final interceptor in interceptors) { + responseData = await interceptor.onResponse(responseData); + } + + // Handle response + if (responseData.statusCode >= 200 && responseData.statusCode < 300) { + if (responseData.body == null) { + return null as T; + } + + if (responseConverter != null) { + return responseConverter(responseData.body as Map); + } else { + return responseData.body as T; + } + } else { + throw ApiException( + 'Request failed: ${responseData.statusCode} - ${responseData.body}', + responseData.statusCode, + ); + } + } catch (error, stackTrace) { + // Apply error interceptors + try { + for (final interceptor in interceptors) { + final errorResponse = await interceptor.onError(error, stackTrace); + // If interceptor handles the error and returns a response, use it + return errorResponse.body as T; + } + } catch (e) { + // If error handling fails, throw the original error + if (error is ApiException) { + rethrow; + } + throw ApiException('Unexpected error: $error'); + } + rethrow; + } finally { + client.close(); + } + } +} diff --git a/packages/stadata_flutter_sdk/lib/src/core/network/request_data.dart b/packages/stadata_flutter_sdk/lib/src/core/network/request_data.dart new file mode 100644 index 00000000..ffa87f80 --- /dev/null +++ b/packages/stadata_flutter_sdk/lib/src/core/network/request_data.dart @@ -0,0 +1,27 @@ +class RequestData { + final String method; + final Uri uri; + final Map headers; + + final dynamic body; + + RequestData({ + required this.method, + required this.uri, + required this.headers, + this.body, + }); + + RequestData copyWith({ + String? method, + Uri? uri, + Map? headers, + dynamic body, + }) => + RequestData( + method: method ?? this.method, + uri: uri ?? this.uri, + headers: headers ?? this.headers, + body: body ?? this.body, + ); +} diff --git a/packages/stadata_flutter_sdk/lib/src/core/network/response_data.dart b/packages/stadata_flutter_sdk/lib/src/core/network/response_data.dart new file mode 100644 index 00000000..f36af3d5 --- /dev/null +++ b/packages/stadata_flutter_sdk/lib/src/core/network/response_data.dart @@ -0,0 +1,29 @@ +import 'package:stadata_flutter_sdk/src/core/core.dart'; + +class ResponseData { + final int statusCode; + final Map headers; + final dynamic body; + final RequestData request; + + ResponseData({ + required this.statusCode, + required this.headers, + required this.body, + required this.request, + }); + + ResponseData copyWith({ + int? statusCode, + Map? headers, + RequestData? request, + dynamic body, + }) { + return ResponseData( + statusCode: statusCode ?? this.statusCode, + headers: headers ?? this.headers, + request: request ?? this.request, + body: body ?? this.body, + ); + } +} diff --git a/packages/stadata_flutter_sdk/lib/src/features/domains/data/datasources/domain_remote_data_source.dart b/packages/stadata_flutter_sdk/lib/src/features/domains/data/datasources/domain_remote_data_source.dart index 48c7bfe5..965b0f8f 100644 --- a/packages/stadata_flutter_sdk/lib/src/features/domains/data/datasources/domain_remote_data_source.dart +++ b/packages/stadata_flutter_sdk/lib/src/features/domains/data/datasources/domain_remote_data_source.dart @@ -10,7 +10,7 @@ abstract class DomainRemoteDataSource { } class DomainRemoteDataSourceImpl implements DomainRemoteDataSource { - final client = injector.get(); + final client = injector.get(); @override Future?>> get({ @@ -21,7 +21,7 @@ class DomainRemoteDataSourceImpl implements DomainRemoteDataSource { throw const DomainProvinceCodeException(); } - final result = await client.get( + final result = await client.get( ApiEndpoint.domain( type: type, provinceCode: provinceCode, diff --git a/packages/stadata_flutter_sdk/lib/src/features/infographics/data/datasources/infographic_remote_data_source.dart b/packages/stadata_flutter_sdk/lib/src/features/infographics/data/datasources/infographic_remote_data_source.dart index 3ad25227..8a57b2bb 100644 --- a/packages/stadata_flutter_sdk/lib/src/features/infographics/data/datasources/infographic_remote_data_source.dart +++ b/packages/stadata_flutter_sdk/lib/src/features/infographics/data/datasources/infographic_remote_data_source.dart @@ -12,7 +12,7 @@ abstract class InfographicRemoteDataSource { } class InfographicRemoteDataSourceImpl implements InfographicRemoteDataSource { - final _client = injector.get(); + final _client = injector.get(instanceName: 'listClient'); @override Future?>> get({ @@ -21,7 +21,7 @@ class InfographicRemoteDataSourceImpl implements InfographicRemoteDataSource { int page = 1, String? keyword, }) async { - final result = await _client.get( + final result = await _client.get( ApiEndpoint.infographic( domain: domain, lang: lang, diff --git a/packages/stadata_flutter_sdk/lib/src/features/news/data/converters/news_converter.dart b/packages/stadata_flutter_sdk/lib/src/features/news/data/converters/news_converter.dart index 83a6a66b..7dfb11b7 100644 --- a/packages/stadata_flutter_sdk/lib/src/features/news/data/converters/news_converter.dart +++ b/packages/stadata_flutter_sdk/lib/src/features/news/data/converters/news_converter.dart @@ -1,10 +1,11 @@ +import 'package:html_unescape/html_unescape_small.dart'; import 'package:stadata_flutter_sdk/src/base/base.dart'; class NewsConverter extends BaseConverter { const NewsConverter(); @override - String fromJson(String json) => json; + String fromJson(String json) => HtmlUnescape().convert(json); @override String toJson(String object) => object; diff --git a/packages/stadata_flutter_sdk/lib/src/features/news/data/datasources/news_remote_data_source.dart b/packages/stadata_flutter_sdk/lib/src/features/news/data/datasources/news_remote_data_source.dart index 4d6b1ab0..973a7f49 100644 --- a/packages/stadata_flutter_sdk/lib/src/features/news/data/datasources/news_remote_data_source.dart +++ b/packages/stadata_flutter_sdk/lib/src/features/news/data/datasources/news_remote_data_source.dart @@ -20,15 +20,15 @@ abstract class NewsRemoteDataSource { } class NewsRemoteDataSourceImpl implements NewsRemoteDataSource { - final _listClient = injector.get(); - final _detailClient = injector.get(); + final _listClient = injector.get(instanceName: 'listClient'); + final _detailClient = injector.get(instanceName: 'viewClient'); @override Future> detail({ required int id, required String domain, DataLanguage lang = DataLanguage.id, }) async { - final result = await _detailClient.get( + final result = await _detailClient.get( ApiEndpoint.newsDetail( id: id, lang: lang, @@ -64,7 +64,7 @@ class NewsRemoteDataSourceImpl implements NewsRemoteDataSource { int? year, String? keyword, }) async { - final result = await _listClient.get( + final result = await _listClient.get( ApiEndpoint.news( page: page, lang: lang, diff --git a/packages/stadata_flutter_sdk/lib/src/features/news_categories/data/datasources/news_category_remote_data_source.dart b/packages/stadata_flutter_sdk/lib/src/features/news_categories/data/datasources/news_category_remote_data_source.dart index 1c387444..e19a5017 100644 --- a/packages/stadata_flutter_sdk/lib/src/features/news_categories/data/datasources/news_category_remote_data_source.dart +++ b/packages/stadata_flutter_sdk/lib/src/features/news_categories/data/datasources/news_category_remote_data_source.dart @@ -10,14 +10,14 @@ abstract class NewsCategoryRemoteDataSource { } class NewsCategoryRemoteDataSourceImpl implements NewsCategoryRemoteDataSource { - final _listClient = injector.get(); + final _listClient = injector.get(instanceName: 'listClient'); @override Future?>> get({ required String domain, DataLanguage lang = DataLanguage.id, }) async { - final result = await _listClient.get( + final result = await _listClient.get( ApiEndpoint.newsCategory( lang: lang, domain: domain, diff --git a/packages/stadata_flutter_sdk/lib/src/features/press_releases/data/datasources/press_release_remote_data_source.dart b/packages/stadata_flutter_sdk/lib/src/features/press_releases/data/datasources/press_release_remote_data_source.dart index 0de513e9..480a02bd 100644 --- a/packages/stadata_flutter_sdk/lib/src/features/press_releases/data/datasources/press_release_remote_data_source.dart +++ b/packages/stadata_flutter_sdk/lib/src/features/press_releases/data/datasources/press_release_remote_data_source.dart @@ -19,8 +19,8 @@ abstract class PressReleaseRemoteDataSource { } class PressReleaseRemoteDataSourceImpl implements PressReleaseRemoteDataSource { - final _listClient = injector.get(); - final _detailClient = injector.get(); + final _listClient = injector.get(instanceName: 'listClient'); + final _detailClient = injector.get(instanceName: 'viewClient'); @override Future> detail({ @@ -28,7 +28,7 @@ class PressReleaseRemoteDataSourceImpl implements PressReleaseRemoteDataSource { required String domain, DataLanguage lang = DataLanguage.id, }) async { - final result = await _detailClient.get( + final result = await _detailClient.get( ApiEndpoint.pressReleaseDetail( id: id, lang: lang, @@ -63,7 +63,7 @@ class PressReleaseRemoteDataSourceImpl implements PressReleaseRemoteDataSource { int? year, String? keyword, }) async { - final result = await _listClient.get( + final result = await _listClient.get( ApiEndpoint.pressReleases( page: page, lang: lang, diff --git a/packages/stadata_flutter_sdk/lib/src/features/publications/data/datasources/publication_remote_data_source.dart b/packages/stadata_flutter_sdk/lib/src/features/publications/data/datasources/publication_remote_data_source.dart index dfe90bf9..30a4c8a3 100644 --- a/packages/stadata_flutter_sdk/lib/src/features/publications/data/datasources/publication_remote_data_source.dart +++ b/packages/stadata_flutter_sdk/lib/src/features/publications/data/datasources/publication_remote_data_source.dart @@ -41,8 +41,8 @@ abstract class PublicationRemoteDataSource { } class PublicationRemoteDataSourceImpl implements PublicationRemoteDataSource { - final listClient = injector.get(); - final detailClient = injector.get(); + final listClient = injector.get(instanceName: 'listClient'); + final detailClient = injector.get(instanceName: 'viewClient'); @override Future> detail({ @@ -50,7 +50,7 @@ class PublicationRemoteDataSourceImpl implements PublicationRemoteDataSource { required String domain, DataLanguage lang = DataLanguage.id, }) async { - final result = await detailClient.get( + final result = await detailClient.get( ApiEndpoint.publicationDetail( id: id, domain: domain, @@ -85,7 +85,7 @@ class PublicationRemoteDataSourceImpl implements PublicationRemoteDataSource { int? month, int? year, }) async { - final result = await listClient.get( + final result = await listClient.get( ApiEndpoint.publication( domain: domain, lang: lang, diff --git a/packages/stadata_flutter_sdk/lib/src/features/static_tables/data/datasources/static_table_remote_data_source.dart b/packages/stadata_flutter_sdk/lib/src/features/static_tables/data/datasources/static_table_remote_data_source.dart index c426ecbd..fd49e409 100644 --- a/packages/stadata_flutter_sdk/lib/src/features/static_tables/data/datasources/static_table_remote_data_source.dart +++ b/packages/stadata_flutter_sdk/lib/src/features/static_tables/data/datasources/static_table_remote_data_source.dart @@ -19,8 +19,8 @@ abstract class StaticTableRemoteDataSource { } class StaticTableRemoteDataSourceImpl implements StaticTableRemoteDataSource { - final _listClient = injector.get(); - final _detailClient = injector.get(); + final _listClient = injector.get(instanceName: 'listClient'); + final _detailClient = injector.get(instanceName: 'viewClient'); @override Future> detail({ @@ -28,7 +28,7 @@ class StaticTableRemoteDataSourceImpl implements StaticTableRemoteDataSource { required String domain, DataLanguage lang = DataLanguage.id, }) async { - final result = await _detailClient.get( + final result = await _detailClient.get( ApiEndpoint.staticTableDetail( id: id, lang: lang, @@ -63,7 +63,7 @@ class StaticTableRemoteDataSourceImpl implements StaticTableRemoteDataSource { int? year, String? keyword, }) async { - final result = await _listClient.get( + final result = await _listClient.get( ApiEndpoint.staticTable( domain: domain, page: page, diff --git a/packages/stadata_flutter_sdk/lib/src/features/statistical_classification/data/datasources/statistic_classification_remote_data_source.dart b/packages/stadata_flutter_sdk/lib/src/features/statistical_classification/data/datasources/statistic_classification_remote_data_source.dart index 71459fdc..02d56ee7 100644 --- a/packages/stadata_flutter_sdk/lib/src/features/statistical_classification/data/datasources/statistic_classification_remote_data_source.dart +++ b/packages/stadata_flutter_sdk/lib/src/features/statistical_classification/data/datasources/statistic_classification_remote_data_source.dart @@ -21,8 +21,8 @@ abstract interface class StatisticClassificationRemoteDataSource { class StatisticClassificationRemoteDataSourceImpl implements StatisticClassificationRemoteDataSource { - final _listClient = injector.get(); - final _viewClient = injector.get(); + final _listClient = injector.get(instanceName: 'listClient'); + final _viewClient = injector.get(instanceName: 'viewClient'); @override Future>> detail({ @@ -32,11 +32,11 @@ class StatisticClassificationRemoteDataSourceImpl int page = 1, int perPage = 10, }) async { - final result = await _viewClient.get( + final result = await _viewClient.get( ApiEndpoint.statisticClassification( type: type, ), - param: { + queryParams: { 'id': id, 'lang': lang.value, 'page': page, @@ -85,11 +85,11 @@ class StatisticClassificationRemoteDataSourceImpl int page = 1, int perPage = 10, }) async { - final result = await _listClient.get( + final result = await _listClient.get( ApiEndpoint.statisticClassification( type: type, ), - param: { + queryParams: { if (level != null) 'level': level.value, 'lang': lang.value, 'page': page, diff --git a/packages/stadata_flutter_sdk/lib/src/features/strategic_indicators/data/datasources/strategic_indicator_remote_data_source.dart b/packages/stadata_flutter_sdk/lib/src/features/strategic_indicators/data/datasources/strategic_indicator_remote_data_source.dart index c2147ba1..2c417b1a 100644 --- a/packages/stadata_flutter_sdk/lib/src/features/strategic_indicators/data/datasources/strategic_indicator_remote_data_source.dart +++ b/packages/stadata_flutter_sdk/lib/src/features/strategic_indicators/data/datasources/strategic_indicator_remote_data_source.dart @@ -13,7 +13,7 @@ abstract interface class StrategicIndicatorRemoteDataSource { class StrategicIndicatorRemoteDataSourceImpl implements StrategicIndicatorRemoteDataSource { - final _listClient = injector.get(); + final _listClient = injector.get(instanceName: 'listClient'); @override Future?>> get({ @@ -22,7 +22,7 @@ class StrategicIndicatorRemoteDataSourceImpl int page = 1, int? variableID, }) async { - final result = await _listClient.get( + final result = await _listClient.get( ApiEndpoint.strategicIndicators( page: page, lang: lang, diff --git a/packages/stadata_flutter_sdk/lib/src/features/subject_categories/data/datasources/subject_category_remote_data_source.dart b/packages/stadata_flutter_sdk/lib/src/features/subject_categories/data/datasources/subject_category_remote_data_source.dart index 16c8c915..1688d516 100644 --- a/packages/stadata_flutter_sdk/lib/src/features/subject_categories/data/datasources/subject_category_remote_data_source.dart +++ b/packages/stadata_flutter_sdk/lib/src/features/subject_categories/data/datasources/subject_category_remote_data_source.dart @@ -12,7 +12,8 @@ abstract class SubjectCategoryRemoteDataSource { class SubjectCategoryRemoteDataSourceImpl implements SubjectCategoryRemoteDataSource { - final _listHttpModule = injector.get(); + final _listHttpModule = + injector.get(instanceName: 'listClient'); @override Future?>> get({ @@ -20,7 +21,7 @@ class SubjectCategoryRemoteDataSourceImpl DataLanguage lang = DataLanguage.id, int page = 1, }) async { - final result = await _listHttpModule.get( + final result = await _listHttpModule.get( ApiEndpoint.subjectCategories( domain: domain, lang: lang, diff --git a/packages/stadata_flutter_sdk/lib/src/features/subjects/data/datasources/subject_remote_data_source.dart b/packages/stadata_flutter_sdk/lib/src/features/subjects/data/datasources/subject_remote_data_source.dart index 3dc062ec..92563055 100644 --- a/packages/stadata_flutter_sdk/lib/src/features/subjects/data/datasources/subject_remote_data_source.dart +++ b/packages/stadata_flutter_sdk/lib/src/features/subjects/data/datasources/subject_remote_data_source.dart @@ -12,7 +12,8 @@ abstract class SubjectRemoteDataSource { } class SubjectRemoteDataSourceImpl implements SubjectRemoteDataSource { - final _listHttpModule = injector.get(); + final _listHttpModule = + injector.get(instanceName: 'listClient'); @override Future?>> get({ @@ -21,7 +22,7 @@ class SubjectRemoteDataSourceImpl implements SubjectRemoteDataSource { DataLanguage lang = DataLanguage.id, int page = 1, }) async { - final result = await _listHttpModule.get( + final result = await _listHttpModule.get( ApiEndpoint.subjects( lang: lang, page: page, diff --git a/packages/stadata_flutter_sdk/lib/src/features/units/data/datasources/unit_data_remote_data_source.dart b/packages/stadata_flutter_sdk/lib/src/features/units/data/datasources/unit_data_remote_data_source.dart index 4a1a927a..d25c3b82 100644 --- a/packages/stadata_flutter_sdk/lib/src/features/units/data/datasources/unit_data_remote_data_source.dart +++ b/packages/stadata_flutter_sdk/lib/src/features/units/data/datasources/unit_data_remote_data_source.dart @@ -12,7 +12,8 @@ abstract class UnitDataRemoteDataSource { } class UnitDataRemoteDataSourceImpl implements UnitDataRemoteDataSource { - final _listHttpModule = injector.get(); + final _listHttpModule = + injector.get(instanceName: 'listClient'); @override Future?>> get({ @@ -21,7 +22,7 @@ class UnitDataRemoteDataSourceImpl implements UnitDataRemoteDataSource { int page = 1, int? variableID, }) async { - final result = await _listHttpModule.get( + final result = await _listHttpModule.get( ApiEndpoint.units( lang: lang, page: page, diff --git a/packages/stadata_flutter_sdk/lib/src/features/variables/data/datasources/variable_remote_data_source.dart b/packages/stadata_flutter_sdk/lib/src/features/variables/data/datasources/variable_remote_data_source.dart index ea45713a..68336410 100644 --- a/packages/stadata_flutter_sdk/lib/src/features/variables/data/datasources/variable_remote_data_source.dart +++ b/packages/stadata_flutter_sdk/lib/src/features/variables/data/datasources/variable_remote_data_source.dart @@ -14,7 +14,8 @@ abstract class VariableRemoteDataSource { } class VariableRemoteDataSourceImpl implements VariableRemoteDataSource { - final _listHttpModule = injector.get(); + final _listHttpModule = + injector.get(instanceName: 'listClient'); @override Future?>> get({ @@ -25,7 +26,7 @@ class VariableRemoteDataSourceImpl implements VariableRemoteDataSource { int? year, int? subjectID, }) async { - final result = await _listHttpModule.get( + final result = await _listHttpModule.get( ApiEndpoint.variables( lang: lang, page: page, diff --git a/packages/stadata_flutter_sdk/lib/src/features/vertical_variables/data/datasources/vertical_variable_remote_data_source.dart b/packages/stadata_flutter_sdk/lib/src/features/vertical_variables/data/datasources/vertical_variable_remote_data_source.dart index 662d1990..c6d42e4f 100644 --- a/packages/stadata_flutter_sdk/lib/src/features/vertical_variables/data/datasources/vertical_variable_remote_data_source.dart +++ b/packages/stadata_flutter_sdk/lib/src/features/vertical_variables/data/datasources/vertical_variable_remote_data_source.dart @@ -13,7 +13,8 @@ abstract class VerticalVariableRemoteDataSource { class VerticalVariableRemoteDataSourceImpl implements VerticalVariableRemoteDataSource { - final _listHttpModule = injector.get(); + final _listHttpModule = + injector.get(instanceName: 'listClient'); @override Future?>> get({ @@ -22,7 +23,7 @@ class VerticalVariableRemoteDataSourceImpl DataLanguage lang = DataLanguage.id, int? variableID, }) async { - final result = await _listHttpModule.get( + final result = await _listHttpModule.get( ApiEndpoint.verticalVariables( lang: lang, page: page, diff --git a/packages/stadata_flutter_sdk/pubspec.yaml b/packages/stadata_flutter_sdk/pubspec.yaml index cd9ec896..d3743ee1 100644 --- a/packages/stadata_flutter_sdk/pubspec.yaml +++ b/packages/stadata_flutter_sdk/pubspec.yaml @@ -11,9 +11,6 @@ environment: dependencies: collection: ^1.18.0 - dio: ^5.7.0 - dio_cache_interceptor: ^3.5.0 - dio_smart_retry: ">=5.0.0 <7.0.0" flutter: sdk: flutter html_unescape: ^2.0.0 diff --git a/packages/stadata_flutter_sdk/test/src/core/network/http/http_setting_test.dart b/packages/stadata_flutter_sdk/test/src/core/network/http/http_setting_test.dart deleted file mode 100644 index ef8d52ce..00000000 --- a/packages/stadata_flutter_sdk/test/src/core/network/http/http_setting_test.dart +++ /dev/null @@ -1,132 +0,0 @@ -import 'package:flutter_test/flutter_test.dart'; -import 'package:stadata_flutter_sdk/src/core/core.dart'; - -void main() { - group( - 'HttpTimeout', - () { - test( - 'has default value if initialize without custom params', - () { - const result = HttpTimeout(); - - expect(result.connectTimeout, equals(30000)); - expect(result.sendTimeout, equals(20000)); - expect(result.receiveTimeout, equals(20000)); - }, - ); - - test( - 'should use correct connectTimeout value if it passed to param', - () { - const result = HttpTimeout( - connectTimeout: 50000, - ); - - expect(result.connectTimeout, equals(50000)); - expect(result.sendTimeout, equals(20000)); - expect(result.receiveTimeout, equals(20000)); - }, - ); - - test( - 'should use correct sendTimeout value if it passed to param', - () { - const result = HttpTimeout( - sendTimeout: 50000, - ); - - expect(result.connectTimeout, equals(30000)); - expect(result.sendTimeout, equals(50000)); - expect(result.receiveTimeout, equals(20000)); - }, - ); - - test( - 'should use correct receiveTimeout value if it passed to param', - () { - const result = HttpTimeout( - receiveTimeout: 50000, - ); - - expect(result.connectTimeout, equals(30000)); - expect(result.sendTimeout, equals(20000)); - expect(result.receiveTimeout, equals(50000)); - }, - ); - }, - ); - group( - 'HttpSetting', - () { - test( - 'should use default value param if no customization made ' - 'and should use given base url', - () { - const result = HttpSetting( - baseUrl: 'BASE_URL', - ); - - expect(result.baseUrl, equals('BASE_URL')); - expect(result.interceptors, isNull); - expect(result.contentType, equals('application/json')); - expect(result.useHttp2, isFalse); - expect(result.timeout, equals(const HttpTimeout())); - }, - ); - - test( - 'should use correct contentType that are passed from constructor param', - () { - const result = HttpSetting( - baseUrl: 'BASE_URL', - contentType: 'application/vnd.api+json', - ); - - expect(result.baseUrl, equals('BASE_URL')); - expect(result.interceptors, isNull); - expect(result.contentType, equals('application/vnd.api+json')); - expect(result.useHttp2, isFalse); - expect(result.timeout, equals(const HttpTimeout())); - }, - ); - - test( - 'should use correct useHttp2 that are passed from constructor param ', - () { - const result = HttpSetting( - baseUrl: 'BASE_URL', - useHttp2: true, - ); - - expect(result.baseUrl, equals('BASE_URL')); - expect(result.interceptors, isNull); - expect(result.contentType, equals('application/json')); - expect(result.useHttp2, isTrue); - expect(result.timeout, equals(const HttpTimeout())); - }, - ); - - test( - 'should use correct timeout that are passed from constructor param ', - () { - const httpTimeout = HttpTimeout( - connectTimeout: 50000, - receiveTimeout: 50000, - sendTimeout: 60000, - ); - const result = HttpSetting( - baseUrl: 'BASE_URL', - timeout: httpTimeout, - ); - - expect(result.baseUrl, equals('BASE_URL')); - expect(result.interceptors, isNull); - expect(result.contentType, equals('application/json')); - expect(result.useHttp2, isFalse); - expect(result.timeout, equals(httpTimeout)); - }, - ); - }, - ); -} diff --git a/packages/stadata_flutter_sdk/test/src/core/network/http/interceptors/logging_interceptor_test.dart b/packages/stadata_flutter_sdk/test/src/core/network/http/interceptors/logging_interceptor_test.dart deleted file mode 100644 index 61cec6a3..00000000 --- a/packages/stadata_flutter_sdk/test/src/core/network/http/interceptors/logging_interceptor_test.dart +++ /dev/null @@ -1,197 +0,0 @@ -import 'package:dio/dio.dart'; -import 'package:flutter_test/flutter_test.dart'; -import 'package:mocktail/mocktail.dart'; -import 'package:stadata_flutter_sdk/src/core/core.dart'; - -import '../../../../../helpers/test_injection.dart'; - -class MockLog extends Mock implements Log {} - -void main() { - group('LoggingInterceptor', () { - late LoggingInterceptor interceptor; - late MockLog mockLog; - - setUpAll( - () { - mockLog = MockLog(); - registerTestLazySingleton(mockLog); - interceptor = LoggingInterceptor(); - }, - ); - - tearDownAll(() => unregisterTestInjection); - - test('onRequest logs request information', () { - // Arrange - when(() => mockLog.console(any())).thenAnswer( - (_) async => {}, - ); - - final options = RequestOptions( - path: '/some/endpoint', - method: 'GET', - baseUrl: 'https://example.com', - headers: {'Header1': 'Value1'}, - queryParameters: {'Param1': 'Value1'}, - data: {'key': 'value'}, - ); - - // Act - interceptor.onRequest(options, RequestInterceptorHandler()); - - // Assert - verify(() => mockLog.console('HTTP REQUEST')); - verify(() => mockLog.console('==============================')); - verify(() => mockLog.console('GET https://example.com/some/endpoint')); - verify(() => mockLog.console('Headers:')); - verify(() => mockLog.console('Header1: Value1')); - verify(() => mockLog.console('Query Parameters:')); - verify(() => mockLog.console('Param1: Value1')); - verify(() => mockLog.console('Body: {key: value}')); - }); - - test('onResponse logs response information', () { - // Arrange - final response = Response( - requestOptions: RequestOptions( - path: '/some/endpoint', - baseUrl: 'https://example.com', - ), - statusCode: 200, - statusMessage: 'OK', - headers: Headers.fromMap( - { - 'Header1': ['Value1'], - }, - ), - data: {'key': 'value'}, - ); - when(() => mockLog.console(any())).thenAnswer((_) async => {}); - - when( - () => response.headers.forEach( - (k, v) => mockLog.console('$k: $v'), - ), - ).thenAnswer( - (_) async => {}, - ); - - // Act - interceptor.onResponse(response, ResponseInterceptorHandler()); - - // Assert - verify(() => mockLog.console('HTTP RESPONSE')); - verify(() => mockLog.console('==============================')); - verify( - () => mockLog.console( - '200 (OK) ' - 'https://example.com/some/endpoint', - ), - ); - verify(() => mockLog.console('Headers:')); - verify( - () => response.headers.forEach( - (k, v) => mockLog.console('$k: $v'), - ), - ); - verify(() => mockLog.console('Body: {key: value}')); - }); - - test( - 'onError logs error information', - () { - // Arrange - final dioException = DioException( - stackTrace: StackTrace.fromString('Example stack trace'), - requestOptions: RequestOptions( - path: '/some/endpoint', - baseUrl: 'https://example.com', - ), - response: Response( - statusCode: 404, - requestOptions: RequestOptions( - connectTimeout: const Duration(milliseconds: 30000), - path: '/some/endpoint', - baseUrl: 'https://example.com', - ), - statusMessage: 'Not Found', - data: {'error': 'Not Found'}, - ), - ); - - when( - () => mockLog.console(any(), type: LogType.error), - ).thenAnswer((_) async => {}); - - // Act - interceptor.onError( - dioException, - ErrorInterceptorHandler(), - ); - - // Assert - verify(() => mockLog.console('HTTP ERROR', type: LogType.error)); - verify( - () => mockLog.console( - '==============================', - type: LogType.error, - ), - ); - verify( - () => mockLog.console( - '404 (Not Found) ' - 'https://example.com/some/endpoint', - type: LogType.error, - ), - ); - verify( - () => - mockLog.console('Body: {error: Not Found}', type: LogType.error), - ); - }, - ); - - test( - 'onError logs error information if response is null', - () { - // Arrange - final dioException = DioException( - stackTrace: StackTrace.fromString('Example stack trace'), - message: 'There is something wrong', - error: 'Error', - requestOptions: RequestOptions( - path: '/some/endpoint', - baseUrl: 'https://example.com', - ), - ); - - when( - () => mockLog.console(any(), type: LogType.error), - ).thenAnswer((_) async => {}); - - // Act - interceptor.onError( - dioException, - ErrorInterceptorHandler(), - ); - - // Assert - verify(() => mockLog.console('HTTP ERROR', type: LogType.error)); - verify( - () => mockLog.console( - '==============================', - type: LogType.error, - ), - ); - verify( - () => mockLog.console( - 'Error (${DioExceptionType.unknown}) ' - 'https://example.com/some/endpoint', - type: LogType.error, - ), - ); - }, - ); - }); -} diff --git a/packages/stadata_flutter_sdk/test/src/core/network/http/interceptors/authentication_interceptor_test.dart b/packages/stadata_flutter_sdk/test/src/core/network/interceptor/auth_interceptor_test.dart similarity index 52% rename from packages/stadata_flutter_sdk/test/src/core/network/http/interceptors/authentication_interceptor_test.dart rename to packages/stadata_flutter_sdk/test/src/core/network/interceptor/auth_interceptor_test.dart index efbf7aea..b4b3b701 100644 --- a/packages/stadata_flutter_sdk/test/src/core/network/http/interceptors/authentication_interceptor_test.dart +++ b/packages/stadata_flutter_sdk/test/src/core/network/interceptor/auth_interceptor_test.dart @@ -1,20 +1,16 @@ -import 'package:dio/dio.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:stadata_flutter_sdk/src/config/api_config.dart'; import 'package:stadata_flutter_sdk/src/core/core.dart'; -import '../../../../../helpers/test_injection.dart'; -class MockApiConfig extends Mock implements ApiConfig {} +import '../../../../helpers/test_injection.dart'; -class MockRequestInterceptorHandler extends Mock - implements RequestInterceptorHandler {} +class MockApiConfig extends Mock implements ApiConfig {} void main() { late ApiConfig mockApiConfig; - late RequestInterceptorHandler mockRequestInterceptorHandler; - late AuthenticationInterceptor interceptor; - late RequestOptions requestOptions; + late AuthInterceptor interceptor; + late RequestData requestData; setUpAll( () { @@ -22,9 +18,12 @@ void main() { registerTestLazySingleton( mockApiConfig, ); - mockRequestInterceptorHandler = MockRequestInterceptorHandler(); - interceptor = AuthenticationInterceptor(); - requestOptions = RequestOptions(path: '/some/endpoint'); + requestData = RequestData( + method: 'GET', + uri: Uri.parse('https://example.com/some/endpoint'), + headers: {}, + ); + interceptor = AuthInterceptor(); }, ); @@ -32,28 +31,27 @@ void main() { const apiKey = 'API_KEY'; - group('AuthenticationInterceptor', () { + group('AuthInterceptor', () { test('modifies queryParameters with apiKey', () async { // Arrange when(() => mockApiConfig.apiKey).thenReturn(apiKey); // Act - await interceptor.onRequest( - requestOptions, - mockRequestInterceptorHandler, + final result = await interceptor.onRequest( + requestData, ); // Assert expect( - requestOptions.queryParameters, + result.uri.queryParameters, containsPair( 'key', apiKey, ), ); verify( - () => mockRequestInterceptorHandler.next(requestOptions), - ); + () => mockApiConfig.apiKey, + ).called(1); }); }); } diff --git a/packages/stadata_flutter_sdk/test/src/core/network/interceptor/logging_interceptor_test.dart b/packages/stadata_flutter_sdk/test/src/core/network/interceptor/logging_interceptor_test.dart new file mode 100644 index 00000000..cebb3369 --- /dev/null +++ b/packages/stadata_flutter_sdk/test/src/core/network/interceptor/logging_interceptor_test.dart @@ -0,0 +1,160 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:stadata_flutter_sdk/src/core/core.dart'; + +import '../../../../helpers/test_injection.dart'; + +class MockLog extends Mock implements Log {} + +void main() { + group('LoggingInterceptor', () { + late LoggingInterceptor interceptor; + late MockLog mockLog; + + final requestData = RequestData( + method: 'GET', + uri: Uri.https( + 'example.com', + '/some/endpoint', + ).replace( + queryParameters: {'Param1': 'Value1'}, + ), + headers: {'Header1': 'Value1'}, + body: {'key': 'value'}, + ); + + final response = ResponseData( + statusCode: 200, + request: requestData, + headers: { + 'Header1': 'Value1', + }, + body: {'key': 'value'}, + ); + + setUpAll( + () { + mockLog = MockLog(); + registerTestLazySingleton(mockLog); + interceptor = LoggingInterceptor(); + }, + ); + + tearDownAll(() => unregisterTestInjection); + + test('onRequest logs request information', () { + // Arrange + when(() => mockLog.console(any())).thenAnswer( + (_) async => {}, + ); + + // Act + interceptor.onRequest(requestData); + + // Assert + verify(() => mockLog.console('HTTP REQUEST')); + verify(() => mockLog.console('==============================')); + verify(() => mockLog.console('GET example.com/some/endpoint')); + verify(() => mockLog.console('Headers:')); + verify(() => mockLog.console('Header1: Value1')); + verify(() => mockLog.console('Query Parameters:')); + verify(() => mockLog.console('Param1: Value1')); + verify(() => mockLog.console('Body: {key: value}')); + }); + + test('onResponse logs response information', () { + // Arrange + + when(() => mockLog.console(any())).thenAnswer((_) async => {}); + + when( + () => response.headers.forEach( + (k, v) => mockLog.console('$k: $v'), + ), + ).thenAnswer( + (_) async => {}, + ); + + when( + () => response.request.uri.queryParameters.forEach( + (k, v) => mockLog.console('$k: $v'), + ), + ).thenAnswer( + (_) async => {}, + ); + + // Act + interceptor.onResponse(response); + + // Assert + verify(() => mockLog.console('HTTP RESPONSE')); + verify(() => mockLog.console('==============================')); + verify( + () => mockLog.console( + '(200) https://example.com/some/endpoint', + ), + ); + verify(() => mockLog.console('Headers:')); + verify( + () => response.headers.forEach( + (k, v) => mockLog.console('$k: $v'), + ), + ); + verify(() => mockLog.console('Query:')); + verify( + () => response.request.uri.queryParameters.forEach( + (k, v) => mockLog.console('$k: $v'), + ), + ); + verify(() => mockLog.console('Body: {key: value}')); + }); + + test( + 'onError logs error information', + () async { + // Arrange + + final apiException = ApiException( + 'Error', + 500, + ); + + final stackTrace = StackTrace.fromString('Error trace'); + + when( + () => mockLog.console(any(), type: LogType.error), + ).thenAnswer((_) async => {}); + + // Act + + await expectLater( + interceptor.onError( + apiException, + stackTrace, + ), + throwsA(apiException), + ); + + // Assert + verify( + () => mockLog.console( + 'HTTP ERROR', + type: LogType.error, + ), + ); + verify( + () => mockLog.console( + '==============================', + type: LogType.error, + ), + ); + verify( + () => mockLog.console( + 'ApiException: Error (Status: 500)', + type: LogType.error, + ), + ); + }, + ); + }); +} diff --git a/packages/stadata_flutter_sdk/test/src/features/domains/data/datasources/domain_remote_data_source_test.dart b/packages/stadata_flutter_sdk/test/src/features/domains/data/datasources/domain_remote_data_source_test.dart index 2abbfc9c..504de79b 100644 --- a/packages/stadata_flutter_sdk/test/src/features/domains/data/datasources/domain_remote_data_source_test.dart +++ b/packages/stadata_flutter_sdk/test/src/features/domains/data/datasources/domain_remote_data_source_test.dart @@ -7,10 +7,10 @@ import 'package:stadata_flutter_sdk/src/shared/shared.dart'; import '../../../../../fixtures/fixtures.dart'; import '../../../../../helpers/test_injection.dart'; -class MockStadataHttpModule extends Mock implements StadataHttpModule {} +class MockNetworkClient extends Mock implements NetworkClient {} void main() { - late StadataHttpModule mockHttpModule; + late NetworkClient mockNetworkClient; late DomainRemoteDataSource dataSource; late ApiResponseModel?> domains; late JSON response; @@ -18,8 +18,10 @@ void main() { setUpAll( () { - mockHttpModule = MockStadataHttpModule(); - registerTestLazySingleton(mockHttpModule); + mockNetworkClient = MockNetworkClient(); + registerTestLazySingleton( + mockNetworkClient, + ); dataSource = DomainRemoteDataSourceImpl(); response = jsonFromFixture(Fixture.domains); @@ -50,7 +52,7 @@ void main() { 'should return List of domains if success', () async { when( - () => mockHttpModule.get(ApiEndpoint.domain()), + () => mockNetworkClient.get(ApiEndpoint.domain()), ).thenAnswer( (_) async => response, ); @@ -59,7 +61,7 @@ void main() { expect(result, equals(domains)); verify( - () => mockHttpModule.get(ApiEndpoint.domain()), + () => mockNetworkClient.get(ApiEndpoint.domain()), ).called(1); }, ); @@ -68,7 +70,7 @@ void main() { 'should throw DomainNotAvailableException when list-not-available', () async { when( - () => mockHttpModule.get(ApiEndpoint.domain()), + () => mockNetworkClient.get(ApiEndpoint.domain()), ).thenAnswer( (_) async => unavailableResponse, ); @@ -82,7 +84,7 @@ void main() { ), ); verify( - () => mockHttpModule.get(ApiEndpoint.domain()), + () => mockNetworkClient.get(ApiEndpoint.domain()), ).called(1); }, ); diff --git a/packages/stadata_flutter_sdk/test/src/features/infographics/data/datasources/infographic_remote_data_source_test.dart b/packages/stadata_flutter_sdk/test/src/features/infographics/data/datasources/infographic_remote_data_source_test.dart index 53816355..966bbb98 100644 --- a/packages/stadata_flutter_sdk/test/src/features/infographics/data/datasources/infographic_remote_data_source_test.dart +++ b/packages/stadata_flutter_sdk/test/src/features/infographics/data/datasources/infographic_remote_data_source_test.dart @@ -7,10 +7,10 @@ import 'package:stadata_flutter_sdk/src/shared/shared.dart'; import '../../../../../fixtures/fixtures.dart'; import '../../../../../helpers/test_injection.dart'; -class MockStadataListHttpModule extends Mock implements StadataListHttpModule {} +class MockNetworkClient extends Mock implements NetworkClient {} void main() { - late StadataListHttpModule mockListHttpModule; + late NetworkClient mockNetworkClient; late InfographicRemoteDataSource dataSource; late ApiResponseModel?> infographics; late JSON listResponse; @@ -18,8 +18,11 @@ void main() { setUpAll( () { - mockListHttpModule = MockStadataListHttpModule(); - registerTestLazySingleton(mockListHttpModule); + mockNetworkClient = MockNetworkClient(); + registerTestFactory( + mockNetworkClient, + instanceName: 'listClient', + ); dataSource = InfographicRemoteDataSourceImpl(); listResponse = jsonFromFixture(Fixture.infographics); @@ -53,7 +56,7 @@ void main() { () async { // arrange when( - () => mockListHttpModule.get( + () => mockNetworkClient.get( ApiEndpoint.infographic( domain: domain, ), @@ -68,7 +71,7 @@ void main() { // assert expect(result, infographics); verify( - () => mockListHttpModule.get( + () => mockNetworkClient.get( ApiEndpoint.infographic( domain: domain, ), @@ -82,7 +85,7 @@ void main() { () async { // arrange when( - () => mockListHttpModule.get( + () => mockNetworkClient.get( ApiEndpoint.infographic( domain: domain, ), @@ -102,7 +105,7 @@ void main() { ), ); verify( - () => mockListHttpModule.get( + () => mockNetworkClient.get( ApiEndpoint.infographic( domain: domain, ), diff --git a/packages/stadata_flutter_sdk/test/src/features/news/data/datasources/news_remote_data_source_test.dart b/packages/stadata_flutter_sdk/test/src/features/news/data/datasources/news_remote_data_source_test.dart index fbe9020b..ee6d5174 100644 --- a/packages/stadata_flutter_sdk/test/src/features/news/data/datasources/news_remote_data_source_test.dart +++ b/packages/stadata_flutter_sdk/test/src/features/news/data/datasources/news_remote_data_source_test.dart @@ -7,21 +7,27 @@ import 'package:stadata_flutter_sdk/src/shared/shared.dart'; import '../../../../../fixtures/fixtures.dart'; import '../../../../../helpers/test_injection.dart'; -class MockStadataListHttpModule extends Mock implements StadataListHttpModule {} +class MockListNetworkClient extends Mock implements NetworkClient {} -class MockStadataViewHttpModule extends Mock implements StadataViewHttpModule {} +class MockViewNetworkClient extends Mock implements NetworkClient {} void main() { - late StadataListHttpModule mockListHttpModule; - late StadataViewHttpModule mockViewHttpModule; + late NetworkClient mockListClient; + late NetworkClient mockViewClient; late NewsRemoteDataSource dataSource; setUpAll( () { - mockListHttpModule = MockStadataListHttpModule(); - registerTestLazySingleton(mockListHttpModule); - mockViewHttpModule = MockStadataViewHttpModule(); - registerTestLazySingleton(mockViewHttpModule); + mockListClient = MockListNetworkClient(); + registerTestFactory( + mockListClient, + instanceName: 'listClient', + ); + mockViewClient = MockViewNetworkClient(); + registerTestFactory( + mockViewClient, + instanceName: 'viewClient', + ); dataSource = NewsRemoteDataSourceImpl(); }, ); @@ -67,7 +73,8 @@ void main() { () async { // arrange when( - () => mockListHttpModule.get(ApiEndpoint.news(domain: domain)), + () => + mockListClient.get(ApiEndpoint.news(domain: domain)), ).thenAnswer((_) async => response); // act @@ -76,7 +83,8 @@ void main() { // assert expect(result, equals(data)); verify( - () => mockListHttpModule.get(ApiEndpoint.news(domain: domain)), + () => + mockListClient.get(ApiEndpoint.news(domain: domain)), ).called(1); }, ); @@ -85,7 +93,7 @@ void main() { 'should throw NewsNotAvailableException when list-not-available', () async { when( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.news( domain: domain, ), @@ -103,7 +111,7 @@ void main() { ), ); verify( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.news( domain: domain, ), @@ -145,7 +153,7 @@ void main() { () async { // arrange when( - () => mockViewHttpModule.get( + () => mockViewClient.get( ApiEndpoint.newsDetail( id: id, domain: domain, @@ -162,7 +170,7 @@ void main() { // assert expect(result, equals(data)); verify( - () => mockViewHttpModule.get( + () => mockViewClient.get( ApiEndpoint.newsDetail( id: id, domain: domain, @@ -177,7 +185,7 @@ void main() { () async { // arrange when( - () => mockViewHttpModule.get( + () => mockViewClient.get( ApiEndpoint.newsDetail( id: id, domain: domain, @@ -199,7 +207,7 @@ void main() { ), ); verify( - () => mockViewHttpModule.get( + () => mockViewClient.get( ApiEndpoint.newsDetail( id: id, domain: domain, diff --git a/packages/stadata_flutter_sdk/test/src/features/news_categories/data/datasources/news_category_remote_data_source_test.dart b/packages/stadata_flutter_sdk/test/src/features/news_categories/data/datasources/news_category_remote_data_source_test.dart index 2e785c19..399d3945 100644 --- a/packages/stadata_flutter_sdk/test/src/features/news_categories/data/datasources/news_category_remote_data_source_test.dart +++ b/packages/stadata_flutter_sdk/test/src/features/news_categories/data/datasources/news_category_remote_data_source_test.dart @@ -7,10 +7,10 @@ import 'package:stadata_flutter_sdk/src/shared/shared.dart'; import '../../../../../fixtures/fixtures.dart'; import '../../../../../helpers/test_injection.dart'; -class MockStadataListHttpModule extends Mock implements StadataListHttpModule {} +class MockListNetworkClient extends Mock implements NetworkClient {} void main() { - late StadataListHttpModule mockListHttpModule; + late NetworkClient mockListClient; late NewsCategoryRemoteDataSource dataSource; late ApiResponseModel?> data; late JSON response; @@ -18,8 +18,11 @@ void main() { setUpAll( () { - mockListHttpModule = MockStadataListHttpModule(); - registerTestLazySingleton(mockListHttpModule); + mockListClient = MockListNetworkClient(); + registerTestFactory( + mockListClient, + instanceName: 'listClient', + ); dataSource = NewsCategoryRemoteDataSourceImpl(); response = jsonFromFixture(Fixture.newsCategory); @@ -53,7 +56,7 @@ void main() { 'should return List of news categories if success', () async { when( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.newsCategory( domain: domain, ), @@ -68,7 +71,7 @@ void main() { expect(result, equals(data)); verify( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.newsCategory( domain: domain, ), @@ -82,7 +85,7 @@ void main() { 'when list-not-available', () async { when( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.newsCategory(domain: domain), ), ).thenAnswer( @@ -100,7 +103,7 @@ void main() { ), ); verify( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.newsCategory(domain: domain), ), ).called(1); diff --git a/packages/stadata_flutter_sdk/test/src/features/press_releases/data/datasources/press_release_remote_data_source_test.dart b/packages/stadata_flutter_sdk/test/src/features/press_releases/data/datasources/press_release_remote_data_source_test.dart index d8a68e10..048d0fda 100644 --- a/packages/stadata_flutter_sdk/test/src/features/press_releases/data/datasources/press_release_remote_data_source_test.dart +++ b/packages/stadata_flutter_sdk/test/src/features/press_releases/data/datasources/press_release_remote_data_source_test.dart @@ -7,21 +7,27 @@ import 'package:stadata_flutter_sdk/src/shared/shared.dart'; import '../../../../../fixtures/fixtures.dart'; import '../../../../../helpers/test_injection.dart'; -class MockStadataListHttpModule extends Mock implements StadataListHttpModule {} +class MockListNetworkClient extends Mock implements NetworkClient {} -class MockStadataViewHttpModule extends Mock implements StadataViewHttpModule {} +class MockViewNetworkClient extends Mock implements NetworkClient {} void main() { - late StadataListHttpModule mockListHttpModule; - late StadataViewHttpModule mockViewHttpModule; + late NetworkClient mockListClient; + late NetworkClient mockViewClient; late PressReleaseRemoteDataSource dataSource; setUpAll( () { - mockListHttpModule = MockStadataListHttpModule(); - registerTestLazySingleton(mockListHttpModule); - mockViewHttpModule = MockStadataViewHttpModule(); - registerTestLazySingleton(mockViewHttpModule); + mockListClient = MockListNetworkClient(); + registerTestFactory( + mockListClient, + instanceName: 'listClient', + ); + mockViewClient = MockViewNetworkClient(); + registerTestFactory( + mockViewClient, + instanceName: 'viewClient', + ); dataSource = PressReleaseRemoteDataSourceImpl(); }, ); @@ -65,8 +71,8 @@ void main() { () async { // arrange when( - () => mockListHttpModule - .get(ApiEndpoint.pressReleases(domain: domain)), + () => mockListClient + .get(ApiEndpoint.pressReleases(domain: domain)), ).thenAnswer((_) async => response); // act @@ -75,8 +81,8 @@ void main() { // assert expect(result, equals(data)); verify( - () => mockListHttpModule - .get(ApiEndpoint.pressReleases(domain: domain)), + () => mockListClient + .get(ApiEndpoint.pressReleases(domain: domain)), ).called(1); }, ); @@ -85,7 +91,7 @@ void main() { 'should throw PressReleaseNotAvailable when list-not-available', () async { when( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.pressReleases( domain: domain, ), @@ -103,7 +109,7 @@ void main() { ), ); verify( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.pressReleases( domain: domain, ), @@ -145,7 +151,7 @@ void main() { () async { // arrange when( - () => mockViewHttpModule.get( + () => mockViewClient.get( ApiEndpoint.pressReleaseDetail( id: id, domain: domain, @@ -162,7 +168,7 @@ void main() { // assert expect(result, equals(data)); verify( - () => mockViewHttpModule.get( + () => mockViewClient.get( ApiEndpoint.pressReleaseDetail( id: id, domain: domain, @@ -177,7 +183,7 @@ void main() { () async { // arrange when( - () => mockViewHttpModule.get( + () => mockViewClient.get( ApiEndpoint.pressReleaseDetail( id: id, domain: domain, @@ -199,7 +205,7 @@ void main() { ), ); verify( - () => mockViewHttpModule.get( + () => mockViewClient.get( ApiEndpoint.pressReleaseDetail( id: id, domain: domain, diff --git a/packages/stadata_flutter_sdk/test/src/features/publications/data/datasources/publication_remote_data_source_test.dart b/packages/stadata_flutter_sdk/test/src/features/publications/data/datasources/publication_remote_data_source_test.dart index f4f729e4..a1ee848b 100644 --- a/packages/stadata_flutter_sdk/test/src/features/publications/data/datasources/publication_remote_data_source_test.dart +++ b/packages/stadata_flutter_sdk/test/src/features/publications/data/datasources/publication_remote_data_source_test.dart @@ -7,21 +7,27 @@ import 'package:stadata_flutter_sdk/src/shared/shared.dart'; import '../../../../../fixtures/fixtures.dart'; import '../../../../../helpers/test_injection.dart'; -class MockStadataListHttpModule extends Mock implements StadataListHttpModule {} +class MockListNetworkClient extends Mock implements NetworkClient {} -class MockStadataViewHttpModule extends Mock implements StadataViewHttpModule {} +class MockViewNetworkClient extends Mock implements NetworkClient {} void main() { - late StadataListHttpModule mockListHttpModule; - late StadataViewHttpModule mockViewHttpModule; + late NetworkClient mockListClient; + late NetworkClient mockViewClient; late PublicationRemoteDataSource dataSource; setUpAll( () { - mockListHttpModule = MockStadataListHttpModule(); - registerTestLazySingleton(mockListHttpModule); - mockViewHttpModule = MockStadataViewHttpModule(); - registerTestLazySingleton(mockViewHttpModule); + mockListClient = MockListNetworkClient(); + registerTestFactory( + mockListClient, + instanceName: 'listClient', + ); + mockViewClient = MockViewNetworkClient(); + registerTestFactory( + mockViewClient, + instanceName: 'viewClient', + ); dataSource = PublicationRemoteDataSourceImpl(); }, ); @@ -65,8 +71,8 @@ void main() { () async { // arrange when( - () => mockListHttpModule - .get(ApiEndpoint.publication(domain: domain)), + () => mockListClient + .get(ApiEndpoint.publication(domain: domain)), ).thenAnswer((_) async => response); // act @@ -75,8 +81,8 @@ void main() { // assert expect(result, equals(data)); verify( - () => mockListHttpModule - .get(ApiEndpoint.publication(domain: domain)), + () => mockListClient + .get(ApiEndpoint.publication(domain: domain)), ).called(1); }, ); @@ -85,7 +91,7 @@ void main() { 'should throw PublicationNotAvailable when list-not-available', () async { when( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.publication( domain: domain, ), @@ -103,7 +109,7 @@ void main() { ), ); verify( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.publication( domain: domain, ), @@ -145,7 +151,7 @@ void main() { () async { // arrange when( - () => mockViewHttpModule.get( + () => mockViewClient.get( ApiEndpoint.publicationDetail( id: id, domain: domain, @@ -162,7 +168,7 @@ void main() { // assert expect(result, equals(data)); verify( - () => mockViewHttpModule.get( + () => mockViewClient.get( ApiEndpoint.publicationDetail( id: id, domain: domain, @@ -177,7 +183,7 @@ void main() { () async { // arrange when( - () => mockViewHttpModule.get( + () => mockViewClient.get( ApiEndpoint.publicationDetail( id: id, domain: domain, @@ -199,7 +205,7 @@ void main() { ), ); verify( - () => mockViewHttpModule.get( + () => mockViewClient.get( ApiEndpoint.publicationDetail( id: id, domain: domain, diff --git a/packages/stadata_flutter_sdk/test/src/features/static_tables/data/datasources/static_table_remote_data_source_test.dart b/packages/stadata_flutter_sdk/test/src/features/static_tables/data/datasources/static_table_remote_data_source_test.dart index 54fe6f9c..ae42ff96 100644 --- a/packages/stadata_flutter_sdk/test/src/features/static_tables/data/datasources/static_table_remote_data_source_test.dart +++ b/packages/stadata_flutter_sdk/test/src/features/static_tables/data/datasources/static_table_remote_data_source_test.dart @@ -7,21 +7,27 @@ import 'package:stadata_flutter_sdk/src/shared/shared.dart'; import '../../../../../fixtures/fixtures.dart'; import '../../../../../helpers/test_injection.dart'; -class MockStadataListHttpModule extends Mock implements StadataListHttpModule {} +class MockListNetworkClient extends Mock implements NetworkClient {} -class MockStadataViewHttpModule extends Mock implements StadataViewHttpModule {} +class MockViewNetworkClient extends Mock implements NetworkClient {} void main() { - late StadataListHttpModule mockListHttpModule; - late StadataViewHttpModule mockViewHttpModule; + late NetworkClient mockListClient; + late NetworkClient mockViewClient; late StaticTableRemoteDataSource dataSource; setUpAll( () { - mockListHttpModule = MockStadataListHttpModule(); - registerTestLazySingleton(mockListHttpModule); - mockViewHttpModule = MockStadataViewHttpModule(); - registerTestLazySingleton(mockViewHttpModule); + mockListClient = MockListNetworkClient(); + registerTestFactory( + mockListClient, + instanceName: 'listClient', + ); + mockViewClient = MockViewNetworkClient(); + registerTestFactory( + mockViewClient, + instanceName: 'viewClient', + ); dataSource = StaticTableRemoteDataSourceImpl(); }, ); @@ -64,8 +70,8 @@ void main() { () async { // arrange when( - () => mockListHttpModule - .get(ApiEndpoint.staticTable(domain: domain)), + () => mockListClient + .get(ApiEndpoint.staticTable(domain: domain)), ).thenAnswer((_) async => response); // act @@ -74,8 +80,8 @@ void main() { // assert expect(result, equals(data)); verify( - () => mockListHttpModule - .get(ApiEndpoint.staticTable(domain: domain)), + () => mockListClient + .get(ApiEndpoint.staticTable(domain: domain)), ).called(1); }, ); @@ -84,7 +90,7 @@ void main() { 'should throw StaticTableNotAvailable when list-not-available', () async { when( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.staticTable( domain: domain, ), @@ -106,7 +112,7 @@ void main() { ), ); verify( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.staticTable( domain: domain, ), @@ -146,7 +152,7 @@ void main() { () async { // arrange when( - () => mockViewHttpModule.get( + () => mockViewClient.get( ApiEndpoint.staticTableDetail( id: id, domain: domain, @@ -163,7 +169,7 @@ void main() { // assert expect(result, equals(data)); verify( - () => mockViewHttpModule.get( + () => mockViewClient.get( ApiEndpoint.staticTableDetail( id: id, domain: domain, @@ -178,7 +184,7 @@ void main() { () async { // arrange when( - () => mockViewHttpModule.get( + () => mockViewClient.get( ApiEndpoint.staticTableDetail( id: id, domain: domain, @@ -204,7 +210,7 @@ void main() { ), ); verify( - () => mockViewHttpModule.get( + () => mockViewClient.get( ApiEndpoint.staticTableDetail( id: id, domain: domain, diff --git a/packages/stadata_flutter_sdk/test/src/features/statistical_classification/data/datasources/statistic_classification_remote_data_source_test.dart b/packages/stadata_flutter_sdk/test/src/features/statistical_classification/data/datasources/statistic_classification_remote_data_source_test.dart index 458da4e8..8fbcc17a 100644 --- a/packages/stadata_flutter_sdk/test/src/features/statistical_classification/data/datasources/statistic_classification_remote_data_source_test.dart +++ b/packages/stadata_flutter_sdk/test/src/features/statistical_classification/data/datasources/statistic_classification_remote_data_source_test.dart @@ -7,21 +7,27 @@ import 'package:stadata_flutter_sdk/src/shared/shared.dart'; import '../../../../../fixtures/fixtures.dart'; import '../../../../../helpers/test_injection.dart'; -class MockStadataListHttpModule extends Mock implements StadataListHttpModule {} +class MockListNetworkClient extends Mock implements NetworkClient {} -class MockStadataViewHttpModule extends Mock implements StadataViewHttpModule {} +class MockViewNetworkClient extends Mock implements NetworkClient {} void main() { - late final StadataListHttpModule mockListHttpModule; - late final StadataViewHttpModule mockViewHttpModule; + late final NetworkClient mockListClient; + late final NetworkClient mockViewClient; late final StatisticClassificationRemoteDataSource dataSource; setUpAll( () { - mockListHttpModule = MockStadataListHttpModule(); - registerTestLazySingleton(mockListHttpModule); - mockViewHttpModule = MockStadataViewHttpModule(); - registerTestLazySingleton(mockViewHttpModule); + mockListClient = MockListNetworkClient(); + registerTestFactory( + mockListClient, + instanceName: 'listClient', + ); + mockViewClient = MockViewNetworkClient(); + registerTestFactory( + mockViewClient, + instanceName: 'viewClient', + ); dataSource = StatisticClassificationRemoteDataSourceImpl(); }, ); @@ -75,11 +81,11 @@ void main() { () async { // arrange when( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.statisticClassification( type: KBLIType.y2009, ), - param: { + queryParams: { 'lang': DataLanguage.id.value, 'page': 1, 'perpage': 10, @@ -95,11 +101,11 @@ void main() { // assert expect(result, equals(data)); verify( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.statisticClassification( type: KBLIType.y2009, ), - param: { + queryParams: { 'lang': DataLanguage.id.value, 'page': 1, 'perpage': 10, @@ -114,11 +120,11 @@ void main() { () async { // arrange when( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.statisticClassification( type: KBLIType.y2009, ), - param: { + queryParams: { 'level': KBLILevel.category.value, 'lang': DataLanguage.id.value, 'page': 1, @@ -136,11 +142,11 @@ void main() { // assert expect(result, equals(data)); verify( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.statisticClassification( type: KBLIType.y2009, ), - param: { + queryParams: { 'level': KBLILevel.category.value, 'lang': DataLanguage.id.value, 'page': 1, @@ -157,11 +163,11 @@ void main() { () async { // arrange when( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.statisticClassification( type: KBLIType.y2009, ), - param: { + queryParams: { 'lang': DataLanguage.id.value, 'page': 1, 'perpage': 10, @@ -186,11 +192,11 @@ void main() { ), ); verify( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.statisticClassification( type: KBLIType.y2009, ), - param: { + queryParams: { 'lang': DataLanguage.id.value, 'page': 1, 'perpage': 10, @@ -247,11 +253,11 @@ void main() { () async { // arrange when( - () => mockViewHttpModule.get( + () => mockViewClient.get( ApiEndpoint.statisticClassification( type: KBLIType.y2009, ), - param: { + queryParams: { 'id': id, 'lang': DataLanguage.id.value, 'page': 1, @@ -269,11 +275,11 @@ void main() { // assert expect(result, equals(data)); verify( - () => mockViewHttpModule.get( + () => mockViewClient.get( ApiEndpoint.statisticClassification( type: KBLIType.y2009, ), - param: { + queryParams: { 'id': id, 'lang': DataLanguage.id.value, 'page': 1, @@ -290,11 +296,11 @@ void main() { () async { // arrange when( - () => mockViewHttpModule.get( + () => mockViewClient.get( ApiEndpoint.statisticClassification( type: KBLIType.y2009, ), - param: { + queryParams: { 'id': id, 'lang': DataLanguage.id.value, 'page': 1, @@ -321,11 +327,11 @@ void main() { ), ); verify( - () => mockViewHttpModule.get( + () => mockViewClient.get( ApiEndpoint.statisticClassification( type: KBLIType.y2009, ), - param: { + queryParams: { 'id': id, 'lang': DataLanguage.id.value, 'page': 1, diff --git a/packages/stadata_flutter_sdk/test/src/features/strategic_indicators/data/datasources/strategic_indicator_remote_data_source_test.dart b/packages/stadata_flutter_sdk/test/src/features/strategic_indicators/data/datasources/strategic_indicator_remote_data_source_test.dart index 4f777a08..0dff64d2 100644 --- a/packages/stadata_flutter_sdk/test/src/features/strategic_indicators/data/datasources/strategic_indicator_remote_data_source_test.dart +++ b/packages/stadata_flutter_sdk/test/src/features/strategic_indicators/data/datasources/strategic_indicator_remote_data_source_test.dart @@ -7,16 +7,19 @@ import 'package:stadata_flutter_sdk/src/shared/shared.dart'; import '../../../../../fixtures/fixtures.dart'; import '../../../../../helpers/test_injection.dart'; -class MockStadataListHttpModule extends Mock implements StadataListHttpModule {} +class MockNetworkClient extends Mock implements NetworkClient {} void main() { - late StadataListHttpModule mockListHttpModule; + late NetworkClient mockListClient; late StrategicIndicatorRemoteDataSource dataSource; setUpAll( () { - mockListHttpModule = MockStadataListHttpModule(); - registerTestLazySingleton(mockListHttpModule); + mockListClient = MockNetworkClient(); + registerTestFactory( + mockListClient, + instanceName: 'listClient', + ); dataSource = StrategicIndicatorRemoteDataSourceImpl(); }, ); @@ -59,8 +62,8 @@ void main() { () async { // arrange when( - () => mockListHttpModule - .get(ApiEndpoint.strategicIndicators(domain: domain)), + () => mockListClient + .get(ApiEndpoint.strategicIndicators(domain: domain)), ).thenAnswer((_) async => response); // act @@ -69,8 +72,8 @@ void main() { // assert expect(result, equals(data)); verify( - () => mockListHttpModule - .get(ApiEndpoint.strategicIndicators(domain: domain)), + () => mockListClient + .get(ApiEndpoint.strategicIndicators(domain: domain)), ).called(1); }, ); @@ -80,7 +83,7 @@ void main() { ' when list-not-available', () async { when( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.strategicIndicators( domain: domain, ), @@ -102,7 +105,7 @@ void main() { ), ); verify( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.strategicIndicators( domain: domain, ), diff --git a/packages/stadata_flutter_sdk/test/src/features/subject_categories/data/datasources/subject_category_remote_data_source_test.dart b/packages/stadata_flutter_sdk/test/src/features/subject_categories/data/datasources/subject_category_remote_data_source_test.dart index cef94980..c51fbbe7 100644 --- a/packages/stadata_flutter_sdk/test/src/features/subject_categories/data/datasources/subject_category_remote_data_source_test.dart +++ b/packages/stadata_flutter_sdk/test/src/features/subject_categories/data/datasources/subject_category_remote_data_source_test.dart @@ -7,10 +7,10 @@ import 'package:stadata_flutter_sdk/src/shared/shared.dart'; import '../../../../../fixtures/fixtures.dart'; import '../../../../../helpers/test_injection.dart'; -class MockStadataListHttpModule extends Mock implements StadataListHttpModule {} +class MockNetworkClient extends Mock implements NetworkClient {} void main() { - late StadataListHttpModule mockListHttpModule; + late NetworkClient mockListClient; late SubjectCategoryRemoteDataSource dataSource; late ApiResponseModel?> subjectCategories; late JSON response; @@ -18,8 +18,11 @@ void main() { setUpAll( () { - mockListHttpModule = MockStadataListHttpModule(); - registerTestLazySingleton(mockListHttpModule); + mockListClient = MockNetworkClient(); + registerTestFactory( + mockListClient, + instanceName: 'listClient', + ); dataSource = SubjectCategoryRemoteDataSourceImpl(); response = jsonFromFixture(Fixture.subjectCategories); @@ -55,7 +58,7 @@ void main() { 'should return List of subject categories if success', () async { when( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.subjectCategories(domain: domain), ), ).thenAnswer( @@ -66,7 +69,7 @@ void main() { expect(result, equals(subjectCategories)); verify( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.subjectCategories(domain: domain), ), ).called(1); @@ -78,7 +81,7 @@ void main() { 'list-not-available', () async { when( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.subjectCategories( domain: domain, ), @@ -96,7 +99,7 @@ void main() { ), ); verify( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.subjectCategories( domain: domain, ), diff --git a/packages/stadata_flutter_sdk/test/src/features/subjects/data/datasources/subject_remote_data_source_test.dart b/packages/stadata_flutter_sdk/test/src/features/subjects/data/datasources/subject_remote_data_source_test.dart index 9cde89b3..9e2242c3 100644 --- a/packages/stadata_flutter_sdk/test/src/features/subjects/data/datasources/subject_remote_data_source_test.dart +++ b/packages/stadata_flutter_sdk/test/src/features/subjects/data/datasources/subject_remote_data_source_test.dart @@ -7,10 +7,10 @@ import 'package:stadata_flutter_sdk/src/shared/shared.dart'; import '../../../../../fixtures/fixtures.dart'; import '../../../../../helpers/test_injection.dart'; -class MockStadataListHttpModule extends Mock implements StadataListHttpModule {} +class MockNetworkClient extends Mock implements NetworkClient {} void main() { - late StadataListHttpModule mockListHttpModule; + late NetworkClient mockListClient; late SubjectRemoteDataSource dataSource; late ApiResponseModel?> subjects; late JSON response; @@ -18,9 +18,10 @@ void main() { setUpAll( () { - mockListHttpModule = MockStadataListHttpModule(); - registerTestLazySingleton( - mockListHttpModule, + mockListClient = MockNetworkClient(); + registerTestFactory( + mockListClient, + instanceName: 'listClient', ); dataSource = SubjectRemoteDataSourceImpl(); @@ -54,7 +55,7 @@ void main() { 'should return List of subjects if success', () async { when( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.subjects(domain: domain), ), ).thenAnswer( @@ -65,7 +66,7 @@ void main() { expect(result, equals(subjects)); verify( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.subjects(domain: domain), ), ).called(1); @@ -77,7 +78,7 @@ void main() { 'list-not-available', () async { when( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.subjects( domain: domain, ), @@ -95,7 +96,7 @@ void main() { ), ); verify( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.subjects( domain: domain, ), diff --git a/packages/stadata_flutter_sdk/test/src/features/units/data/datasources/unit_data_remote_data_source_test.dart b/packages/stadata_flutter_sdk/test/src/features/units/data/datasources/unit_data_remote_data_source_test.dart index 685ca983..a1ee6411 100644 --- a/packages/stadata_flutter_sdk/test/src/features/units/data/datasources/unit_data_remote_data_source_test.dart +++ b/packages/stadata_flutter_sdk/test/src/features/units/data/datasources/unit_data_remote_data_source_test.dart @@ -7,10 +7,10 @@ import 'package:stadata_flutter_sdk/src/shared/shared.dart'; import '../../../../../fixtures/fixtures.dart'; import '../../../../../helpers/test_injection.dart'; -class MockStadataListHttpModule extends Mock implements StadataListHttpModule {} +class MockNetworkClient extends Mock implements NetworkClient {} void main() { - late StadataListHttpModule mockListHttpModule; + late NetworkClient mockListClient; late UnitDataRemoteDataSource dataSource; late ApiResponseModel?> units; late JSON response; @@ -18,8 +18,11 @@ void main() { setUpAll( () { - mockListHttpModule = MockStadataListHttpModule(); - registerTestLazySingleton(mockListHttpModule); + mockListClient = MockNetworkClient(); + registerTestFactory( + mockListClient, + instanceName: 'listClient', + ); dataSource = UnitDataRemoteDataSourceImpl(); response = jsonFromFixture(Fixture.units); @@ -52,7 +55,7 @@ void main() { 'should return List of units if success', () async { when( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.units(domain: domain), ), ).thenAnswer( @@ -63,7 +66,7 @@ void main() { expect(result, equals(units)); verify( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.units(domain: domain), ), ).called(1); @@ -75,7 +78,7 @@ void main() { 'list-not-available', () async { when( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.units( domain: domain, ), @@ -93,7 +96,7 @@ void main() { ), ); verify( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.units( domain: domain, ), diff --git a/packages/stadata_flutter_sdk/test/src/features/variables/data/datasources/variable_remote_data_source_test.dart b/packages/stadata_flutter_sdk/test/src/features/variables/data/datasources/variable_remote_data_source_test.dart index b34469d8..44c6f63d 100644 --- a/packages/stadata_flutter_sdk/test/src/features/variables/data/datasources/variable_remote_data_source_test.dart +++ b/packages/stadata_flutter_sdk/test/src/features/variables/data/datasources/variable_remote_data_source_test.dart @@ -7,10 +7,10 @@ import 'package:stadata_flutter_sdk/src/shared/shared.dart'; import '../../../../../fixtures/fixtures.dart'; import '../../../../../helpers/test_injection.dart'; -class MockStadataListHttpModule extends Mock implements StadataListHttpModule {} +class MockNetworkClient extends Mock implements NetworkClient {} void main() { - late StadataListHttpModule mockListHttpModule; + late NetworkClient mockListClient; late VariableRemoteDataSource dataSource; late ApiResponseModel?> variables; late JSON response; @@ -18,8 +18,11 @@ void main() { setUpAll( () { - mockListHttpModule = MockStadataListHttpModule(); - registerTestLazySingleton(mockListHttpModule); + mockListClient = MockNetworkClient(); + registerTestFactory( + mockListClient, + instanceName: 'listClient', + ); dataSource = VariableRemoteDataSourceImpl(); response = jsonFromFixture(Fixture.variables); @@ -52,7 +55,7 @@ void main() { 'should return List of variables if success', () async { when( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.variables(domain: domain), ), ).thenAnswer( @@ -63,7 +66,7 @@ void main() { expect(result, equals(variables)); verify( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.variables(domain: domain), ), ).called(1); @@ -75,7 +78,7 @@ void main() { 'list-not-available', () async { when( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.variables( domain: domain, ), @@ -93,7 +96,7 @@ void main() { ), ); verify( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.variables( domain: domain, ), diff --git a/packages/stadata_flutter_sdk/test/src/features/vertical_variables/data/datasources/vertical_variable_remote_data_source_test.dart b/packages/stadata_flutter_sdk/test/src/features/vertical_variables/data/datasources/vertical_variable_remote_data_source_test.dart index 603e3301..683145da 100644 --- a/packages/stadata_flutter_sdk/test/src/features/vertical_variables/data/datasources/vertical_variable_remote_data_source_test.dart +++ b/packages/stadata_flutter_sdk/test/src/features/vertical_variables/data/datasources/vertical_variable_remote_data_source_test.dart @@ -7,10 +7,10 @@ import 'package:stadata_flutter_sdk/src/shared/shared.dart'; import '../../../../../fixtures/fixtures.dart'; import '../../../../../helpers/test_injection.dart'; -class MockStadataListHttpModule extends Mock implements StadataListHttpModule {} +class MockNetworkClient extends Mock implements NetworkClient {} void main() { - late StadataListHttpModule mockListHttpModule; + late NetworkClient mockListClient; late VerticalVariableRemoteDataSource dataSource; late ApiResponseModel?> verticalVariables; late JSON response; @@ -18,8 +18,11 @@ void main() { setUpAll( () { - mockListHttpModule = MockStadataListHttpModule(); - registerTestLazySingleton(mockListHttpModule); + mockListClient = MockNetworkClient(); + registerTestFactory( + mockListClient, + instanceName: 'listClient', + ); dataSource = VerticalVariableRemoteDataSourceImpl(); response = jsonFromFixture(Fixture.verticalVariables); @@ -55,7 +58,7 @@ void main() { 'should return List of vertical variables if success', () async { when( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.verticalVariables(domain: domain), ), ).thenAnswer( @@ -66,7 +69,7 @@ void main() { expect(result, equals(verticalVariables)); verify( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.verticalVariables(domain: domain), ), ).called(1); @@ -78,7 +81,7 @@ void main() { 'list-not-available', () async { when( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.verticalVariables( domain: domain, ), @@ -96,7 +99,7 @@ void main() { ), ); verify( - () => mockListHttpModule.get( + () => mockListClient.get( ApiEndpoint.verticalVariables( domain: domain, ),