diff --git a/lib/core/init/network/ICoreDio.dart b/lib/core/init/network/ICoreDio.dart index 685600a..bee2377 100644 --- a/lib/core/init/network/ICoreDio.dart +++ b/lib/core/init/network/ICoreDio.dart @@ -9,6 +9,15 @@ abstract class ICoreDio { {@required HttpTypes type, @required T parseModel, dynamic data, - Map queryParameters, + Map queryParameters, + void Function(int, int) onReceiveProgress}); +} + +abstract class ICoreDioFull extends ICoreDio { + Future> fetchNoNetwork(String path, + {@required HttpTypes type, + @required T parseModel, + dynamic data, + Map queryParameters, void Function(int, int) onReceiveProgress}); } diff --git a/lib/core/init/network/core_dio.dart b/lib/core/init/network/core_dio.dart index f08e2ac..1acf806 100644 --- a/lib/core/init/network/core_dio.dart +++ b/lib/core/init/network/core_dio.dart @@ -32,7 +32,7 @@ class CoreDio with DioMixin implements Dio, ICoreDio { switch (response.statusCode) { case HttpStatus.ok: case HttpStatus.accepted: - final model = _responseParser(parseModel, _responseParser); + final model = _responseParser(parseModel, response.data); return ResponseModel(data: model); default: return ResponseModel(error: BaseError("message")); diff --git a/lib/core/init/network/network_core/core_operations.dart b/lib/core/init/network/network_core/core_operations.dart index 5cb3f8d..b0f7569 100644 --- a/lib/core/init/network/network_core/core_operations.dart +++ b/lib/core/init/network/network_core/core_operations.dart @@ -1,9 +1,9 @@ part of "../core_dio.dart"; extension _CoreDioOperations on CoreDio { - R _responseParser(BaseModel model, dynamic data) { + R _responseParser(BaseModel model, dynamic data) { if (data is List) { - return data.map((e) => model.fromJson(e)).toList() as R; + return data.map((e) => model.fromJson(e)).toList().cast() as R; } else if (data is Map) { return model.fromJson(data) as R; } diff --git a/test/core/extension/string_extension_test.dart b/test/core/extension/string_extension_test.dart new file mode 100644 index 0000000..830f93b --- /dev/null +++ b/test/core/extension/string_extension_test.dart @@ -0,0 +1,10 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:fluttermvvmtemplate/core/extension/string_extension.dart'; + +main() { + setUp(() {}); + test("Email Regexp", () { + String email = "joedoe@gmail.com"; + expect(email.isValidEmail, null); + }); +} diff --git a/test/core/network/core_dio_mock.dart b/test/core/network/core_dio_mock.dart new file mode 100644 index 0000000..eb55611 --- /dev/null +++ b/test/core/network/core_dio_mock.dart @@ -0,0 +1,76 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:dio/adapter.dart'; +import 'package:dio/dio.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:fluttermvvmtemplate/core/base/model/base_error.dart'; +import 'package:fluttermvvmtemplate/core/constants/enums/http_request_enum.dart'; +import 'package:fluttermvvmtemplate/core/base/model/base_model.dart'; +import 'package:fluttermvvmtemplate/core/extension/network_exntension.dart'; +import 'package:fluttermvvmtemplate/core/init/network/ICoreDio.dart'; +import 'package:fluttermvvmtemplate/core/init/network/IResponseModel.dart'; + +class CoreDioMock with DioMixin implements ICoreDioFull, Dio { + final BaseOptions options; + + CoreDioMock(this.options) { + this.options = options; + this.interceptors.add(InterceptorsWrapper()); + this.httpClientAdapter = DefaultHttpClientAdapter(); + } + @override + Future> fetch(String path, + {HttpTypes type, + T parseModel, + data, + Map queryParameters, + void Function(int p1, int p2) onReceiveProgress}) async { + final response = await request(path, data: data, options: Options(method: type.rawValue)); + + switch (response.statusCode) { + case HttpStatus.ok: + case HttpStatus.accepted: + final model = _responseParser(parseModel, response.data); + return ResponseModel(data: model); + default: + return ResponseModel(error: BaseError("message")); + } + } + + Future> fetchNoNetwork(String path, + {HttpTypes type, + T parseModel, + data, + Map queryParameters, + void Function(int p1, int p2) onReceiveProgress}) async { + String dumyJson = """[ + { + "userId": 1, + "id": 1, + "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", + "body": "quia et suscipit suscipit recusandae consequuntur expedita et cumnreprehenderit molestiae ut ut quas totamnostrum rerum est autem sunt rem eveniet architecto" + }, + { + "userId": 1, + "id": 2, + "title": "qui est esse", + "body": "est rerum tempore vitaensequi sint nihil reprehenderit dolor beatae ea dolores nequenfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendisnqui aperiam non debitis possimus qui neque nisi nulla" + }]"""; + final response = jsonDecode(dumyJson); + final model = _responseParser(parseModel, response); + return ResponseModel(data: model); + } + + R _responseParser(BaseModel model, dynamic data) { + if (data is List) { + return data.map((e) => model.fromJson(e)).toList().cast() as R; + } else if (data is Map) { + return model.fromJson(data) as R; + } + return data as R; + } +} + +class Dio {} diff --git a/test/core/network/core_dio_test.dart b/test/core/network/core_dio_test.dart new file mode 100644 index 0000000..dda81f0 --- /dev/null +++ b/test/core/network/core_dio_test.dart @@ -0,0 +1,47 @@ +import 'package:dio/dio.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:fluttermvvmtemplate/core/constants/enums/http_request_enum.dart'; +import 'package:fluttermvvmtemplate/core/init/network/ICoreDio.dart'; +import 'core_dio_mock.dart'; +import 'dio_mock_model.dart'; + +main() { + ICoreDioFull service; + setUp(() { + service = CoreDioMock(BaseOptions(baseUrl: "https://jsonplaceholder.typicode.com")); + }); + test("CoreDio List", () async { + final data = + await service.fetch, PostModel>("/posts", type: HttpTypes.GET, parseModel: PostModel()); + + expect(data.data, isList); + }); + + test("CoreDio List No Network", () async { + final data = await service.fetchNoNetwork, PostModel>("/posts", + type: HttpTypes.GET, parseModel: PostModel()); + + expect(data.data, isList); + }); + + test("CoreDio Object", () async { + final data = + await service.fetch, PostModel>("/posts", type: HttpTypes.GET, parseModel: PostModel()); + + expect(data.data, isList); + }); + + test("CoreDio Primitive", () async { + final data = + await service.fetch, PostModel>("/posts", type: HttpTypes.GET, parseModel: PostModel()); + + expect(data.data, isList); + }); + + test("CoreDio Error", () async { + final data = await service.fetchNoNetwork, PostModel>("/posts", + type: HttpTypes.GET, parseModel: PostModel()); + + expect(data.data, isList); + }); +} diff --git a/test/core/network/dio_mock_model.dart b/test/core/network/dio_mock_model.dart new file mode 100644 index 0000000..79f4672 --- /dev/null +++ b/test/core/network/dio_mock_model.dart @@ -0,0 +1,31 @@ +import 'package:fluttermvvmtemplate/core/base/model/base_model.dart'; + +class PostModel extends BaseModel { + int userId; + int id; + String title; + String body; + + PostModel({this.userId, this.id, this.title, this.body}); + + PostModel.fromJson(Map json) { + userId = json['userId']; + id = json['id']; + title = json['title']; + body = json['body']; + } + + Map toJson() { + final Map data = new Map(); + data['userId'] = this.userId; + data['id'] = this.id; + data['title'] = this.title; + data['body'] = this.body; + return data; + } + + @override + PostModel fromJson(Map json) { + return PostModel.fromJson(json); + } +} diff --git a/test/feature/login/login_test.dart b/test/feature/login/login_test.dart index 36963c6..1e98d44 100644 --- a/test/feature/login/login_test.dart +++ b/test/feature/login/login_test.dart @@ -1,7 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:fluttermvvmtemplate/core/base/model/base_error.dart'; -import 'package:fluttermvvmtemplate/core/base/model/base_model.dart'; -import 'package:fluttermvvmtemplate/view/authenticate/test/model/test_model.dart'; main() { setUp(() { diff --git a/test/feature/onboard/onboard_mock_view_model.dart b/test/feature/onboard/onboard_mock_view_model.dart new file mode 100644 index 0000000..d9ab5f6 --- /dev/null +++ b/test/feature/onboard/onboard_mock_view_model.dart @@ -0,0 +1,67 @@ +import 'package:dio/dio.dart'; +import 'package:fluttermvvmtemplate/core/constants/enums/http_request_enum.dart'; +import 'package:fluttermvvmtemplate/core/init/network/core_dio.dart'; +import 'package:fluttermvvmtemplate/view/authenticate/onboard/model/on_board_model.dart'; +import 'package:fluttermvvmtemplate/core/init/network/ICoreDio.dart'; +import 'package:flutter/src/widgets/framework.dart'; +import 'package:fluttermvvmtemplate/view/authenticate/onboard/view-model/on_board_view_model.dart'; + +import '../../core/network/dio_mock_model.dart'; + +class OnBoardMockViewModel implements OnBoardViewModel { + @override + BuildContext context; + + @override + ICoreDio coreDio; + + IStringHelper stringHelper; + + @override + int currentPageIndex; + + bool isLoading = false; + + @override + List onBoarModel; + + @override + void init() { + coreDio = CoreDio(BaseOptions(baseUrl: "https://jsonplaceholder.typicode.com")); + stringHelper = MockStringHelper(); + } + + @override + void onPageChanged(int value) { + currentPageIndex = value; + } + + Future onBoardGetModels() async { + final response = + await coreDio.fetch, PostModel>("/posts", type: HttpTypes.GET, parseModel: PostModel()); + + if (response.data is List) { + onBoarModel = response.data.map((e) => OnBoardModel(stringHelper.toUpper(e.title))).toList().cast(); + } + } + + Future getServiceRequest() async { + isLoading = true; + await onBoardGetModels(); + isLoading = false; + } + + @override + void setContext(BuildContext context) {} +} + +abstract class IStringHelper { + String toUpper(String data); +} + +class MockStringHelper extends IStringHelper { + @override + String toUpper(String data) { + return data.toUpperCase(); + } +} diff --git a/test/feature/onboard/onboard_test.dart b/test/feature/onboard/onboard_test.dart new file mode 100644 index 0000000..3c853c0 --- /dev/null +++ b/test/feature/onboard/onboard_test.dart @@ -0,0 +1,50 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import 'onboard_mock_view_model.dart'; + +main() { + OnBoardMockViewModel mockViewModel; + IStringHelper stringHelper; + setUp(() { + SharedPreferences.setMockInitialValues({"token": "asdasd"}); //set values here + mockViewModel = OnBoardMockViewModel(); + stringHelper = MockStringHelper(); + mockViewModel.init(); + }); + test("String Helper Upper Case", () { + String text = " Helelo"; + text = stringHelper.toUpper(text); + expect(text.contains(RegExp("[A-Z\s]+")), true); + }); + + test("OnBoard Get Models", () async { + await mockViewModel.onBoardGetModels(); + expect(mockViewModel.onBoarModel, isNotEmpty); + }); + + test("OnBoard Get Service Request", () async { + expect(mockViewModel.isLoading, false); + mockViewModel.getServiceRequest(); + expect(mockViewModel.isLoading, true); + }); + + test("OnBoard On Page Changed", () { + mockViewModel.onPageChanged(5); + expect(5, mockViewModel.currentPageIndex); + }); + + group("Test All", () { + int index = 0; + test("OnBoard Get Models", () async { + await mockViewModel.onBoardGetModels(); + index = mockViewModel.onBoarModel.length; + expect(mockViewModel.onBoarModel, isNotEmpty); + }); + + test("OnBoard On Page Changed", () { + mockViewModel.onPageChanged(index); + expect(index, mockViewModel.currentPageIndex); + }); + }); +} diff --git a/test/feature/test/sample_view_test.dart b/test/feature/test/sample_view_test.dart new file mode 100644 index 0000000..479baa9 --- /dev/null +++ b/test/feature/test/sample_view_test.dart @@ -0,0 +1,11 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:fluttermvvmtemplate/core/init/network/ICoreDio.dart'; +import 'package:fluttermvvmtemplate/core/init/network/network_manager.dart'; + +main() { + ICoreDio coreDio; + setUp(() { + coreDio = NetworkManager.instance.coreDio; + }); + test("Sample", () {}); +}