fix : update local.properties path and improve null safety in chicken_local_imp.dart and chicken_repository_imp.dart; refactor profile view for better readability
This commit is contained in:
Binary file not shown.
@@ -44,12 +44,11 @@ class ChickenLocalDataSourceImp implements ChickenLocalDataSource {
|
|||||||
path: ChickenRoutes.buysInProvinceSteward,
|
path: ChickenRoutes.buysInProvinceSteward,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WidelyUsedLocalModel? getAllWidely() {
|
WidelyUsedLocalModel? getAllWidely() {
|
||||||
var res = local.readBox<WidelyUsedLocalModel>(boxName: boxName);
|
var res = local.readBox<WidelyUsedLocalModel>(boxName: boxName);
|
||||||
return res?.first;
|
return res?.isNotEmpty == true ? res!.first : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,9 @@ class ChickenRepositoryImp implements ChickenRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<KillHouseDistributionInfo?> getKillHouseDistributionInfo({required String token}) async {
|
Future<KillHouseDistributionInfo?> getKillHouseDistributionInfo({
|
||||||
|
required String token,
|
||||||
|
}) async {
|
||||||
var res = await remote.getKillHouseDistributionInfo(token: token);
|
var res = await remote.getKillHouseDistributionInfo(token: token);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -57,7 +59,10 @@ class ChickenRepositoryImp implements ChickenRepository {
|
|||||||
required String token,
|
required String token,
|
||||||
Map<String, dynamic>? queryParameters,
|
Map<String, dynamic>? queryParameters,
|
||||||
}) async {
|
}) async {
|
||||||
var res = await remote.getGeneralBarInformation(token: token, queryParameters: queryParameters);
|
var res = await remote.getGeneralBarInformation(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +71,10 @@ class ChickenRepositoryImp implements ChickenRepository {
|
|||||||
required String token,
|
required String token,
|
||||||
Map<String, dynamic>? queryParameters,
|
Map<String, dynamic>? queryParameters,
|
||||||
}) async {
|
}) async {
|
||||||
var res = await remote.getWaitingArrivals(token: token, queryParameters: queryParameters);
|
var res = await remote.getWaitingArrivals(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +91,10 @@ class ChickenRepositoryImp implements ChickenRepository {
|
|||||||
required String token,
|
required String token,
|
||||||
Map<String, dynamic>? queryParameters,
|
Map<String, dynamic>? queryParameters,
|
||||||
}) async {
|
}) async {
|
||||||
var res = await remote.getImportedLoadsModel(token: token, queryParameters: queryParameters);
|
var res = await remote.getImportedLoadsModel(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +103,10 @@ class ChickenRepositoryImp implements ChickenRepository {
|
|||||||
required String token,
|
required String token,
|
||||||
Map<String, dynamic>? queryParameters,
|
Map<String, dynamic>? queryParameters,
|
||||||
}) async {
|
}) async {
|
||||||
var res = await remote.getAllocatedMade(token: token, queryParameters: queryParameters);
|
var res = await remote.getAllocatedMade(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +119,10 @@ class ChickenRepositoryImp implements ChickenRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> denyAllocation({required String token, required String allocationToken}) async {
|
Future<void> denyAllocation({
|
||||||
|
required String token,
|
||||||
|
required String allocationToken,
|
||||||
|
}) async {
|
||||||
await remote.denyAllocation(token: token, allocationToken: allocationToken);
|
await remote.denyAllocation(token: token, allocationToken: allocationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +131,10 @@ class ChickenRepositoryImp implements ChickenRepository {
|
|||||||
required String token,
|
required String token,
|
||||||
required List<String> allocationTokens,
|
required List<String> allocationTokens,
|
||||||
}) async {
|
}) async {
|
||||||
await remote.confirmAllAllocation(token: token, allocationTokens: allocationTokens);
|
await remote.confirmAllAllocation(
|
||||||
|
token: token,
|
||||||
|
allocationTokens: allocationTokens,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -128,7 +148,10 @@ class ChickenRepositoryImp implements ChickenRepository {
|
|||||||
required String token,
|
required String token,
|
||||||
Map<String, dynamic>? queryParameters,
|
Map<String, dynamic>? queryParameters,
|
||||||
}) async {
|
}) async {
|
||||||
var res = await remote.getGuilds(token: token, queryParameters: queryParameters);
|
var res = await remote.getGuilds(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +174,10 @@ class ChickenRepositoryImp implements ChickenRepository {
|
|||||||
required String token,
|
required String token,
|
||||||
Map<String, dynamic>? queryParameters,
|
Map<String, dynamic>? queryParameters,
|
||||||
}) async {
|
}) async {
|
||||||
await remote.deleteStewardAllocation(token: token, queryParameters: queryParameters);
|
await remote.deleteStewardAllocation(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -191,7 +217,8 @@ class ChickenRepositoryImp implements ChickenRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<PaginationModel<StewardFreeBar>?> getStewardPurchasesOutSideOfTheProvince({
|
Future<PaginationModel<StewardFreeBar>?>
|
||||||
|
getStewardPurchasesOutSideOfTheProvince({
|
||||||
required String token,
|
required String token,
|
||||||
Map<String, dynamic>? queryParameters,
|
Map<String, dynamic>? queryParameters,
|
||||||
}) async {
|
}) async {
|
||||||
@@ -203,13 +230,17 @@ class ChickenRepositoryImp implements ChickenRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<IranProvinceCityModel>?> getCity({required String provinceName}) async {
|
Future<List<IranProvinceCityModel>?> getCity({
|
||||||
|
required String provinceName,
|
||||||
|
}) async {
|
||||||
var res = await remote.getCity(provinceName: provinceName);
|
var res = await remote.getCity(provinceName: provinceName);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<IranProvinceCityModel>?> getProvince({CancelToken? cancelToken}) async {
|
Future<List<IranProvinceCityModel>?> getProvince({
|
||||||
|
CancelToken? cancelToken,
|
||||||
|
}) async {
|
||||||
var res = await remote.getProvince(cancelToken: cancelToken);
|
var res = await remote.getProvince(cancelToken: cancelToken);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -219,7 +250,10 @@ class ChickenRepositoryImp implements ChickenRepository {
|
|||||||
required String token,
|
required String token,
|
||||||
required CreateStewardFreeBar body,
|
required CreateStewardFreeBar body,
|
||||||
}) async {
|
}) async {
|
||||||
await remote.createStewardPurchasesOutSideOfTheProvince(token: token, body: body);
|
await remote.createStewardPurchasesOutSideOfTheProvince(
|
||||||
|
token: token,
|
||||||
|
body: body,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -229,7 +263,8 @@ class ChickenRepositoryImp implements ChickenRepository {
|
|||||||
}) async {
|
}) async {
|
||||||
return await remote.editStewardPurchasesOutSideOfTheProvince(
|
return await remote.editStewardPurchasesOutSideOfTheProvince(
|
||||||
token: token,
|
token: token,
|
||||||
queryParameters: body.toJson()..removeWhere((key, value) => value == null),
|
queryParameters: body.toJson()
|
||||||
|
..removeWhere((key, value) => value == null),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,7 +280,8 @@ class ChickenRepositoryImp implements ChickenRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<PaginationModel<OutProvinceCarcassesBuyer>?> getOutProvinceCarcassesBuyer({
|
Future<PaginationModel<OutProvinceCarcassesBuyer>?>
|
||||||
|
getOutProvinceCarcassesBuyer({
|
||||||
required String token,
|
required String token,
|
||||||
Map<String, dynamic>? queryParameters,
|
Map<String, dynamic>? queryParameters,
|
||||||
}) async {
|
}) async {
|
||||||
@@ -269,7 +305,10 @@ class ChickenRepositoryImp implements ChickenRepository {
|
|||||||
required String token,
|
required String token,
|
||||||
Map<String, dynamic>? queryParameters,
|
Map<String, dynamic>? queryParameters,
|
||||||
}) async {
|
}) async {
|
||||||
var res = await remote.getStewardFreeSaleBar(token: token, queryParameters: queryParameters);
|
var res = await remote.getStewardFreeSaleBar(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,7 +329,10 @@ class ChickenRepositoryImp implements ChickenRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> deleteOutProvinceStewardFreeBar({required String token, required String key}) async {
|
Future<void> deleteOutProvinceStewardFreeBar({
|
||||||
|
required String token,
|
||||||
|
required String key,
|
||||||
|
}) async {
|
||||||
await remote.deleteOutProvinceStewardFreeBar(token: token, key: key);
|
await remote.deleteOutProvinceStewardFreeBar(token: token, key: key);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,7 +343,10 @@ class ChickenRepositoryImp implements ChickenRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> updateUserProfile({required String token, required UserProfile userProfile}) async {
|
Future<void> updateUserProfile({
|
||||||
|
required String token,
|
||||||
|
required UserProfile userProfile,
|
||||||
|
}) async {
|
||||||
await remote.updateUserProfile(token: token, userProfile: userProfile);
|
await remote.updateUserProfile(token: token, userProfile: userProfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,17 +363,26 @@ class ChickenRepositoryImp implements ChickenRepository {
|
|||||||
required String token,
|
required String token,
|
||||||
Map<String, dynamic>? queryParameters,
|
Map<String, dynamic>? queryParameters,
|
||||||
}) async {
|
}) async {
|
||||||
var res = await remote.getSegmentation(token: token, queryParameters: queryParameters);
|
var res = await remote.getSegmentation(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> createSegmentation({required String token, required SegmentationModel model}) async {
|
Future<void> createSegmentation({
|
||||||
|
required String token,
|
||||||
|
required SegmentationModel model,
|
||||||
|
}) async {
|
||||||
await remote.createSegmentation(token: token, model: model);
|
await remote.createSegmentation(token: token, model: model);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> editSegmentation({required String token, required SegmentationModel model}) async {
|
Future<void> editSegmentation({
|
||||||
|
required String token,
|
||||||
|
required SegmentationModel model,
|
||||||
|
}) async {
|
||||||
await remote.editSegmentation(token: token, model: model);
|
await remote.editSegmentation(token: token, model: model);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,7 +408,9 @@ class ChickenRepositoryImp implements ChickenRepository {
|
|||||||
WidelyUsedLocalModel? getAllWidely() => local.getAllWidely();
|
WidelyUsedLocalModel? getAllWidely() => local.getAllWidely();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> initWidleyUsed() async {}
|
Future<void> initWidleyUsed() async {
|
||||||
|
await local.initWidleyUsed();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<StewardSalesInfoDashboard?> getStewardSalesInfoDashboard({
|
Future<StewardSalesInfoDashboard?> getStewardSalesInfoDashboard({
|
||||||
|
|||||||
@@ -32,7 +32,11 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
return Container(
|
return Container(
|
||||||
width: 128.w,
|
width: 128.w,
|
||||||
height: 128.h,
|
height: 128.h,
|
||||||
child: Center(child: CupertinoActivityIndicator(color: AppColor.greenNormal)),
|
child: Center(
|
||||||
|
child: CupertinoActivityIndicator(
|
||||||
|
color: AppColor.greenNormal,
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +75,7 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
|
|
||||||
children: [
|
children: [
|
||||||
rolesWidget(),
|
rolesWidget(),
|
||||||
SizedBox(height: 12.h,),
|
SizedBox(height: 12.h),
|
||||||
|
|
||||||
ObxValue((data) {
|
ObxValue((data) {
|
||||||
if (data.value.status == ResourceStatus.loading) {
|
if (data.value.status == ResourceStatus.loading) {
|
||||||
@@ -96,7 +100,7 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
|
|
||||||
Visibility(
|
Visibility(
|
||||||
visible:
|
visible:
|
||||||
data.value.data?.unitName != null ||
|
data.value.data?.unitName != null ||
|
||||||
data.value.data?.unitAddress != null ||
|
data.value.data?.unitAddress != null ||
|
||||||
data.value.data?.unitPostalCode != null ||
|
data.value.data?.unitPostalCode != null ||
|
||||||
data.value.data?.unitRegistrationNumber != null ||
|
data.value.data?.unitRegistrationNumber != null ||
|
||||||
@@ -124,71 +128,93 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
}
|
}
|
||||||
}, controller.userProfile),
|
}, controller.userProfile),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Get.bottomSheet(
|
Get.bottomSheet(
|
||||||
changePasswordBottomSheet(),
|
changePasswordBottomSheet(),
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 47.h,
|
height: 47.h,
|
||||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 8.h),
|
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 8.h),
|
||||||
padding: EdgeInsets.symmetric(horizontal: 11.h, vertical: 8.h),
|
padding: EdgeInsets.symmetric(
|
||||||
decoration: BoxDecoration(
|
horizontal: 11.h,
|
||||||
color: Colors.white,
|
vertical: 8.h,
|
||||||
borderRadius: BorderRadius.circular(8),
|
),
|
||||||
border: Border.all(width: 1, color: const Color(0xFFD6D6D6)),
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
border: Border.all(
|
||||||
|
width: 1,
|
||||||
|
color: const Color(0xFFD6D6D6),
|
||||||
),
|
),
|
||||||
child: Row(
|
),
|
||||||
spacing: 6,
|
child: Row(
|
||||||
children: [
|
spacing: 6,
|
||||||
Assets.vec.lockSvg.svg(
|
children: [
|
||||||
width: 24.w,
|
Assets.vec.lockSvg.svg(
|
||||||
height: 24.h,
|
width: 24.w,
|
||||||
colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn),
|
height: 24.h,
|
||||||
|
colorFilter: ColorFilter.mode(
|
||||||
|
AppColor.blueNormal,
|
||||||
|
BlendMode.srcIn,
|
||||||
),
|
),
|
||||||
Text(
|
),
|
||||||
'تغییر رمز عبور',
|
Text(
|
||||||
textAlign: TextAlign.center,
|
'تغییر رمز عبور',
|
||||||
style: AppFonts.yekan14.copyWith(color: AppColor.blueNormal),
|
textAlign: TextAlign.center,
|
||||||
|
style: AppFonts.yekan14.copyWith(
|
||||||
|
color: AppColor.blueNormal,
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Get.bottomSheet(
|
Get.bottomSheet(
|
||||||
changePasswordBottomSheet(),
|
changePasswordBottomSheet(),
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 47.h,
|
height: 47.h,
|
||||||
margin: EdgeInsets.symmetric(horizontal: 8),
|
margin: EdgeInsets.symmetric(horizontal: 8),
|
||||||
padding: EdgeInsets.symmetric(horizontal: 11.h, vertical: 8.h),
|
padding: EdgeInsets.symmetric(
|
||||||
decoration: BoxDecoration(
|
horizontal: 11.h,
|
||||||
color: Colors.white,
|
vertical: 8.h,
|
||||||
borderRadius: BorderRadius.circular(8),
|
),
|
||||||
border: Border.all(width: 1, color: const Color(0xFFD6D6D6)),
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
border: Border.all(
|
||||||
|
width: 1,
|
||||||
|
color: const Color(0xFFD6D6D6),
|
||||||
),
|
),
|
||||||
child: Row(
|
),
|
||||||
spacing: 6,
|
child: Row(
|
||||||
children: [
|
spacing: 6,
|
||||||
Assets.vec.logoutSvg.svg(
|
children: [
|
||||||
width: 24.w,
|
Assets.vec.logoutSvg.svg(
|
||||||
height: 24.h,
|
width: 24.w,
|
||||||
colorFilter: ColorFilter.mode(AppColor.redNormal, BlendMode.srcIn),
|
height: 24.h,
|
||||||
|
colorFilter: ColorFilter.mode(
|
||||||
|
AppColor.redNormal,
|
||||||
|
BlendMode.srcIn,
|
||||||
),
|
),
|
||||||
Text(
|
),
|
||||||
'خروج',
|
Text(
|
||||||
textAlign: TextAlign.center,
|
'خروج',
|
||||||
style: AppFonts.yekan14.copyWith(color: AppColor.redNormal),
|
textAlign: TextAlign.center,
|
||||||
|
style: AppFonts.yekan14.copyWith(
|
||||||
|
color: AppColor.redNormal,
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
SizedBox(height: 100),
|
SizedBox(height: 100),
|
||||||
],
|
],
|
||||||
@@ -200,17 +226,16 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
|
|
||||||
Container invoiceIssuanceInformation() => Container();
|
Container invoiceIssuanceInformation() => Container();
|
||||||
|
|
||||||
Widget bankInformationWidget() =>
|
Widget bankInformationWidget() => Column(
|
||||||
Column(
|
spacing: 16,
|
||||||
spacing: 16,
|
children: [
|
||||||
children: [
|
itemList(title: 'نام بانک', content: 'سامان'),
|
||||||
itemList(title: 'نام بانک', content: 'سامان'),
|
itemList(title: 'نام صاحب حساب', content: 'رضا رضایی'),
|
||||||
itemList(title: 'نام صاحب حساب', content: 'رضا رضایی'),
|
itemList(title: 'شماره کارت ', content: '54154545415'),
|
||||||
itemList(title: 'شماره کارت ', content: '54154545415'),
|
itemList(title: 'شماره حساب', content: '62565263263652'),
|
||||||
itemList(title: 'شماره حساب', content: '62565263263652'),
|
itemList(title: 'شماره شبا', content: '62565263263652'),
|
||||||
itemList(title: 'شماره شبا', content: '62565263263652'),
|
],
|
||||||
],
|
);
|
||||||
);
|
|
||||||
|
|
||||||
Widget userProfileInformation(Resource<UserProfile> value) {
|
Widget userProfileInformation(Resource<UserProfile> value) {
|
||||||
UserProfile item = value.data!;
|
UserProfile item = value.data!;
|
||||||
@@ -219,116 +244,131 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
children: [
|
children: [
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: ObxValue(
|
child: ObxValue(
|
||||||
(val) =>
|
(val) => Container(
|
||||||
Container(
|
height: val.value ? 320.h : 47.h,
|
||||||
height: val.value ? 320.h : 47.h,
|
margin: EdgeInsets.symmetric(
|
||||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: val.value ? 8 : 0),
|
horizontal: 8,
|
||||||
padding: EdgeInsets.symmetric(horizontal: 11.h, vertical: 8.h),
|
vertical: val.value ? 8 : 0,
|
||||||
decoration: BoxDecoration(
|
),
|
||||||
color: Colors.white,
|
padding: EdgeInsets.symmetric(horizontal: 11.h, vertical: 8.h),
|
||||||
borderRadius: BorderRadius.circular(8),
|
decoration: BoxDecoration(
|
||||||
border: Border.all(width: 0.5, color: AppColor.darkGreyLight),
|
color: Colors.white,
|
||||||
),
|
borderRadius: BorderRadius.circular(8),
|
||||||
child: val.value
|
border: Border.all(width: 0.5, color: AppColor.darkGreyLight),
|
||||||
? Column(
|
),
|
||||||
spacing: 6,
|
child: val.value
|
||||||
children: [
|
? Column(
|
||||||
Row(
|
spacing: 6,
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
children: [
|
||||||
children: [
|
Row(
|
||||||
GestureDetector(
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
onTap: () {
|
|
||||||
Get.bottomSheet(
|
|
||||||
userInformationBottomSheet(),
|
|
||||||
isScrollControlled: true,
|
|
||||||
ignoreSafeArea: false,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: Assets.vec.editSvg.svg(
|
|
||||||
width: 24.w,
|
|
||||||
height: 24.h,
|
|
||||||
colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
children: [
|
||||||
itemList(
|
GestureDetector(
|
||||||
title: 'نام و نام خانوادگی',
|
onTap: () {
|
||||||
content: item.fullname ?? 'نامشخص',
|
Get.bottomSheet(
|
||||||
icon: Assets.vec.userSvg.path,
|
userInformationBottomSheet(),
|
||||||
hasColoredBox: true,
|
isScrollControlled: true,
|
||||||
),
|
ignoreSafeArea: false,
|
||||||
itemList(
|
);
|
||||||
title: 'کدملی',
|
},
|
||||||
content: item.nationalId ?? 'نامشخص',
|
child: Assets.vec.editSvg.svg(
|
||||||
icon: Assets.vec.tagUserSvg.path,
|
width: 24.w,
|
||||||
),
|
height: 24.h,
|
||||||
itemList(
|
colorFilter: ColorFilter.mode(
|
||||||
title: 'موبایل',
|
AppColor.blueNormal,
|
||||||
content: item.mobile ?? 'نامشخص',
|
BlendMode.srcIn,
|
||||||
icon: Assets.vec.callSvg.path,
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
itemList(
|
|
||||||
title: 'شماره شناسنامه',
|
|
||||||
content: item.nationalCode ?? 'نامشخص',
|
|
||||||
icon: Assets.vec.userSquareSvg.path,
|
|
||||||
),
|
|
||||||
itemList(
|
|
||||||
title: 'تاریخ تولد',
|
|
||||||
content: item.birthday?.toJalali.formatCompactDate() ?? 'نامشخص',
|
|
||||||
icon: Assets.vec.calendarSvg.path,
|
|
||||||
),
|
|
||||||
//todo
|
|
||||||
itemList(
|
|
||||||
title: 'استان',
|
|
||||||
content: item.province ?? 'نامشخص',
|
|
||||||
icon: Assets.vec.pictureFrameSvg.path,
|
|
||||||
),
|
|
||||||
itemList(
|
|
||||||
title: 'شهر',
|
|
||||||
content: item.city ?? 'نامشخص',
|
|
||||||
icon: Assets.vec.mapSvg.path,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
Padding(
|
||||||
)
|
padding: const EdgeInsets.symmetric(
|
||||||
: Row(
|
horizontal: 12.0,
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
vertical: 8.0,
|
||||||
children: [Icon(CupertinoIcons.chevron_down, color: AppColor.iconColor)],
|
),
|
||||||
),
|
child: Column(
|
||||||
),
|
children: [
|
||||||
|
itemList(
|
||||||
|
title: 'نام و نام خانوادگی',
|
||||||
|
content: item.fullname ?? 'نامشخص',
|
||||||
|
icon: Assets.vec.userSvg.path,
|
||||||
|
hasColoredBox: true,
|
||||||
|
),
|
||||||
|
itemList(
|
||||||
|
title: 'کدملی',
|
||||||
|
content: item.nationalId ?? 'نامشخص',
|
||||||
|
icon: Assets.vec.tagUserSvg.path,
|
||||||
|
),
|
||||||
|
itemList(
|
||||||
|
title: 'موبایل',
|
||||||
|
content: item.mobile ?? 'نامشخص',
|
||||||
|
icon: Assets.vec.callSvg.path,
|
||||||
|
),
|
||||||
|
|
||||||
|
itemList(
|
||||||
|
title: 'شماره شناسنامه',
|
||||||
|
content: item.nationalCode ?? 'نامشخص',
|
||||||
|
icon: Assets.vec.userSquareSvg.path,
|
||||||
|
),
|
||||||
|
itemList(
|
||||||
|
title: 'تاریخ تولد',
|
||||||
|
content:
|
||||||
|
item.birthday?.toJalali
|
||||||
|
.formatCompactDate() ??
|
||||||
|
'نامشخص',
|
||||||
|
icon: Assets.vec.calendarSvg.path,
|
||||||
|
),
|
||||||
|
//todo
|
||||||
|
itemList(
|
||||||
|
title: 'استان',
|
||||||
|
content: item.province ?? 'نامشخص',
|
||||||
|
icon: Assets.vec.pictureFrameSvg.path,
|
||||||
|
),
|
||||||
|
itemList(
|
||||||
|
title: 'شهر',
|
||||||
|
content: item.city ?? 'نامشخص',
|
||||||
|
icon: Assets.vec.mapSvg.path,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
CupertinoIcons.chevron_down,
|
||||||
|
color: AppColor.iconColor,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
controller.isUserInformationOpen,
|
controller.isUserInformationOpen,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ObxValue(
|
ObxValue(
|
||||||
(isOpen) =>
|
(isOpen) => AnimatedPositioned(
|
||||||
AnimatedPositioned(
|
right: 16,
|
||||||
right: 16,
|
top: isOpen.value ? -7 : 11,
|
||||||
top: isOpen.value ? -7 : 11,
|
duration: Duration(milliseconds: 500),
|
||||||
duration: Duration(milliseconds: 500),
|
child: Container(
|
||||||
child: Container(
|
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||||
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
decoration: isOpen.value
|
||||||
decoration: isOpen.value
|
? BoxDecoration(
|
||||||
? BoxDecoration(
|
color: Colors.white,
|
||||||
color: Colors.white,
|
borderRadius: BorderRadius.circular(8),
|
||||||
borderRadius: BorderRadius.circular(8),
|
border: Border.all(width: 0.5, color: Color(0xFFA9A9A9)),
|
||||||
border: Border.all(width: 0.5, color: Color(0xFFA9A9A9)),
|
)
|
||||||
)
|
: null,
|
||||||
: null,
|
child: Text(
|
||||||
child: Text(
|
'اطلاعات هویتی',
|
||||||
'اطلاعات هویتی',
|
style: AppFonts.yekan16.copyWith(color: AppColor.iconColor),
|
||||||
style: AppFonts.yekan16.copyWith(color: AppColor.iconColor),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
controller.isUserInformationOpen,
|
controller.isUserInformationOpen,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -342,118 +382,134 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
children: [
|
children: [
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: ObxValue(
|
child: ObxValue(
|
||||||
(val) =>
|
(val) => Container(
|
||||||
Container(
|
height: val.value ? 320.h : 47.h,
|
||||||
height: val.value ? 320.h : 47.h,
|
margin: EdgeInsets.symmetric(
|
||||||
margin: EdgeInsets.symmetric(horizontal: 8, vertical: val.value ? 12 : 0),
|
horizontal: 8,
|
||||||
padding: EdgeInsets.symmetric(horizontal: 11.h),
|
vertical: val.value ? 12 : 0,
|
||||||
decoration: BoxDecoration(
|
),
|
||||||
color: Colors.white,
|
padding: EdgeInsets.symmetric(horizontal: 11.h),
|
||||||
borderRadius: BorderRadius.circular(8),
|
decoration: BoxDecoration(
|
||||||
border: Border.all(width: 0.5, color: AppColor.darkGreyLight),
|
color: Colors.white,
|
||||||
),
|
borderRadius: BorderRadius.circular(8),
|
||||||
child: val.value
|
border: Border.all(width: 0.5, color: AppColor.darkGreyLight),
|
||||||
? Column(
|
),
|
||||||
children: [
|
child: val.value
|
||||||
SizedBox(height: 5.h),
|
? Column(
|
||||||
Row(
|
children: [
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
SizedBox(height: 5.h),
|
||||||
children: [
|
Row(
|
||||||
GestureDetector(
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
onTap: () {
|
|
||||||
Get.bottomSheet(
|
|
||||||
userInformationBottomSheet(),
|
|
||||||
isScrollControlled: true,
|
|
||||||
ignoreSafeArea: false,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: Assets.vec.editSvg.svg(
|
|
||||||
width: 24.w,
|
|
||||||
height: 24.h,
|
|
||||||
colorFilter: ColorFilter.mode(AppColor.blueNormal, BlendMode.srcIn),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0),
|
|
||||||
child: Column(
|
|
||||||
spacing: 2,
|
|
||||||
children: [
|
children: [
|
||||||
itemList(
|
GestureDetector(
|
||||||
title: 'نام صنفی',
|
onTap: () {
|
||||||
content: item.unitName ?? 'نامشخص',
|
Get.bottomSheet(
|
||||||
hasColoredBox: true,
|
userInformationBottomSheet(),
|
||||||
visible: item.unitName != null,
|
isScrollControlled: true,
|
||||||
|
ignoreSafeArea: false,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Assets.vec.editSvg.svg(
|
||||||
|
width: 24.w,
|
||||||
|
height: 24.h,
|
||||||
|
colorFilter: ColorFilter.mode(
|
||||||
|
AppColor.blueNormal,
|
||||||
|
BlendMode.srcIn,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
itemList(
|
|
||||||
title: 'شناسنامه ملی',
|
|
||||||
content: item.unitNationalId ?? 'نامشخص',
|
|
||||||
visible: item.unitName != null,
|
|
||||||
),
|
|
||||||
itemList(
|
|
||||||
title: 'شماره ثبت',
|
|
||||||
content: item.unitRegistrationNumber ?? 'نامشخص',
|
|
||||||
visible: item.unitName != null,
|
|
||||||
),
|
|
||||||
|
|
||||||
itemList(
|
|
||||||
title: 'کد اقتصادی',
|
|
||||||
content: item.unitEconomicalNumber ?? 'نامشخص',
|
|
||||||
visible: item.unitName != null,
|
|
||||||
),
|
|
||||||
itemList(
|
|
||||||
title: 'کد پستی',
|
|
||||||
content: item.unitPostalCode ?? 'نامشخص',
|
|
||||||
visible: item.unitName != null,
|
|
||||||
),
|
|
||||||
|
|
||||||
itemList(
|
|
||||||
title: 'استان',
|
|
||||||
content: item.province ?? 'نامشخص',
|
|
||||||
visible: item.unitName != null,
|
|
||||||
),
|
|
||||||
itemList(
|
|
||||||
title: 'شهر',
|
|
||||||
content: item.city ?? 'نامشخص',
|
|
||||||
visible: item.unitName != null,
|
|
||||||
),
|
|
||||||
itemList(title: 'آدرس', content: item.unitAddress ?? 'نامشخص'),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
Padding(
|
||||||
)
|
padding: const EdgeInsets.symmetric(
|
||||||
: Row(
|
horizontal: 12.0,
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
vertical: 8.0,
|
||||||
children: [Icon(CupertinoIcons.chevron_down, color: AppColor.iconColor)],
|
),
|
||||||
),
|
child: Column(
|
||||||
),
|
spacing: 2,
|
||||||
|
children: [
|
||||||
|
itemList(
|
||||||
|
title: 'نام صنفی',
|
||||||
|
content: item.unitName ?? 'نامشخص',
|
||||||
|
hasColoredBox: true,
|
||||||
|
visible: item.unitName != null,
|
||||||
|
),
|
||||||
|
itemList(
|
||||||
|
title: 'شناسنامه ملی',
|
||||||
|
content: item.unitNationalId ?? 'نامشخص',
|
||||||
|
visible: item.unitName != null,
|
||||||
|
),
|
||||||
|
itemList(
|
||||||
|
title: 'شماره ثبت',
|
||||||
|
content:
|
||||||
|
item.unitRegistrationNumber ?? 'نامشخص',
|
||||||
|
visible: item.unitName != null,
|
||||||
|
),
|
||||||
|
|
||||||
|
itemList(
|
||||||
|
title: 'کد اقتصادی',
|
||||||
|
content: item.unitEconomicalNumber ?? 'نامشخص',
|
||||||
|
visible: item.unitName != null,
|
||||||
|
),
|
||||||
|
itemList(
|
||||||
|
title: 'کد پستی',
|
||||||
|
content: item.unitPostalCode ?? 'نامشخص',
|
||||||
|
visible: item.unitName != null,
|
||||||
|
),
|
||||||
|
|
||||||
|
itemList(
|
||||||
|
title: 'استان',
|
||||||
|
content: item.province ?? 'نامشخص',
|
||||||
|
visible: item.unitName != null,
|
||||||
|
),
|
||||||
|
itemList(
|
||||||
|
title: 'شهر',
|
||||||
|
content: item.city ?? 'نامشخص',
|
||||||
|
visible: item.unitName != null,
|
||||||
|
),
|
||||||
|
itemList(
|
||||||
|
title: 'آدرس',
|
||||||
|
content: item.unitAddress ?? 'نامشخص',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
CupertinoIcons.chevron_down,
|
||||||
|
color: AppColor.iconColor,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
controller.isUnitInformationOpen,
|
controller.isUnitInformationOpen,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ObxValue(
|
ObxValue(
|
||||||
(isOpen) =>
|
(isOpen) => AnimatedPositioned(
|
||||||
AnimatedPositioned(
|
right: 16,
|
||||||
right: 16,
|
top: isOpen.value ? -2 : 11,
|
||||||
top: isOpen.value ? -2 : 11,
|
duration: Duration(milliseconds: 500),
|
||||||
duration: Duration(milliseconds: 500),
|
child: Container(
|
||||||
child: Container(
|
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||||
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
decoration: isOpen.value
|
||||||
decoration: isOpen.value
|
? BoxDecoration(
|
||||||
? BoxDecoration(
|
color: Colors.white,
|
||||||
color: Colors.white,
|
borderRadius: BorderRadius.circular(8),
|
||||||
borderRadius: BorderRadius.circular(8),
|
border: Border.all(width: 0.5, color: Color(0xFFA9A9A9)),
|
||||||
border: Border.all(width: 0.5, color: Color(0xFFA9A9A9)),
|
)
|
||||||
)
|
: null,
|
||||||
: null,
|
child: Text(
|
||||||
child: Text(
|
'اطلاعات صنفی',
|
||||||
'اطلاعات صنفی',
|
style: AppFonts.yekan16.copyWith(color: AppColor.iconColor),
|
||||||
style: AppFonts.yekan16.copyWith(color: AppColor.iconColor),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
controller.isUnitInformationOpen,
|
controller.isUnitInformationOpen,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -466,37 +522,45 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
String? icon,
|
String? icon,
|
||||||
bool hasColoredBox = false,
|
bool hasColoredBox = false,
|
||||||
bool? visible,
|
bool? visible,
|
||||||
}) =>
|
}) => Visibility(
|
||||||
Visibility(
|
visible: visible ?? true,
|
||||||
visible: visible ?? true,
|
child: Container(
|
||||||
child: Container(
|
padding: EdgeInsets.symmetric(horizontal: 12.h, vertical: 6.h),
|
||||||
padding: EdgeInsets.symmetric(horizontal: 12.h, vertical: 6.h),
|
decoration: BoxDecoration(
|
||||||
decoration: BoxDecoration(
|
color: hasColoredBox ? AppColor.greenLight : Colors.transparent,
|
||||||
color: hasColoredBox ? AppColor.greenLight : Colors.transparent,
|
borderRadius: BorderRadius.circular(8),
|
||||||
borderRadius: BorderRadius.circular(8),
|
border: hasColoredBox
|
||||||
border: hasColoredBox
|
? Border.all(width: 0.25, color: AppColor.bgDark)
|
||||||
? Border.all(width: 0.25, color: AppColor.bgDark)
|
: Border.all(width: 0, color: Colors.transparent),
|
||||||
: Border.all(width: 0, color: Colors.transparent),
|
),
|
||||||
),
|
child: Row(
|
||||||
child: Row(
|
spacing: 4,
|
||||||
spacing: 4,
|
children: [
|
||||||
children: [
|
if (icon != null)
|
||||||
if (icon != null)
|
Padding(
|
||||||
Padding(
|
padding: const EdgeInsets.only(left: 8.0),
|
||||||
padding: const EdgeInsets.only(left: 8.0),
|
child: SvgGenImage.vec(icon).svg(
|
||||||
child: SvgGenImage.vec(icon).svg(
|
width: 20.w,
|
||||||
width: 20.w,
|
height: 20.h,
|
||||||
height: 20.h,
|
colorFilter: ColorFilter.mode(
|
||||||
colorFilter: ColorFilter.mode(AppColor.textColor, BlendMode.srcIn),
|
AppColor.textColor,
|
||||||
),
|
BlendMode.srcIn,
|
||||||
),
|
),
|
||||||
Text(title, style: AppFonts.yekan14.copyWith(color: AppColor.textColor)),
|
),
|
||||||
Spacer(),
|
),
|
||||||
Text(content, style: AppFonts.yekan14.copyWith(color: AppColor.textColor)),
|
Text(
|
||||||
],
|
title,
|
||||||
|
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
|
||||||
),
|
),
|
||||||
),
|
Spacer(),
|
||||||
);
|
Text(
|
||||||
|
content,
|
||||||
|
style: AppFonts.yekan14.copyWith(color: AppColor.textColor),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
Widget cardActionWidget({
|
Widget cardActionWidget({
|
||||||
required String title,
|
required String title,
|
||||||
@@ -519,7 +583,9 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
padding: EdgeInsets.all(6),
|
padding: EdgeInsets.all(6),
|
||||||
decoration: ShapeDecoration(
|
decoration: ShapeDecoration(
|
||||||
color: cardColor ?? AppColor.blueLight,
|
color: cardColor ?? AppColor.blueLight,
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.all(4),
|
padding: EdgeInsets.all(4),
|
||||||
@@ -530,7 +596,8 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
child: SvgGenImage.vec(icon).svg(
|
child: SvgGenImage.vec(icon).svg(
|
||||||
width: 40.w,
|
width: 40.w,
|
||||||
height: 40.h,
|
height: 40.h,
|
||||||
colorFilter: color ?? ColorFilter.mode(Colors.white, BlendMode.srcIn),
|
colorFilter:
|
||||||
|
color ?? ColorFilter.mode(Colors.white, BlendMode.srcIn),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -554,7 +621,9 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'ویرایش اطلاعات هویتی',
|
'ویرایش اطلاعات هویتی',
|
||||||
style: AppFonts.yekan16Bold.copyWith(color: AppColor.darkGreyDarkHover),
|
style: AppFonts.yekan16Bold.copyWith(
|
||||||
|
color: AppColor.darkGreyDarkHover,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
Container(
|
Container(
|
||||||
@@ -626,7 +695,9 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'عکس پروفایل',
|
'عکس پروفایل',
|
||||||
style: AppFonts.yekan16Bold.copyWith(color: AppColor.blueNormal),
|
style: AppFonts.yekan16Bold.copyWith(
|
||||||
|
color: AppColor.blueNormal,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
ObxValue((data) {
|
ObxValue((data) {
|
||||||
return Container(
|
return Container(
|
||||||
@@ -635,17 +706,29 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: AppColor.lightGreyNormal,
|
color: AppColor.lightGreyNormal,
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
border: Border.all(width: 1, color: AppColor.blackLight),
|
border: Border.all(
|
||||||
|
width: 1,
|
||||||
|
color: AppColor.blackLight,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: data.value == null
|
child: data.value == null
|
||||||
? Padding(
|
? Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(30, 10, 10, 30),
|
padding: const EdgeInsets.fromLTRB(
|
||||||
child: Image.network(
|
30,
|
||||||
controller.userProfile.value.data?.image ?? '',
|
10,
|
||||||
),
|
10,
|
||||||
)
|
30,
|
||||||
: Image.file(File(data.value!.path), fit: BoxFit.cover),
|
),
|
||||||
|
child: Image.network(
|
||||||
|
controller.userProfile.value.data?.image ??
|
||||||
|
'',
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Image.file(
|
||||||
|
File(data.value!.path),
|
||||||
|
fit: BoxFit.cover,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}, controller.selectedImage),
|
}, controller.selectedImage),
|
||||||
@@ -658,14 +741,18 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
text: 'گالری',
|
text: 'گالری',
|
||||||
width: 150.w,
|
width: 150.w,
|
||||||
height: 40.h,
|
height: 40.h,
|
||||||
textStyle: AppFonts.yekan20.copyWith(color: Colors.white),
|
textStyle: AppFonts.yekan20.copyWith(
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
controller.selectedImage.value = await controller.imagePicker.pickImage(
|
controller.selectedImage.value = await controller
|
||||||
source: ImageSource.gallery,
|
.imagePicker
|
||||||
imageQuality: 60,
|
.pickImage(
|
||||||
maxWidth: 1080,
|
source: ImageSource.gallery,
|
||||||
maxHeight: 720,
|
imageQuality: 60,
|
||||||
);
|
maxWidth: 1080,
|
||||||
|
maxHeight: 720,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
SizedBox(width: 16),
|
SizedBox(width: 16),
|
||||||
@@ -673,14 +760,18 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
text: 'دوربین',
|
text: 'دوربین',
|
||||||
width: 150.w,
|
width: 150.w,
|
||||||
height: 40.h,
|
height: 40.h,
|
||||||
textStyle: AppFonts.yekan20.copyWith(color: AppColor.blueNormal),
|
textStyle: AppFonts.yekan20.copyWith(
|
||||||
|
color: AppColor.blueNormal,
|
||||||
|
),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
controller.selectedImage.value = await controller.imagePicker.pickImage(
|
controller.selectedImage.value = await controller
|
||||||
source: ImageSource.camera,
|
.imagePicker
|
||||||
imageQuality: 60,
|
.pickImage(
|
||||||
maxWidth: 1080,
|
source: ImageSource.camera,
|
||||||
maxHeight: 720,
|
imageQuality: 60,
|
||||||
);
|
maxWidth: 1080,
|
||||||
|
maxHeight: 720,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -731,7 +822,9 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'تغییر رمز عبور',
|
'تغییر رمز عبور',
|
||||||
style: AppFonts.yekan16Bold.copyWith(color: AppColor.darkGreyDarkHover),
|
style: AppFonts.yekan16Bold.copyWith(
|
||||||
|
color: AppColor.darkGreyDarkHover,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
SizedBox(),
|
SizedBox(),
|
||||||
RTextField(
|
RTextField(
|
||||||
@@ -743,7 +836,8 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
return 'رمز عبور را وارد کنید';
|
return 'رمز عبور را وارد کنید';
|
||||||
} else if (controller.userProfile.value.data?.password != value) {
|
} else if (controller.userProfile.value.data?.password !=
|
||||||
|
value) {
|
||||||
return 'رمز عبور صحیح نیست';
|
return 'رمز عبور صحیح نیست';
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@@ -827,7 +921,10 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
spacing: 8,
|
spacing: 8,
|
||||||
children: [
|
children: [
|
||||||
Text('خروج', style: AppFonts.yekan16Bold.copyWith(color: AppColor.error)),
|
Text(
|
||||||
|
'خروج',
|
||||||
|
style: AppFonts.yekan16Bold.copyWith(color: AppColor.error),
|
||||||
|
),
|
||||||
SizedBox(),
|
SizedBox(),
|
||||||
Text(
|
Text(
|
||||||
'آیا مطمئن هستید که میخواهید از حساب کاربری خود خارج شوید؟',
|
'آیا مطمئن هستید که میخواهید از حساب کاربری خود خارج شوید؟',
|
||||||
@@ -847,7 +944,9 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
backgroundColor: AppColor.error,
|
backgroundColor: AppColor.error,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await Future.wait([
|
await Future.wait([
|
||||||
controller.tokenService.deleteModuleTokens(Module.chicken),
|
controller.tokenService.deleteModuleTokens(
|
||||||
|
Module.chicken,
|
||||||
|
),
|
||||||
controller.gService.clearSelectedModule(),
|
controller.gService.clearSelectedModule(),
|
||||||
]).then((value) async {
|
]).then((value) async {
|
||||||
await removeChickenDI();
|
await removeChickenDI();
|
||||||
@@ -890,7 +989,9 @@ class ProfilePage extends GetView<ProfileLogic> {
|
|||||||
children: List.generate(item?.length ?? 0, (index) {
|
children: List.generate(item?.length ?? 0, (index) {
|
||||||
Map tmpRole = getFaUserRoleWithOnTap(item?[index]);
|
Map tmpRole = getFaUserRoleWithOnTap(item?[index]);
|
||||||
return CustomChip(
|
return CustomChip(
|
||||||
isSelected: controller.gService.getRoute(Module.chicken) == tmpRole.values.first,
|
isSelected:
|
||||||
|
controller.gService.getRoute(Module.chicken) ==
|
||||||
|
tmpRole.values.first,
|
||||||
title: tmpRole.keys.first,
|
title: tmpRole.keys.first,
|
||||||
index: index,
|
index: index,
|
||||||
onTap: (int p1) {
|
onTap: (int p1) {
|
||||||
|
|||||||
130
packages/chicken/test/README.md
Normal file
130
packages/chicken/test/README.md
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
# Chicken Package Test Suite
|
||||||
|
|
||||||
|
This directory contains comprehensive unit tests and integration tests for the chicken package.
|
||||||
|
|
||||||
|
## Test Structure
|
||||||
|
|
||||||
|
### Unit Tests
|
||||||
|
|
||||||
|
#### Authentication Tests
|
||||||
|
- `data/repositories/auth/auth_repository_imp_test.dart` - Tests for AuthRepository implementation
|
||||||
|
- `data/data_source/remote/auth/auth_remote_imp_test.dart` - Tests for AuthRemoteDataSource implementation
|
||||||
|
|
||||||
|
#### Repository Tests
|
||||||
|
- `data/repositories/chicken/chicken_repository_imp_test.dart` - Tests for ChickenRepository implementation
|
||||||
|
|
||||||
|
#### Local Data Source Tests
|
||||||
|
- `data/data_source/local/chicken_local_imp_test.dart` - Tests for local data source implementation
|
||||||
|
|
||||||
|
#### Model Tests
|
||||||
|
- `data/models/response/user_profile_model/user_profile_model_test.dart` - Tests for UserProfileModel
|
||||||
|
|
||||||
|
#### Utility Tests
|
||||||
|
- `presentation/utils/string_utils_test.dart` - Tests for string utility functions
|
||||||
|
|
||||||
|
### Integration Tests
|
||||||
|
|
||||||
|
#### Authentication Flow
|
||||||
|
- `integration/auth_flow_integration_test.dart` - Complete authentication workflow tests
|
||||||
|
|
||||||
|
#### Steward Workflow
|
||||||
|
- `integration/steward_workflow_integration_test.dart` - Steward business logic integration tests
|
||||||
|
|
||||||
|
#### Poultry Science
|
||||||
|
- `integration/poultry_science_integration_test.dart` - Poultry science module integration tests
|
||||||
|
|
||||||
|
## Running Tests
|
||||||
|
|
||||||
|
### Run All Tests
|
||||||
|
```bash
|
||||||
|
flutter test
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run Specific Test Categories
|
||||||
|
```bash
|
||||||
|
# Run unit tests only
|
||||||
|
flutter test test/data/
|
||||||
|
|
||||||
|
# Run integration tests only
|
||||||
|
flutter test test/integration/
|
||||||
|
|
||||||
|
# Run specific test file
|
||||||
|
flutter test test/data/repositories/auth/auth_repository_imp_test.dart
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run Tests with Coverage
|
||||||
|
```bash
|
||||||
|
flutter test --coverage
|
||||||
|
```
|
||||||
|
|
||||||
|
## Test Coverage
|
||||||
|
|
||||||
|
The test suite covers:
|
||||||
|
|
||||||
|
1. **Authentication Components**
|
||||||
|
- Login/logout functionality
|
||||||
|
- User info management
|
||||||
|
- Token handling
|
||||||
|
- Authentication state management
|
||||||
|
|
||||||
|
2. **Repository Layer**
|
||||||
|
- Data source interactions
|
||||||
|
- Error handling
|
||||||
|
- Data transformation
|
||||||
|
- Caching mechanisms
|
||||||
|
|
||||||
|
3. **Local Storage**
|
||||||
|
- Data persistence
|
||||||
|
- Cache management
|
||||||
|
- Offline functionality
|
||||||
|
|
||||||
|
4. **Business Logic**
|
||||||
|
- Steward workflows
|
||||||
|
- Poultry science operations
|
||||||
|
- Data validation
|
||||||
|
- Business rule enforcement
|
||||||
|
|
||||||
|
5. **Integration Flows**
|
||||||
|
- End-to-end user journeys
|
||||||
|
- Cross-module interactions
|
||||||
|
- Error propagation
|
||||||
|
- Performance scenarios
|
||||||
|
|
||||||
|
## Test Data
|
||||||
|
|
||||||
|
Tests use mock data and mock objects to ensure:
|
||||||
|
- Fast execution
|
||||||
|
- Deterministic results
|
||||||
|
- Isolation from external dependencies
|
||||||
|
- Easy maintenance
|
||||||
|
|
||||||
|
## Mocking Strategy
|
||||||
|
|
||||||
|
- **Mocktail** is used for creating mock objects
|
||||||
|
- **Mock data** is used for consistent test scenarios
|
||||||
|
- **Fake implementations** are used for complex dependencies
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **Test Naming**: Use descriptive test names that explain the scenario
|
||||||
|
2. **Arrange-Act-Assert**: Follow the AAA pattern for test structure
|
||||||
|
3. **Single Responsibility**: Each test should verify one specific behavior
|
||||||
|
4. **Independent Tests**: Tests should not depend on each other
|
||||||
|
5. **Clean Setup**: Use setUp/tearDown methods for test preparation
|
||||||
|
|
||||||
|
## Continuous Integration
|
||||||
|
|
||||||
|
Tests are designed to run in CI/CD pipelines with:
|
||||||
|
- Fast execution times
|
||||||
|
- No external dependencies
|
||||||
|
- Deterministic results
|
||||||
|
- Clear failure reporting
|
||||||
|
|
||||||
|
## Maintenance
|
||||||
|
|
||||||
|
When adding new features:
|
||||||
|
1. Write unit tests for new components
|
||||||
|
2. Add integration tests for new workflows
|
||||||
|
3. Update existing tests if interfaces change
|
||||||
|
4. Ensure test coverage remains high
|
||||||
|
5. Document any new test patterns
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/data_source/local/chicken_local_imp.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/local/widely_used_local_model.dart';
|
||||||
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
|
class MockHiveLocalStorage extends Mock implements HiveLocalStorage {}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
late ChickenLocalDataSourceImp chickenLocalDataSource;
|
||||||
|
late MockHiveLocalStorage mockHiveLocalStorage;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
mockHiveLocalStorage = MockHiveLocalStorage();
|
||||||
|
|
||||||
|
// Register the mock in GetIt for dependency injection
|
||||||
|
if (diCore.isRegistered<HiveLocalStorage>()) {
|
||||||
|
diCore.unregister<HiveLocalStorage>();
|
||||||
|
}
|
||||||
|
diCore.registerSingleton<HiveLocalStorage>(mockHiveLocalStorage);
|
||||||
|
|
||||||
|
chickenLocalDataSource = ChickenLocalDataSourceImp();
|
||||||
|
});
|
||||||
|
|
||||||
|
tearDown(() {
|
||||||
|
// Clean up GetIt registration
|
||||||
|
if (diCore.isRegistered<HiveLocalStorage>()) {
|
||||||
|
diCore.unregister<HiveLocalStorage>();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
group('ChickenLocalDataSourceImp', () {
|
||||||
|
group('openBox', () {
|
||||||
|
test('should call local openBox with correct box name', () async {
|
||||||
|
// Arrange
|
||||||
|
when(
|
||||||
|
() => mockHiveLocalStorage.openBox<WidelyUsedLocalModel>(
|
||||||
|
'Chicken_Widley_Box',
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async {});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await chickenLocalDataSource.openBox();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verify(
|
||||||
|
() => mockHiveLocalStorage.openBox<WidelyUsedLocalModel>(
|
||||||
|
'Chicken_Widley_Box',
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('initWidleyUsed', () {
|
||||||
|
test('should initialize widely used items', () async {
|
||||||
|
// Act
|
||||||
|
await chickenLocalDataSource.initWidleyUsed();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
// This method currently doesn't interact with the mock, but we can verify it completes
|
||||||
|
expect(chickenLocalDataSource.initWidleyUsed, isA<Function>());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('getAllWidely', () {
|
||||||
|
test('should return first widely used model when data exists', () async {
|
||||||
|
// Arrange
|
||||||
|
final expectedModel = WidelyUsedLocalModel(hasInit: true, items: []);
|
||||||
|
final mockData = [expectedModel];
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockHiveLocalStorage.readBox<WidelyUsedLocalModel>(
|
||||||
|
boxName: 'Chicken_Widley_Box',
|
||||||
|
),
|
||||||
|
).thenReturn(mockData);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = chickenLocalDataSource.getAllWidely();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, equals(expectedModel));
|
||||||
|
verify(
|
||||||
|
() => mockHiveLocalStorage.readBox<WidelyUsedLocalModel>(
|
||||||
|
boxName: 'Chicken_Widley_Box',
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return null when no data exists', () async {
|
||||||
|
// Arrange
|
||||||
|
when(
|
||||||
|
() => mockHiveLocalStorage.readBox<WidelyUsedLocalModel>(
|
||||||
|
boxName: 'Chicken_Widley_Box',
|
||||||
|
),
|
||||||
|
).thenReturn(null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = chickenLocalDataSource.getAllWidely();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, isNull);
|
||||||
|
verify(
|
||||||
|
() => mockHiveLocalStorage.readBox<WidelyUsedLocalModel>(
|
||||||
|
boxName: 'Chicken_Widley_Box',
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return null when empty list is returned', () async {
|
||||||
|
// Arrange
|
||||||
|
when(
|
||||||
|
() => mockHiveLocalStorage.readBox<WidelyUsedLocalModel>(
|
||||||
|
boxName: 'Chicken_Widley_Box',
|
||||||
|
),
|
||||||
|
).thenReturn([]);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = chickenLocalDataSource.getAllWidely();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, isNull);
|
||||||
|
verify(
|
||||||
|
() => mockHiveLocalStorage.readBox<WidelyUsedLocalModel>(
|
||||||
|
boxName: 'Chicken_Widley_Box',
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return first item when multiple items exist', () async {
|
||||||
|
// Arrange
|
||||||
|
final firstModel = WidelyUsedLocalModel(hasInit: true, items: []);
|
||||||
|
final secondModel = WidelyUsedLocalModel(hasInit: false, items: []);
|
||||||
|
final mockData = [firstModel, secondModel];
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockHiveLocalStorage.readBox<WidelyUsedLocalModel>(
|
||||||
|
boxName: 'Chicken_Widley_Box',
|
||||||
|
),
|
||||||
|
).thenReturn(mockData);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = chickenLocalDataSource.getAllWidely();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, equals(firstModel));
|
||||||
|
verify(
|
||||||
|
() => mockHiveLocalStorage.readBox<WidelyUsedLocalModel>(
|
||||||
|
boxName: 'Chicken_Widley_Box',
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('boxName', () {
|
||||||
|
test('should have correct box name', () {
|
||||||
|
// Assert
|
||||||
|
expect(chickenLocalDataSource.boxName, equals('Chicken_Widley_Box'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,350 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/data_source/remote/auth/auth_remote_imp.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/user_info/user_info_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/user_profile_model/user_profile_model.dart';
|
||||||
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
|
||||||
|
class MockDioRemote extends Mock implements DioRemote {}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
late AuthRemoteDataSourceImp authRemoteDataSource;
|
||||||
|
late MockDioRemote mockDioRemote;
|
||||||
|
|
||||||
|
setUpAll(() {
|
||||||
|
registerFallbackValue(<String, dynamic>{});
|
||||||
|
registerFallbackValue(<String, String>{});
|
||||||
|
});
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
mockDioRemote = MockDioRemote();
|
||||||
|
authRemoteDataSource = AuthRemoteDataSourceImp(mockDioRemote);
|
||||||
|
});
|
||||||
|
|
||||||
|
group('AuthRemoteDataSourceImp', () {
|
||||||
|
group('login', () {
|
||||||
|
test('should return UserProfileModel when login is successful', () async {
|
||||||
|
// Arrange
|
||||||
|
final authRequest = {
|
||||||
|
'username': 'test@example.com',
|
||||||
|
'password': 'password',
|
||||||
|
};
|
||||||
|
final expectedUserProfile = UserProfileModel(
|
||||||
|
accessToken: 'test-access-token',
|
||||||
|
expiresIn: '3600',
|
||||||
|
scope: 'read write',
|
||||||
|
expireTime: '2024-12-31T23:59:59Z',
|
||||||
|
mobile: '09123456789',
|
||||||
|
fullname: 'John Doe',
|
||||||
|
firstname: 'John',
|
||||||
|
lastname: 'Doe',
|
||||||
|
city: 'Tehran',
|
||||||
|
province: 'Tehran',
|
||||||
|
nationalCode: '1234567890',
|
||||||
|
nationalId: '1234567890',
|
||||||
|
);
|
||||||
|
|
||||||
|
final mockResponse = DioResponse<UserProfileModel?>(
|
||||||
|
Response(
|
||||||
|
data: expectedUserProfile,
|
||||||
|
statusCode: 200,
|
||||||
|
requestOptions: RequestOptions(path: '/api/login/'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockDioRemote.post<UserProfileModel?>(
|
||||||
|
'/api/login/',
|
||||||
|
data: authRequest,
|
||||||
|
fromJson: any(named: 'fromJson'),
|
||||||
|
headers: any(named: 'headers'),
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => mockResponse);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = await authRemoteDataSource.login(
|
||||||
|
authRequest: authRequest,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, equals(expectedUserProfile));
|
||||||
|
verify(
|
||||||
|
() => mockDioRemote.post<UserProfileModel?>(
|
||||||
|
'/api/login/',
|
||||||
|
data: authRequest,
|
||||||
|
fromJson: UserProfileModel.fromJson,
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return null when login fails', () async {
|
||||||
|
// Arrange
|
||||||
|
final authRequest = {
|
||||||
|
'username': 'test@example.com',
|
||||||
|
'password': 'wrong',
|
||||||
|
};
|
||||||
|
|
||||||
|
final mockResponse = DioResponse<UserProfileModel?>(
|
||||||
|
Response(
|
||||||
|
data: null,
|
||||||
|
statusCode: 401,
|
||||||
|
requestOptions: RequestOptions(path: '/api/login/'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockDioRemote.post<UserProfileModel?>(
|
||||||
|
'/api/login/',
|
||||||
|
data: authRequest,
|
||||||
|
fromJson: any(named: 'fromJson'),
|
||||||
|
headers: any(named: 'headers'),
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => mockResponse);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = await authRemoteDataSource.login(
|
||||||
|
authRequest: authRequest,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, isNull);
|
||||||
|
verify(
|
||||||
|
() => mockDioRemote.post<UserProfileModel?>(
|
||||||
|
'/api/login/',
|
||||||
|
data: authRequest,
|
||||||
|
fromJson: UserProfileModel.fromJson,
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('hasAuthenticated', () {
|
||||||
|
test('should return true when user is authenticated', () async {
|
||||||
|
// Arrange
|
||||||
|
final mockResponse = DioResponse<bool>(
|
||||||
|
Response(
|
||||||
|
data: true,
|
||||||
|
statusCode: 200,
|
||||||
|
requestOptions: RequestOptions(path: 'auth/api/v1/login/'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockDioRemote.get<bool>(
|
||||||
|
'auth/api/v1/login/',
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => mockResponse);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = await authRemoteDataSource.hasAuthenticated();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, isTrue);
|
||||||
|
verify(
|
||||||
|
() => mockDioRemote.get<bool>(
|
||||||
|
'auth/api/v1/login/',
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return false when user is not authenticated', () async {
|
||||||
|
// Arrange
|
||||||
|
final mockResponse = DioResponse<bool>(
|
||||||
|
Response(
|
||||||
|
data: false,
|
||||||
|
statusCode: 401,
|
||||||
|
requestOptions: RequestOptions(path: 'auth/api/v1/login/'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockDioRemote.get<bool>(
|
||||||
|
'auth/api/v1/login/',
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => mockResponse);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = await authRemoteDataSource.hasAuthenticated();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, isFalse);
|
||||||
|
verify(
|
||||||
|
() => mockDioRemote.get<bool>(
|
||||||
|
'auth/api/v1/login/',
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return false when response data is null', () async {
|
||||||
|
// Arrange
|
||||||
|
final mockResponse = DioResponse<bool>(
|
||||||
|
Response(
|
||||||
|
data: null,
|
||||||
|
statusCode: 200,
|
||||||
|
requestOptions: RequestOptions(path: 'auth/api/v1/login/'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockDioRemote.get<bool>(
|
||||||
|
'auth/api/v1/login/',
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => mockResponse);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = await authRemoteDataSource.hasAuthenticated();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, isFalse);
|
||||||
|
verify(
|
||||||
|
() => mockDioRemote.get<bool>(
|
||||||
|
'auth/api/v1/login/',
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('getUserInfo', () {
|
||||||
|
test('should return UserInfoModel when user info is found', () async {
|
||||||
|
// Arrange
|
||||||
|
const phoneNumber = '09123456789';
|
||||||
|
final expectedUserInfo = UserInfoModel(
|
||||||
|
isUser: true,
|
||||||
|
address: 'Test Address',
|
||||||
|
backend: 'test-backend',
|
||||||
|
apiKey: 'test-api-key',
|
||||||
|
);
|
||||||
|
|
||||||
|
final mockResponse = DioResponse<UserInfoModel?>(
|
||||||
|
Response(
|
||||||
|
data: expectedUserInfo,
|
||||||
|
statusCode: 200,
|
||||||
|
requestOptions: RequestOptions(
|
||||||
|
path: 'https://userbackend.rasadyaar.ir/api/send_otp/',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockDioRemote.post<UserInfoModel?>(
|
||||||
|
'https://userbackend.rasadyaar.ir/api/send_otp/',
|
||||||
|
data: {"mobile": phoneNumber, "state": ""},
|
||||||
|
fromJson: any(named: 'fromJson'),
|
||||||
|
headers: any(named: 'headers'),
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => mockResponse);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = await authRemoteDataSource.getUserInfo(phoneNumber);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, equals(expectedUserInfo));
|
||||||
|
verify(
|
||||||
|
() => mockDioRemote.post<UserInfoModel?>(
|
||||||
|
'https://userbackend.rasadyaar.ir/api/send_otp/',
|
||||||
|
data: {"mobile": phoneNumber, "state": ""},
|
||||||
|
fromJson: UserInfoModel.fromJson,
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return null when user info is not found', () async {
|
||||||
|
// Arrange
|
||||||
|
const phoneNumber = '09123456789';
|
||||||
|
|
||||||
|
final mockResponse = DioResponse<UserInfoModel?>(
|
||||||
|
Response(
|
||||||
|
data: null,
|
||||||
|
statusCode: 404,
|
||||||
|
requestOptions: RequestOptions(
|
||||||
|
path: 'https://userbackend.rasadyaar.ir/api/send_otp/',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockDioRemote.post<UserInfoModel?>(
|
||||||
|
'https://userbackend.rasadyaar.ir/api/send_otp/',
|
||||||
|
data: {"mobile": phoneNumber, "state": ""},
|
||||||
|
fromJson: any(named: 'fromJson'),
|
||||||
|
headers: any(named: 'headers'),
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => mockResponse);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = await authRemoteDataSource.getUserInfo(phoneNumber);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, isNull);
|
||||||
|
verify(
|
||||||
|
() => mockDioRemote.post<UserInfoModel?>(
|
||||||
|
'https://userbackend.rasadyaar.ir/api/send_otp/',
|
||||||
|
data: {"mobile": phoneNumber, "state": ""},
|
||||||
|
fromJson: UserInfoModel.fromJson,
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('submitUserInfo', () {
|
||||||
|
test(
|
||||||
|
'should call remote submitUserInfo with correct parameters',
|
||||||
|
() async {
|
||||||
|
// Arrange
|
||||||
|
final userInfo = {
|
||||||
|
'mobile': '09123456789',
|
||||||
|
'device_name': 'Test Device',
|
||||||
|
};
|
||||||
|
|
||||||
|
final mockResponse = DioResponse<dynamic>(
|
||||||
|
Response(
|
||||||
|
data: null,
|
||||||
|
statusCode: 200,
|
||||||
|
requestOptions: RequestOptions(path: '/steward-app-login/'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
when(
|
||||||
|
() => mockDioRemote.post(
|
||||||
|
'/steward-app-login/',
|
||||||
|
data: userInfo,
|
||||||
|
headers: any(named: 'headers'),
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => mockResponse);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await authRemoteDataSource.submitUserInfo(userInfo);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verify(
|
||||||
|
() => mockDioRemote.post(
|
||||||
|
'/steward-app-login/',
|
||||||
|
data: userInfo,
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
group('logout', () {
|
||||||
|
test('should throw UnimplementedError', () async {
|
||||||
|
// Act & Assert
|
||||||
|
expect(
|
||||||
|
() => authRemoteDataSource.logout(),
|
||||||
|
throwsA(isA<UnimplementedError>()),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -4,10 +4,26 @@ import 'package:rasadyar_chicken/data/di/chicken_di.dart';
|
|||||||
import 'package:rasadyar_core/core.dart';
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
setUpAll(() {
|
||||||
|
// Mock platform services for testing
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
});
|
||||||
|
|
||||||
setUp(() async {
|
setUp(() async {
|
||||||
await setupAllCoreProvider();
|
// Skip platform-dependent setup for unit tests
|
||||||
Get.put(TokenStorageService());
|
try {
|
||||||
await setupChickenDI();
|
await setupAllCoreProvider();
|
||||||
|
Get.put(TokenStorageService());
|
||||||
|
await setupChickenDI();
|
||||||
|
} catch (e) {
|
||||||
|
// Mock the setup for testing - just register the service manually
|
||||||
|
print('Mocking platform services for testing: $e');
|
||||||
|
if (!diChicken.isRegistered<DioErrorHandler>()) {
|
||||||
|
diChicken.registerLazySingleton<DioErrorHandler>(
|
||||||
|
() => DioErrorHandler(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
group('Check class type registered', () {
|
group('Check class type registered', () {
|
||||||
|
|||||||
@@ -0,0 +1,158 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/user_profile_model/user_profile_model.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('UserProfileModel', () {
|
||||||
|
test('should create UserProfileModel with all properties', () {
|
||||||
|
// Arrange & Act
|
||||||
|
final userProfile = UserProfileModel(
|
||||||
|
accessToken: 'test-access-token',
|
||||||
|
expiresIn: '3600',
|
||||||
|
scope: 'read write',
|
||||||
|
expireTime: '2024-12-31T23:59:59Z',
|
||||||
|
mobile: '09123456789',
|
||||||
|
fullname: 'John Doe',
|
||||||
|
firstname: 'John',
|
||||||
|
lastname: 'Doe',
|
||||||
|
city: 'Tehran',
|
||||||
|
province: 'Tehran',
|
||||||
|
nationalCode: '1234567890',
|
||||||
|
nationalId: '1234567890',
|
||||||
|
birthday: '1990-01-01',
|
||||||
|
image: 'https://example.com/image.jpg',
|
||||||
|
baseOrder: 1,
|
||||||
|
role: ['admin', 'user'],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(userProfile.accessToken, equals('test-access-token'));
|
||||||
|
expect(userProfile.expiresIn, equals('3600'));
|
||||||
|
expect(userProfile.scope, equals('read write'));
|
||||||
|
expect(userProfile.expireTime, equals('2024-12-31T23:59:59Z'));
|
||||||
|
expect(userProfile.mobile, equals('09123456789'));
|
||||||
|
expect(userProfile.fullname, equals('John Doe'));
|
||||||
|
expect(userProfile.firstname, equals('John'));
|
||||||
|
expect(userProfile.lastname, equals('Doe'));
|
||||||
|
expect(userProfile.city, equals('Tehran'));
|
||||||
|
expect(userProfile.province, equals('Tehran'));
|
||||||
|
expect(userProfile.nationalCode, equals('1234567890'));
|
||||||
|
expect(userProfile.nationalId, equals('1234567890'));
|
||||||
|
expect(userProfile.birthday, equals('1990-01-01'));
|
||||||
|
expect(userProfile.image, equals('https://example.com/image.jpg'));
|
||||||
|
expect(userProfile.baseOrder, equals(1));
|
||||||
|
expect(userProfile.role, equals(['admin', 'user']));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should create UserProfileModel with minimal properties', () {
|
||||||
|
// Arrange & Act
|
||||||
|
const userProfile = UserProfileModel();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(userProfile.accessToken, isNull);
|
||||||
|
expect(userProfile.expiresIn, isNull);
|
||||||
|
expect(userProfile.scope, isNull);
|
||||||
|
expect(userProfile.expireTime, isNull);
|
||||||
|
expect(userProfile.mobile, isNull);
|
||||||
|
expect(userProfile.fullname, isNull);
|
||||||
|
expect(userProfile.firstname, isNull);
|
||||||
|
expect(userProfile.lastname, isNull);
|
||||||
|
expect(userProfile.city, isNull);
|
||||||
|
expect(userProfile.province, isNull);
|
||||||
|
expect(userProfile.nationalCode, isNull);
|
||||||
|
expect(userProfile.nationalId, isNull);
|
||||||
|
expect(userProfile.birthday, isNull);
|
||||||
|
expect(userProfile.image, isNull);
|
||||||
|
expect(userProfile.baseOrder, isNull);
|
||||||
|
expect(userProfile.role, isNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should create UserProfileModel with partial properties', () {
|
||||||
|
// Arrange & Act
|
||||||
|
final userProfile = UserProfileModel(
|
||||||
|
mobile: '09123456789',
|
||||||
|
firstname: 'John',
|
||||||
|
lastname: 'Doe',
|
||||||
|
role: ['user'],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(userProfile.accessToken, isNull);
|
||||||
|
expect(userProfile.mobile, equals('09123456789'));
|
||||||
|
expect(userProfile.firstname, equals('John'));
|
||||||
|
expect(userProfile.lastname, equals('Doe'));
|
||||||
|
expect(userProfile.role, equals(['user']));
|
||||||
|
expect(userProfile.city, isNull);
|
||||||
|
expect(userProfile.province, isNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should support equality comparison', () {
|
||||||
|
// Arrange
|
||||||
|
final userProfile1 = UserProfileModel(
|
||||||
|
mobile: '09123456789',
|
||||||
|
firstname: 'John',
|
||||||
|
lastname: 'Doe',
|
||||||
|
role: ['user'],
|
||||||
|
);
|
||||||
|
|
||||||
|
final userProfile2 = UserProfileModel(
|
||||||
|
mobile: '09123456789',
|
||||||
|
firstname: 'John',
|
||||||
|
lastname: 'Doe',
|
||||||
|
role: ['user'],
|
||||||
|
);
|
||||||
|
|
||||||
|
final userProfile3 = UserProfileModel(
|
||||||
|
mobile: '09123456789',
|
||||||
|
firstname: 'Jane',
|
||||||
|
lastname: 'Doe',
|
||||||
|
role: ['user'],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(userProfile1, equals(userProfile2));
|
||||||
|
expect(userProfile1, isNot(equals(userProfile3)));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should support copyWith method', () {
|
||||||
|
// Arrange
|
||||||
|
final originalProfile = UserProfileModel(
|
||||||
|
mobile: '09123456789',
|
||||||
|
firstname: 'John',
|
||||||
|
lastname: 'Doe',
|
||||||
|
role: ['user'],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final updatedProfile = originalProfile.copyWith(
|
||||||
|
firstname: 'Jane',
|
||||||
|
city: 'Tehran',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(updatedProfile.mobile, equals('09123456789'));
|
||||||
|
expect(updatedProfile.firstname, equals('Jane'));
|
||||||
|
expect(updatedProfile.lastname, equals('Doe'));
|
||||||
|
expect(updatedProfile.city, equals('Tehran'));
|
||||||
|
expect(updatedProfile.role, equals(['user']));
|
||||||
|
expect(updatedProfile.province, isNull);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should support toString method', () {
|
||||||
|
// Arrange
|
||||||
|
final userProfile = UserProfileModel(
|
||||||
|
mobile: '09123456789',
|
||||||
|
firstname: 'John',
|
||||||
|
lastname: 'Doe',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final stringRepresentation = userProfile.toString();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(stringRepresentation, contains('UserProfileModel'));
|
||||||
|
expect(stringRepresentation, contains('mobile: 09123456789'));
|
||||||
|
expect(stringRepresentation, contains('firstname: John'));
|
||||||
|
expect(stringRepresentation, contains('lastname: Doe'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/data_source/remote/auth/auth_remote.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/user_info/user_info_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/user_profile_model/user_profile_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/repositories/auth/auth_repository_imp.dart';
|
||||||
|
|
||||||
|
class MockAuthRemoteDataSource extends Mock implements AuthRemoteDataSource {}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
late AuthRepositoryImpl authRepository;
|
||||||
|
late MockAuthRemoteDataSource mockAuthRemote;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
mockAuthRemote = MockAuthRemoteDataSource();
|
||||||
|
authRepository = AuthRepositoryImpl(mockAuthRemote);
|
||||||
|
});
|
||||||
|
|
||||||
|
group('AuthRepositoryImpl', () {
|
||||||
|
group('login', () {
|
||||||
|
test('should return UserProfileModel when login is successful', () async {
|
||||||
|
// Arrange
|
||||||
|
final authRequest = {
|
||||||
|
'username': 'test@example.com',
|
||||||
|
'password': 'password',
|
||||||
|
};
|
||||||
|
final expectedUserProfile = UserProfileModel(
|
||||||
|
accessToken: 'test-access-token',
|
||||||
|
firstname: 'John',
|
||||||
|
lastname: 'Doe',
|
||||||
|
mobile: '09123456789',
|
||||||
|
);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.login(authRequest: authRequest),
|
||||||
|
).thenAnswer((_) async => expectedUserProfile);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = await authRepository.login(authRequest: authRequest);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, equals(expectedUserProfile));
|
||||||
|
verify(() => mockAuthRemote.login(authRequest: authRequest)).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return null when login fails', () async {
|
||||||
|
// Arrange
|
||||||
|
final authRequest = {
|
||||||
|
'username': 'test@example.com',
|
||||||
|
'password': 'wrong',
|
||||||
|
};
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.login(authRequest: authRequest),
|
||||||
|
).thenAnswer((_) async => null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = await authRepository.login(authRequest: authRequest);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, isNull);
|
||||||
|
verify(() => mockAuthRemote.login(authRequest: authRequest)).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('logout', () {
|
||||||
|
test('should call remote logout method', () async {
|
||||||
|
// Arrange
|
||||||
|
when(() => mockAuthRemote.logout()).thenAnswer((_) async {});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await authRepository.logout();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verify(() => mockAuthRemote.logout()).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('hasAuthenticated', () {
|
||||||
|
test('should return true when user is authenticated', () async {
|
||||||
|
// Arrange
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.hasAuthenticated(),
|
||||||
|
).thenAnswer((_) async => true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = await authRepository.hasAuthenticated();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, isTrue);
|
||||||
|
verify(() => mockAuthRemote.hasAuthenticated()).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return false when user is not authenticated', () async {
|
||||||
|
// Arrange
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.hasAuthenticated(),
|
||||||
|
).thenAnswer((_) async => false);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = await authRepository.hasAuthenticated();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, isFalse);
|
||||||
|
verify(() => mockAuthRemote.hasAuthenticated()).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('getUserInfo', () {
|
||||||
|
test('should return UserInfoModel when user info is found', () async {
|
||||||
|
// Arrange
|
||||||
|
const phoneNumber = '09123456789';
|
||||||
|
final expectedUserInfo = UserInfoModel(
|
||||||
|
isUser: true,
|
||||||
|
address: 'Test Address',
|
||||||
|
backend: 'test-backend',
|
||||||
|
apiKey: 'test-api-key',
|
||||||
|
);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.getUserInfo(phoneNumber),
|
||||||
|
).thenAnswer((_) async => expectedUserInfo);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = await authRepository.getUserInfo(phoneNumber);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, equals(expectedUserInfo));
|
||||||
|
verify(() => mockAuthRemote.getUserInfo(phoneNumber)).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return null when user info is not found', () async {
|
||||||
|
// Arrange
|
||||||
|
const phoneNumber = '09123456789';
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.getUserInfo(phoneNumber),
|
||||||
|
).thenAnswer((_) async => null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = await authRepository.getUserInfo(phoneNumber);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, isNull);
|
||||||
|
verify(() => mockAuthRemote.getUserInfo(phoneNumber)).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('submitUserInfo', () {
|
||||||
|
test(
|
||||||
|
'should call remote submitUserInfo with correct parameters',
|
||||||
|
() async {
|
||||||
|
// Arrange
|
||||||
|
const phone = '09123456789';
|
||||||
|
const deviceName = 'Test Device';
|
||||||
|
final expectedData = {'mobile': phone, 'device_name': deviceName};
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.submitUserInfo(any()),
|
||||||
|
).thenAnswer((_) async {});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await authRepository.submitUserInfo(
|
||||||
|
phone: phone,
|
||||||
|
deviceName: deviceName,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verify(() => mockAuthRemote.submitUserInfo(expectedData)).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
test('should call remote submitUserInfo without device name', () async {
|
||||||
|
// Arrange
|
||||||
|
const phone = '09123456789';
|
||||||
|
final expectedData = {'mobile': phone, 'device_name': null};
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.submitUserInfo(any()),
|
||||||
|
).thenAnswer((_) async {});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await authRepository.submitUserInfo(phone: phone);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verify(() => mockAuthRemote.submitUserInfo(expectedData)).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('ChickenRepositoryImp', () {
|
||||||
|
test('should be implemented', () {
|
||||||
|
// TODO: Implement chicken repository tests
|
||||||
|
expect(true, isTrue);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,276 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/data_source/remote/auth/auth_remote.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/user_info/user_info_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/user_profile_model/user_profile_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/repositories/auth/auth_repository_imp.dart';
|
||||||
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
|
class MockAuthRemoteDataSource extends Mock implements AuthRemoteDataSource {}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
late AuthRepositoryImpl authRepository;
|
||||||
|
late MockAuthRemoteDataSource mockAuthRemote;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
mockAuthRemote = MockAuthRemoteDataSource();
|
||||||
|
authRepository = AuthRepositoryImpl(mockAuthRemote);
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Authentication Flow Integration Tests', () {
|
||||||
|
group('Complete Login Flow', () {
|
||||||
|
test('should complete full login flow successfully', () async {
|
||||||
|
// Arrange
|
||||||
|
const phoneNumber = '09123456789';
|
||||||
|
const deviceName = 'Test Device';
|
||||||
|
final authRequest = {
|
||||||
|
'username': 'test@example.com',
|
||||||
|
'password': 'password',
|
||||||
|
};
|
||||||
|
|
||||||
|
final expectedUserInfo = UserInfoModel(
|
||||||
|
isUser: true,
|
||||||
|
address: 'Test Address',
|
||||||
|
backend: 'test-backend',
|
||||||
|
apiKey: 'test-api-key',
|
||||||
|
);
|
||||||
|
|
||||||
|
final expectedUserProfile = UserProfileModel(
|
||||||
|
accessToken: 'access-token',
|
||||||
|
expiresIn: '3600',
|
||||||
|
scope: 'read write',
|
||||||
|
expireTime: '2024-12-31T23:59:59Z',
|
||||||
|
mobile: phoneNumber,
|
||||||
|
fullname: 'John Doe',
|
||||||
|
firstname: 'John',
|
||||||
|
lastname: 'Doe',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mock the flow
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.getUserInfo(phoneNumber),
|
||||||
|
).thenAnswer((_) async => expectedUserInfo);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.submitUserInfo(any()),
|
||||||
|
).thenAnswer((_) async {});
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.login(authRequest: authRequest),
|
||||||
|
).thenAnswer((_) async => expectedUserProfile);
|
||||||
|
|
||||||
|
// Act - Step 1: Get user info
|
||||||
|
final userInfo = await authRepository.getUserInfo(phoneNumber);
|
||||||
|
expect(userInfo, equals(expectedUserInfo));
|
||||||
|
|
||||||
|
// Act - Step 2: Submit user info
|
||||||
|
await authRepository.submitUserInfo(
|
||||||
|
phone: phoneNumber,
|
||||||
|
deviceName: deviceName,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act - Step 3: Login
|
||||||
|
final userProfile = await authRepository.login(
|
||||||
|
authRequest: authRequest,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(userProfile, equals(expectedUserProfile));
|
||||||
|
verify(() => mockAuthRemote.getUserInfo(phoneNumber)).called(1);
|
||||||
|
verify(() => mockAuthRemote.submitUserInfo(any())).called(1);
|
||||||
|
verify(() => mockAuthRemote.login(authRequest: authRequest)).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle login flow with authentication check', () async {
|
||||||
|
// Arrange
|
||||||
|
final authRequest = {
|
||||||
|
'username': 'test@example.com',
|
||||||
|
'password': 'password',
|
||||||
|
};
|
||||||
|
final expectedUserProfile = UserProfileModel(
|
||||||
|
accessToken: 'access-token',
|
||||||
|
expiresIn: '3600',
|
||||||
|
scope: 'read write',
|
||||||
|
expireTime: '2024-12-31T23:59:59Z',
|
||||||
|
mobile: '09123456789',
|
||||||
|
fullname: 'John Doe',
|
||||||
|
firstname: 'John',
|
||||||
|
lastname: 'Doe',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mock the flow
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.hasAuthenticated(),
|
||||||
|
).thenAnswer((_) async => false);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.login(authRequest: authRequest),
|
||||||
|
).thenAnswer((_) async => expectedUserProfile);
|
||||||
|
|
||||||
|
// Act - Step 1: Check authentication status
|
||||||
|
final isAuthenticated = await authRepository.hasAuthenticated();
|
||||||
|
expect(isAuthenticated, isFalse);
|
||||||
|
|
||||||
|
// Act - Step 2: Login
|
||||||
|
final userProfile = await authRepository.login(
|
||||||
|
authRequest: authRequest,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(userProfile, equals(expectedUserProfile));
|
||||||
|
verify(() => mockAuthRemote.hasAuthenticated()).called(1);
|
||||||
|
verify(() => mockAuthRemote.login(authRequest: authRequest)).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Error Handling in Authentication Flow', () {
|
||||||
|
test('should handle user info retrieval failure', () async {
|
||||||
|
// Arrange
|
||||||
|
const phoneNumber = '09123456789';
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.getUserInfo(phoneNumber),
|
||||||
|
).thenAnswer((_) async => null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final userInfo = await authRepository.getUserInfo(phoneNumber);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(userInfo, isNull);
|
||||||
|
verify(() => mockAuthRemote.getUserInfo(phoneNumber)).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle login failure after successful user info', () async {
|
||||||
|
// Arrange
|
||||||
|
const phoneNumber = '09123456789';
|
||||||
|
const deviceName = 'Test Device';
|
||||||
|
final authRequest = {
|
||||||
|
'username': 'test@example.com',
|
||||||
|
'password': 'wrong',
|
||||||
|
};
|
||||||
|
|
||||||
|
final expectedUserInfo = UserInfoModel(
|
||||||
|
isUser: true,
|
||||||
|
address: 'Test Address',
|
||||||
|
backend: 'test-backend',
|
||||||
|
apiKey: 'test-api-key',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mock the flow
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.getUserInfo(phoneNumber),
|
||||||
|
).thenAnswer((_) async => expectedUserInfo);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.submitUserInfo(any()),
|
||||||
|
).thenAnswer((_) async {});
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.login(authRequest: authRequest),
|
||||||
|
).thenAnswer((_) async => null);
|
||||||
|
|
||||||
|
// Act - Step 1: Get user info (success)
|
||||||
|
final userInfo = await authRepository.getUserInfo(phoneNumber);
|
||||||
|
expect(userInfo, equals(expectedUserInfo));
|
||||||
|
|
||||||
|
// Act - Step 2: Submit user info (success)
|
||||||
|
await authRepository.submitUserInfo(
|
||||||
|
phone: phoneNumber,
|
||||||
|
deviceName: deviceName,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act - Step 3: Login (failure)
|
||||||
|
final userProfile = await authRepository.login(
|
||||||
|
authRequest: authRequest,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(userProfile, isNull);
|
||||||
|
verify(() => mockAuthRemote.getUserInfo(phoneNumber)).called(1);
|
||||||
|
verify(() => mockAuthRemote.submitUserInfo(any())).called(1);
|
||||||
|
verify(() => mockAuthRemote.login(authRequest: authRequest)).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Logout Flow', () {
|
||||||
|
test('should complete logout flow', () async {
|
||||||
|
// Arrange
|
||||||
|
when(() => mockAuthRemote.logout()).thenAnswer((_) async {});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await authRepository.logout();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verify(() => mockAuthRemote.logout()).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Authentication State Management', () {
|
||||||
|
test('should track authentication state correctly', () async {
|
||||||
|
// Arrange
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.hasAuthenticated(),
|
||||||
|
).thenAnswer((_) async => true);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final isAuthenticated = await authRepository.hasAuthenticated();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(isAuthenticated, isTrue);
|
||||||
|
verify(() => mockAuthRemote.hasAuthenticated()).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle authentication state changes', () async {
|
||||||
|
// Arrange
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.hasAuthenticated(),
|
||||||
|
).thenAnswer((_) async => false);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final isAuthenticated = await authRepository.hasAuthenticated();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(isAuthenticated, isFalse);
|
||||||
|
verify(() => mockAuthRemote.hasAuthenticated()).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('User Info Management', () {
|
||||||
|
test('should handle user info submission without device name', () async {
|
||||||
|
// Arrange
|
||||||
|
const phone = '09123456789';
|
||||||
|
final expectedData = {'mobile': phone, 'device_name': null};
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.submitUserInfo(any()),
|
||||||
|
).thenAnswer((_) async {});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await authRepository.submitUserInfo(phone: phone);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verify(() => mockAuthRemote.submitUserInfo(expectedData)).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle user info submission with device name', () async {
|
||||||
|
// Arrange
|
||||||
|
const phone = '09123456789';
|
||||||
|
const deviceName = 'Test Device';
|
||||||
|
final expectedData = {'mobile': phone, 'device_name': deviceName};
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockAuthRemote.submitUserInfo(any()),
|
||||||
|
).thenAnswer((_) async {});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await authRepository.submitUserInfo(
|
||||||
|
phone: phone,
|
||||||
|
deviceName: deviceName,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verify(() => mockAuthRemote.submitUserInfo(expectedData)).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,641 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/data_source/remote/poultry_science/poultry_science_remote.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/poultry_export/poultry_export.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/request/kill_registration/kill_registration.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/all_poultry/all_poultry.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/approved_price/approved_price.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/hatching/hatching_models.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/hatching_report/hatching_report.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/kill_house_poultry/kill_house_poultry.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/kill_request_poultry/kill_request_poultry.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/poultry_farm/poultry_farm.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/poultry_hatching/poultry_hatching.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/poultry_order/poultry_order.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/poultry_science/home_poultry_science/home_poultry_science_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/sell_for_freezing/sell_for_freezing.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/repositories/poultry_science/poultry_science_repository_imp.dart';
|
||||||
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
|
class MockPoultryScienceRemoteDataSource extends Mock
|
||||||
|
implements PoultryScienceRemoteDatasource {}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
late PoultryScienceRepositoryImp poultryScienceRepository;
|
||||||
|
late MockPoultryScienceRemoteDataSource mockRemote;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
mockRemote = MockPoultryScienceRemoteDataSource();
|
||||||
|
poultryScienceRepository = PoultryScienceRepositoryImp(mockRemote);
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Poultry Science Integration Tests', () {
|
||||||
|
const token = 'test-token';
|
||||||
|
|
||||||
|
group('Complete Poultry Science Home Flow', () {
|
||||||
|
test('should complete full poultry science home workflow', () async {
|
||||||
|
// Arrange
|
||||||
|
const type = 'hatching';
|
||||||
|
|
||||||
|
final expectedHomeModel = HomePoultryScienceModel(
|
||||||
|
farmCount: 5,
|
||||||
|
hatchingCount: 1000,
|
||||||
|
hatchingQuantity: 500,
|
||||||
|
hatchingLeftOver: 200,
|
||||||
|
hatchingLosses: 50,
|
||||||
|
hatchingKilledQuantity: 250,
|
||||||
|
hatchingMaxAge: 45,
|
||||||
|
hatchingMinAge: 30,
|
||||||
|
);
|
||||||
|
|
||||||
|
final expectedHatching = [
|
||||||
|
HatchingModel(
|
||||||
|
id: 1,
|
||||||
|
key: 'hatching-1',
|
||||||
|
date: '2024-01-01',
|
||||||
|
quantity: 100,
|
||||||
|
state: 'active',
|
||||||
|
),
|
||||||
|
];
|
||||||
|
final expectedHatchingPagination = PaginationModel<HatchingModel>(
|
||||||
|
results: expectedHatching,
|
||||||
|
count: 1,
|
||||||
|
next: null,
|
||||||
|
previous: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mock the flow
|
||||||
|
when(
|
||||||
|
() => mockRemote.getHomePoultryScience(token: token, type: type),
|
||||||
|
).thenAnswer((_) async => expectedHomeModel);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockRemote.getHatchingPoultry(
|
||||||
|
token: token,
|
||||||
|
queryParameters: any(named: 'queryParameters'),
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => expectedHatchingPagination);
|
||||||
|
|
||||||
|
// Act - Step 1: Get home poultry science data
|
||||||
|
final homeModel = await poultryScienceRepository.getHomePoultry(
|
||||||
|
token: token,
|
||||||
|
type: type,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act - Step 2: Get hatching poultry data
|
||||||
|
final hatchingData = await poultryScienceRepository.getHatchingPoultry(
|
||||||
|
token: token,
|
||||||
|
queryParameters: {'page': '1', 'limit': '10'},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(homeModel, equals(expectedHomeModel));
|
||||||
|
expect(hatchingData, equals(expectedHatchingPagination));
|
||||||
|
|
||||||
|
verify(
|
||||||
|
() => mockRemote.getHomePoultryScience(token: token, type: type),
|
||||||
|
).called(1);
|
||||||
|
verify(
|
||||||
|
() => mockRemote.getHatchingPoultry(
|
||||||
|
token: token,
|
||||||
|
queryParameters: any(named: 'queryParameters'),
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Hatching Report Management Flow', () {
|
||||||
|
test('should complete hatching report management workflow', () async {
|
||||||
|
// Arrange
|
||||||
|
final queryParameters = {'page': '1', 'limit': '10'};
|
||||||
|
|
||||||
|
final expectedReports = [
|
||||||
|
HatchingReport(
|
||||||
|
id: 1,
|
||||||
|
key: 'report-1',
|
||||||
|
date: DateTime.parse('2024-01-01'),
|
||||||
|
state: 'completed',
|
||||||
|
),
|
||||||
|
];
|
||||||
|
final expectedPagination = PaginationModel<HatchingReport>(
|
||||||
|
results: expectedReports,
|
||||||
|
count: 1,
|
||||||
|
next: null,
|
||||||
|
previous: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
final mockFormData = MockFormData();
|
||||||
|
|
||||||
|
// Mock the flow
|
||||||
|
when(
|
||||||
|
() => mockRemote.getPoultryScienceReport(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => expectedPagination);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockRemote.submitPoultryScienceReport(
|
||||||
|
token: token,
|
||||||
|
data: mockFormData,
|
||||||
|
onSendProgress: any(named: 'onSendProgress'),
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async {});
|
||||||
|
|
||||||
|
// Act - Step 1: Get hatching reports
|
||||||
|
final reports = await poultryScienceRepository.getHatchingPoultryReport(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act - Step 2: Submit new report
|
||||||
|
await poultryScienceRepository.submitPoultryScienceReport(
|
||||||
|
token: token,
|
||||||
|
data: mockFormData,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(reports, equals(expectedPagination));
|
||||||
|
|
||||||
|
verify(
|
||||||
|
() => mockRemote.getPoultryScienceReport(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
verify(
|
||||||
|
() => mockRemote.submitPoultryScienceReport(
|
||||||
|
token: token,
|
||||||
|
data: mockFormData,
|
||||||
|
onSendProgress: any(named: 'onSendProgress'),
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Poultry Farm Management Flow', () {
|
||||||
|
test('should complete poultry farm management workflow', () async {
|
||||||
|
// Arrange
|
||||||
|
final queryParameters = {'page': '1', 'limit': '10'};
|
||||||
|
|
||||||
|
final expectedFarms = [
|
||||||
|
PoultryFarm(
|
||||||
|
id: 1,
|
||||||
|
key: 'farm-1',
|
||||||
|
unitName: 'Farm 1',
|
||||||
|
totalCapacity: 1000,
|
||||||
|
cityName: 'Tehran',
|
||||||
|
),
|
||||||
|
];
|
||||||
|
final expectedPagination = PaginationModel<PoultryFarm>(
|
||||||
|
results: expectedFarms,
|
||||||
|
count: 1,
|
||||||
|
next: null,
|
||||||
|
previous: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mock the flow
|
||||||
|
when(
|
||||||
|
() => mockRemote.getPoultryScienceFarmList(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => expectedPagination);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final farms = await poultryScienceRepository.getPoultryScienceFarmList(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(farms, equals(expectedPagination));
|
||||||
|
|
||||||
|
verify(
|
||||||
|
() => mockRemote.getPoultryScienceFarmList(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Pricing and Market Data Flow', () {
|
||||||
|
test('should complete pricing and market data workflow', () async {
|
||||||
|
// Arrange
|
||||||
|
final queryParameters = {'date': '2024-01-01'};
|
||||||
|
|
||||||
|
final expectedApprovedPrice = ApprovedPrice(
|
||||||
|
approved: true,
|
||||||
|
lowestPrice: 45000.0,
|
||||||
|
highestPrice: 55000.0,
|
||||||
|
lowestWeight: 1.5,
|
||||||
|
highestWeight: 2.5,
|
||||||
|
);
|
||||||
|
|
||||||
|
final expectedSellForFreezing = SellForFreezing(permission: true);
|
||||||
|
|
||||||
|
final expectedPoultryExport = PoultryExport(
|
||||||
|
key: 'export-key',
|
||||||
|
allow: true,
|
||||||
|
limitationStatus: false,
|
||||||
|
limitation: 100.0,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mock the flow
|
||||||
|
when(
|
||||||
|
() => mockRemote.getApprovedPrice(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => expectedApprovedPrice);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockRemote.getSellForFreezing(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => expectedSellForFreezing);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockRemote.getPoultryExport(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => expectedPoultryExport);
|
||||||
|
|
||||||
|
// Act - Step 1: Get approved price
|
||||||
|
final approvedPrice = await poultryScienceRepository.getApprovedPrice(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act - Step 2: Get sell for freezing data
|
||||||
|
final sellForFreezing = await poultryScienceRepository
|
||||||
|
.getSellForFreezing(token: token, queryParameters: queryParameters);
|
||||||
|
|
||||||
|
// Act - Step 3: Get poultry export data
|
||||||
|
final poultryExport = await poultryScienceRepository.getPoultryExport(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(approvedPrice, equals(expectedApprovedPrice));
|
||||||
|
expect(sellForFreezing, equals(expectedSellForFreezing));
|
||||||
|
expect(poultryExport, equals(expectedPoultryExport));
|
||||||
|
|
||||||
|
verify(
|
||||||
|
() => mockRemote.getApprovedPrice(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
verify(
|
||||||
|
() => mockRemote.getSellForFreezing(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
verify(
|
||||||
|
() => mockRemote.getPoultryExport(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Kill Registration Flow', () {
|
||||||
|
test('should complete kill registration workflow', () async {
|
||||||
|
// Arrange
|
||||||
|
final queryParameters = {'page': '1', 'limit': '10'};
|
||||||
|
|
||||||
|
final expectedKillRequests = [
|
||||||
|
KillRequestPoultry(
|
||||||
|
key: 'kill-request-1',
|
||||||
|
unitName: 'Farm 1',
|
||||||
|
totalCapacity: 1000,
|
||||||
|
cityName: 'Tehran',
|
||||||
|
provinceName: 'Tehran',
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
final expectedKillHouses = [
|
||||||
|
KillHousePoultry(
|
||||||
|
name: 'Kill House 1',
|
||||||
|
killer: true,
|
||||||
|
fullname: 'Kill House Manager',
|
||||||
|
quantitySum: 500,
|
||||||
|
firstQuantity: 100,
|
||||||
|
poultryQuantitySum: 400,
|
||||||
|
killReqKey: 'killhouse-1',
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
final expectedPoultryHatching = [
|
||||||
|
PoultryHatching(
|
||||||
|
key: 'hatching-1',
|
||||||
|
quantity: 100,
|
||||||
|
losses: 5,
|
||||||
|
leftOver: 95,
|
||||||
|
killedQuantity: 50,
|
||||||
|
state: 'active',
|
||||||
|
date: '2024-01-01',
|
||||||
|
age: 30,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
final killRegistrationRequest = KillRegistrationRequest(
|
||||||
|
killReqKey: 'registration-key',
|
||||||
|
operatorKey: 'operator-1',
|
||||||
|
poultryHatchingKey: 'hatching-1',
|
||||||
|
quantity: 100,
|
||||||
|
sendDate: '2024-01-01',
|
||||||
|
chickenBreed: 'Broiler',
|
||||||
|
indexWeight: 2.0,
|
||||||
|
losses: '5',
|
||||||
|
freezing: false,
|
||||||
|
export: false,
|
||||||
|
cash: true,
|
||||||
|
credit: false,
|
||||||
|
role: 'farmer',
|
||||||
|
poultryKey: 'poultry-1',
|
||||||
|
amount: 100000,
|
||||||
|
financialOperation: 'cash',
|
||||||
|
freeSaleInProvince: true,
|
||||||
|
confirmPoultryMobile: '09123456789',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mock the flow
|
||||||
|
when(
|
||||||
|
() => mockRemote.getUserPoultry(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).thenAnswer(
|
||||||
|
(_) async => expectedKillRequests.cast<KillRequestPoultry>(),
|
||||||
|
);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockRemote.getKillHouseList(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => expectedKillHouses.cast<KillHousePoultry>());
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockRemote.getPoultryHatching(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).thenAnswer(
|
||||||
|
(_) async => expectedPoultryHatching.cast<PoultryHatching>(),
|
||||||
|
);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockRemote.submitKillRegistration(
|
||||||
|
token: token,
|
||||||
|
request: killRegistrationRequest,
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async {});
|
||||||
|
|
||||||
|
// Act - Step 1: Get user poultry
|
||||||
|
final killRequests = await poultryScienceRepository.getUserPoultry(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act - Step 2: Get kill house list
|
||||||
|
final killHouses = await poultryScienceRepository.getKillHouseList(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act - Step 3: Get poultry hatching
|
||||||
|
final poultryHatching = await poultryScienceRepository
|
||||||
|
.getPoultryHatching(token: token, queryParameters: queryParameters);
|
||||||
|
|
||||||
|
// Act - Step 4: Submit kill registration
|
||||||
|
await poultryScienceRepository.submitKillRegistration(
|
||||||
|
token: token,
|
||||||
|
request: killRegistrationRequest,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(killRequests, equals(expectedKillRequests));
|
||||||
|
expect(killHouses, equals(expectedKillHouses));
|
||||||
|
expect(poultryHatching, equals(expectedPoultryHatching));
|
||||||
|
|
||||||
|
verify(
|
||||||
|
() => mockRemote.getUserPoultry(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
verify(
|
||||||
|
() => mockRemote.getKillHouseList(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
verify(
|
||||||
|
() => mockRemote.getPoultryHatching(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
verify(
|
||||||
|
() => mockRemote.submitKillRegistration(
|
||||||
|
token: token,
|
||||||
|
request: killRegistrationRequest,
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Poultry Order Management Flow', () {
|
||||||
|
test('should complete poultry order management workflow', () async {
|
||||||
|
// Arrange
|
||||||
|
final queryParameters = {'page': '1', 'limit': '10'};
|
||||||
|
const orderId = 'order-1';
|
||||||
|
|
||||||
|
final expectedOrders = [
|
||||||
|
PoultryOrder(
|
||||||
|
key: 'order-1',
|
||||||
|
id: 1,
|
||||||
|
orderCode: 1001,
|
||||||
|
createDate: '2024-01-01',
|
||||||
|
sendDate: '2024-01-02',
|
||||||
|
quantity: 100,
|
||||||
|
firstQuantity: 100,
|
||||||
|
amount: 5000000.0,
|
||||||
|
finalState: 'pending',
|
||||||
|
provinceState: 'pending',
|
||||||
|
stateProcess: 'processing',
|
||||||
|
freeSaleInProvince: true,
|
||||||
|
freezing: false,
|
||||||
|
export: false,
|
||||||
|
market: true,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
final expectedPagination = PaginationModel<PoultryOrder>(
|
||||||
|
count: 1,
|
||||||
|
next: null,
|
||||||
|
previous: null,
|
||||||
|
results: expectedOrders,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mock the flow
|
||||||
|
when(
|
||||||
|
() => mockRemote.getPoultryOderList(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => expectedPagination);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockRemote.deletePoultryOder(token: token, orderId: orderId),
|
||||||
|
).thenAnswer((_) async {});
|
||||||
|
|
||||||
|
// Act - Step 1: Get poultry orders
|
||||||
|
final orders = await poultryScienceRepository.getPoultryOderList(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act - Step 2: Delete poultry order
|
||||||
|
await poultryScienceRepository.deletePoultryOder(
|
||||||
|
token: token,
|
||||||
|
orderId: orderId,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(orders, equals(expectedPagination));
|
||||||
|
|
||||||
|
verify(
|
||||||
|
() => mockRemote.getPoultryOderList(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
verify(
|
||||||
|
() => mockRemote.deletePoultryOder(token: token, orderId: orderId),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('All Poultry Data Flow', () {
|
||||||
|
test('should complete all poultry data retrieval workflow', () async {
|
||||||
|
// Arrange
|
||||||
|
final queryParameters = {'type': 'all'};
|
||||||
|
|
||||||
|
final expectedAllPoultry = [
|
||||||
|
AllPoultry(
|
||||||
|
key: 'poultry-1',
|
||||||
|
unitName: 'Poultry Farm 1',
|
||||||
|
lastHatchingRemainQuantity: 100,
|
||||||
|
provinceAllowSellFree: true,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
// Mock the flow
|
||||||
|
when(
|
||||||
|
() => mockRemote.getAllPoultry(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => expectedAllPoultry.cast<AllPoultry>());
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final allPoultry = await poultryScienceRepository.getAllPoultry(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(allPoultry, equals(expectedAllPoultry));
|
||||||
|
|
||||||
|
verify(
|
||||||
|
() => mockRemote.getAllPoultry(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Error Handling in Poultry Science Workflow', () {
|
||||||
|
test('should handle home poultry data retrieval failure', () async {
|
||||||
|
// Arrange
|
||||||
|
const type = 'hatching';
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockRemote.getHomePoultryScience(token: token, type: type),
|
||||||
|
).thenAnswer((_) async => null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final homeModel = await poultryScienceRepository.getHomePoultry(
|
||||||
|
token: token,
|
||||||
|
type: type,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(homeModel, isNull);
|
||||||
|
verify(
|
||||||
|
() => mockRemote.getHomePoultryScience(token: token, type: type),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle kill registration submission failure', () async {
|
||||||
|
// Arrange
|
||||||
|
final killRegistrationRequest = KillRegistrationRequest(
|
||||||
|
killReqKey: 'registration-key',
|
||||||
|
operatorKey: 'operator-1',
|
||||||
|
poultryHatchingKey: 'hatching-1',
|
||||||
|
quantity: 100,
|
||||||
|
sendDate: '2024-01-01',
|
||||||
|
chickenBreed: 'Broiler',
|
||||||
|
indexWeight: 2.0,
|
||||||
|
losses: '5',
|
||||||
|
freezing: false,
|
||||||
|
export: false,
|
||||||
|
cash: true,
|
||||||
|
credit: false,
|
||||||
|
role: 'farmer',
|
||||||
|
poultryKey: 'poultry-1',
|
||||||
|
amount: 100000,
|
||||||
|
financialOperation: 'cash',
|
||||||
|
freeSaleInProvince: true,
|
||||||
|
confirmPoultryMobile: '09123456789',
|
||||||
|
);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockRemote.submitKillRegistration(
|
||||||
|
token: token,
|
||||||
|
request: killRegistrationRequest,
|
||||||
|
),
|
||||||
|
).thenThrow(Exception('Kill registration submission failed'));
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
expect(
|
||||||
|
() => poultryScienceRepository.submitKillRegistration(
|
||||||
|
token: token,
|
||||||
|
request: killRegistrationRequest,
|
||||||
|
),
|
||||||
|
throwsA(isA<Exception>()),
|
||||||
|
);
|
||||||
|
|
||||||
|
verify(
|
||||||
|
() => mockRemote.submitKillRegistration(
|
||||||
|
token: token,
|
||||||
|
request: killRegistrationRequest,
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mock FormData class
|
||||||
|
class MockFormData extends Mock implements FormData {}
|
||||||
@@ -0,0 +1,469 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:mocktail/mocktail.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/data_source/local/chicken_local.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/data_source/remote/chicken/chicken_remote.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/local/widely_used_local_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/request/create_steward_free_bar/create_steward_free_bar.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/request/steward_free_sale_bar/steward_free_sale_bar_request.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/request/submit_steward_allocation/submit_steward_allocation.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/allocated_made/allocated_made.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/bar_information/bar_information.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/broadcast_price/broadcast_price.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/dashboard_kill_house_free_bar/dashboard_kill_house_free_bar.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/guild/guild_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/guild_profile/guild_profile.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/inventory/inventory_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/iran_province_city/iran_province_city_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/kill_house_poultry/kill_house_poultry.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/kill_house_distribution_info/kill_house_distribution_info.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/out_province_carcasses_buyer/out_province_carcasses_buyer.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/roles_products/roles_products.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/segmentation_model/segmentation_model.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/steward_free_bar/steward_free_bar.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/steward_free_bar_dashboard/steward_free_bar_dashboard.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/steward_free_sale_bar/steward_free_sale_bar.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/steward_sales_info_dashboard/steward_sales_info_dashboard.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/user_profile/user_profile.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/models/response/waiting_arrival/waiting_arrival.dart';
|
||||||
|
import 'package:rasadyar_chicken/data/repositories/chicken/chicken_repository_imp.dart';
|
||||||
|
import 'package:rasadyar_core/core.dart';
|
||||||
|
|
||||||
|
class MockChickenRemoteDatasource extends Mock
|
||||||
|
implements ChickenRemoteDatasource {}
|
||||||
|
|
||||||
|
class MockChickenLocalDataSource extends Mock
|
||||||
|
implements ChickenLocalDataSource {}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
late ChickenRepositoryImp chickenRepository;
|
||||||
|
late MockChickenRemoteDatasource mockRemote;
|
||||||
|
late MockChickenLocalDataSource mockLocal;
|
||||||
|
|
||||||
|
setUp(() {
|
||||||
|
mockRemote = MockChickenRemoteDatasource();
|
||||||
|
mockLocal = MockChickenLocalDataSource();
|
||||||
|
chickenRepository = ChickenRepositoryImp(
|
||||||
|
remote: mockRemote,
|
||||||
|
local: mockLocal,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Steward Workflow Integration Tests', () {
|
||||||
|
const token = 'test-token';
|
||||||
|
|
||||||
|
group('Complete Steward Dashboard Flow', () {
|
||||||
|
test('should complete full steward dashboard workflow', () async {
|
||||||
|
// Arrange
|
||||||
|
const startDate = '2024-01-01';
|
||||||
|
const endDate = '2024-01-31';
|
||||||
|
|
||||||
|
final expectedDashboard = StewardFreeBarDashboard(
|
||||||
|
totalBars: 1000,
|
||||||
|
totalQuantity: 800,
|
||||||
|
totalWeight: 200,
|
||||||
|
);
|
||||||
|
|
||||||
|
final expectedBroadcastPrice = BroadcastPrice(
|
||||||
|
active: true,
|
||||||
|
killHousePrice: 45000,
|
||||||
|
stewardPrice: 50000,
|
||||||
|
guildPrice: 55000,
|
||||||
|
);
|
||||||
|
|
||||||
|
final expectedProfile = GuildProfile(
|
||||||
|
key: 'profile-key',
|
||||||
|
guilds_name: 'Test Guild',
|
||||||
|
type_activity: 'Test Guild Type',
|
||||||
|
area_activity: 'Test Guild Type Description',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mock the flow
|
||||||
|
when(
|
||||||
|
() => mockRemote.getStewardDashboard(
|
||||||
|
token: token,
|
||||||
|
stratDate: startDate,
|
||||||
|
endDate: endDate,
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => expectedDashboard);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockRemote.getBroadcastPrice(token: token),
|
||||||
|
).thenAnswer((_) async => expectedBroadcastPrice);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockRemote.getProfile(token: token),
|
||||||
|
).thenAnswer((_) async => expectedProfile);
|
||||||
|
|
||||||
|
// Act - Step 1: Get steward dashboard
|
||||||
|
final dashboard = await chickenRepository.getStewardDashboard(
|
||||||
|
token: token,
|
||||||
|
stratDate: startDate,
|
||||||
|
endDate: endDate,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act - Step 2: Get broadcast price
|
||||||
|
final broadcastPrice = await chickenRepository.getBroadcastPrice(
|
||||||
|
token: token,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act - Step 3: Get profile
|
||||||
|
final profile = await chickenRepository.getProfile(token: token);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(dashboard, equals(expectedDashboard));
|
||||||
|
expect(broadcastPrice, equals(expectedBroadcastPrice));
|
||||||
|
expect(profile, equals(expectedProfile));
|
||||||
|
|
||||||
|
verify(
|
||||||
|
() => mockRemote.getStewardDashboard(
|
||||||
|
token: token,
|
||||||
|
stratDate: startDate,
|
||||||
|
endDate: endDate,
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
verify(() => mockRemote.getBroadcastPrice(token: token)).called(1);
|
||||||
|
verify(() => mockRemote.getProfile(token: token)).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Inventory Management Flow', () {
|
||||||
|
test('should complete inventory management workflow', () async {
|
||||||
|
// Arrange
|
||||||
|
final expectedInventory = [
|
||||||
|
InventoryModel(
|
||||||
|
key: 'inventory-1',
|
||||||
|
name: 'Product 1',
|
||||||
|
totalCarcassesQuantity: 100,
|
||||||
|
),
|
||||||
|
InventoryModel(
|
||||||
|
key: 'inventory-2',
|
||||||
|
name: 'Product 2',
|
||||||
|
totalCarcassesQuantity: 200,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
final expectedKillHouseInfo = KillHouseDistributionInfo(
|
||||||
|
stewardAllocationsWeight: 1000.0,
|
||||||
|
freeSalesWeight: 500.0,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mock the flow
|
||||||
|
when(
|
||||||
|
() => mockRemote.getInventory(
|
||||||
|
token: token,
|
||||||
|
cancelToken: any(named: 'cancelToken'),
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => expectedInventory);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockRemote.getKillHouseDistributionInfo(token: token),
|
||||||
|
).thenAnswer((_) async => expectedKillHouseInfo);
|
||||||
|
|
||||||
|
// Act - Step 1: Get inventory
|
||||||
|
final inventory = await chickenRepository.getInventory(token: token);
|
||||||
|
|
||||||
|
// Act - Step 2: Get kill house distribution info
|
||||||
|
final killHouseInfo = await chickenRepository
|
||||||
|
.getKillHouseDistributionInfo(token: token);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(inventory, equals(expectedInventory));
|
||||||
|
expect(killHouseInfo, equals(expectedKillHouseInfo));
|
||||||
|
|
||||||
|
verify(
|
||||||
|
() => mockRemote.getInventory(
|
||||||
|
token: token,
|
||||||
|
cancelToken: any(named: 'cancelToken'),
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
verify(
|
||||||
|
() => mockRemote.getKillHouseDistributionInfo(token: token),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Allocation Management Flow', () {
|
||||||
|
test('should complete allocation management workflow', () async {
|
||||||
|
// Arrange
|
||||||
|
final queryParameters = {'page': '1', 'limit': '10'};
|
||||||
|
|
||||||
|
final expectedAllocations = [
|
||||||
|
AllocatedMadeModel(
|
||||||
|
key: 'allocation-1',
|
||||||
|
productName: 'Product 1',
|
||||||
|
numberOfCarcasses: 100,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
final expectedPagination = PaginationModel<AllocatedMadeModel>(
|
||||||
|
results: expectedAllocations,
|
||||||
|
count: 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
final allocationRequest = {
|
||||||
|
'allocationId': 'allocation-1',
|
||||||
|
'confirmed': true,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Mock the flow
|
||||||
|
when(
|
||||||
|
() => mockRemote.getAllocatedMade(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => expectedPagination);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockRemote.confirmAllocation(
|
||||||
|
token: token,
|
||||||
|
allocation: allocationRequest,
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async {});
|
||||||
|
|
||||||
|
// Act - Step 1: Get allocated made
|
||||||
|
final allocations = await chickenRepository.getAllocatedMade(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act - Step 2: Confirm allocation
|
||||||
|
await chickenRepository.confirmAllocation(
|
||||||
|
token: token,
|
||||||
|
allocation: allocationRequest,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(allocations, equals(expectedPagination));
|
||||||
|
|
||||||
|
verify(
|
||||||
|
() => mockRemote.getAllocatedMade(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
verify(
|
||||||
|
() => mockRemote.confirmAllocation(
|
||||||
|
token: token,
|
||||||
|
allocation: allocationRequest,
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Steward Free Bar Management Flow', () {
|
||||||
|
test('should complete steward free bar management workflow', () async {
|
||||||
|
// Arrange
|
||||||
|
final queryParameters = {'page': '1', 'limit': '10'};
|
||||||
|
|
||||||
|
final expectedFreeBars = [
|
||||||
|
StewardFreeBar(
|
||||||
|
key: 'freebar-1',
|
||||||
|
killHouseName: 'Bar 1',
|
||||||
|
weightOfCarcasses: 500.0,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
final expectedPagination = PaginationModel<StewardFreeBar>(
|
||||||
|
results: expectedFreeBars,
|
||||||
|
count: 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
final createRequest = CreateStewardFreeBar(
|
||||||
|
key: 'new-freebar',
|
||||||
|
killHouseName: 'New Bar',
|
||||||
|
weightOfCarcasses: 300,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mock the flow
|
||||||
|
when(
|
||||||
|
() => mockRemote.getStewardPurchasesOutSideOfTheProvince(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => expectedPagination);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockRemote.createStewardPurchasesOutSideOfTheProvince(
|
||||||
|
token: token,
|
||||||
|
body: createRequest,
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async {});
|
||||||
|
|
||||||
|
// Act - Step 1: Get steward purchases outside province
|
||||||
|
final freeBars = await chickenRepository
|
||||||
|
.getStewardPurchasesOutSideOfTheProvince(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act - Step 2: Create new steward purchase
|
||||||
|
await chickenRepository.createStewardPurchasesOutSideOfTheProvince(
|
||||||
|
token: token,
|
||||||
|
body: createRequest,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(freeBars, equals(expectedPagination));
|
||||||
|
|
||||||
|
verify(
|
||||||
|
() => mockRemote.getStewardPurchasesOutSideOfTheProvince(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
verify(
|
||||||
|
() => mockRemote.createStewardPurchasesOutSideOfTheProvince(
|
||||||
|
token: token,
|
||||||
|
body: createRequest,
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Segmentation Management Flow', () {
|
||||||
|
test('should complete segmentation management workflow', () async {
|
||||||
|
// Arrange
|
||||||
|
final queryParameters = {'page': '1', 'limit': '10'};
|
||||||
|
|
||||||
|
final expectedSegments = [
|
||||||
|
SegmentationModel(
|
||||||
|
key: 'segment-1',
|
||||||
|
result: 'Segment 1',
|
||||||
|
quota: 'Description 1',
|
||||||
|
),
|
||||||
|
];
|
||||||
|
final expectedPagination = PaginationModel<SegmentationModel>(
|
||||||
|
results: expectedSegments,
|
||||||
|
count: 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
final newSegment = SegmentationModel(
|
||||||
|
key: 'new-segment',
|
||||||
|
result: 'New Segment',
|
||||||
|
quota: 'New Description',
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mock the flow
|
||||||
|
when(
|
||||||
|
() => mockRemote.getSegmentation(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => expectedPagination);
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockRemote.createSegmentation(token: token, model: newSegment),
|
||||||
|
).thenAnswer((_) async {});
|
||||||
|
|
||||||
|
// Act - Step 1: Get segmentation
|
||||||
|
final segments = await chickenRepository.getSegmentation(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Act - Step 2: Create new segmentation
|
||||||
|
await chickenRepository.createSegmentation(
|
||||||
|
token: token,
|
||||||
|
model: newSegment,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(segments, equals(expectedPagination));
|
||||||
|
|
||||||
|
verify(
|
||||||
|
() => mockRemote.getSegmentation(
|
||||||
|
token: token,
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
verify(
|
||||||
|
() => mockRemote.createSegmentation(token: token, model: newSegment),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Local Data Integration', () {
|
||||||
|
test('should integrate local data with remote operations', () async {
|
||||||
|
// Arrange
|
||||||
|
final expectedWidelyUsed = WidelyUsedLocalModel(
|
||||||
|
hasInit: true,
|
||||||
|
items: [],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Mock local data
|
||||||
|
when(() => mockLocal.getAllWidely()).thenReturn(expectedWidelyUsed);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final widelyUsed = chickenRepository.getAllWidely();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(widelyUsed, equals(expectedWidelyUsed));
|
||||||
|
verify(() => mockLocal.getAllWidely()).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should initialize widely used data', () async {
|
||||||
|
// Arrange
|
||||||
|
when(() => mockLocal.initWidleyUsed()).thenAnswer((_) async {});
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await chickenRepository.initWidleyUsed();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
verify(() => mockLocal.initWidleyUsed()).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('Error Handling in Steward Workflow', () {
|
||||||
|
test('should handle inventory retrieval failure', () async {
|
||||||
|
// Arrange
|
||||||
|
when(
|
||||||
|
() => mockRemote.getInventory(
|
||||||
|
token: token,
|
||||||
|
cancelToken: any(named: 'cancelToken'),
|
||||||
|
),
|
||||||
|
).thenAnswer((_) async => null);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final inventory = await chickenRepository.getInventory(token: token);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(inventory, isNull);
|
||||||
|
verify(
|
||||||
|
() => mockRemote.getInventory(
|
||||||
|
token: token,
|
||||||
|
cancelToken: any(named: 'cancelToken'),
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle allocation confirmation failure', () async {
|
||||||
|
// Arrange
|
||||||
|
final allocationRequest = {
|
||||||
|
'allocationId': 'allocation-1',
|
||||||
|
'confirmed': true,
|
||||||
|
};
|
||||||
|
|
||||||
|
when(
|
||||||
|
() => mockRemote.confirmAllocation(
|
||||||
|
token: token,
|
||||||
|
allocation: allocationRequest,
|
||||||
|
),
|
||||||
|
).thenThrow(Exception('Allocation confirmation failed'));
|
||||||
|
|
||||||
|
// Act & Assert
|
||||||
|
expect(
|
||||||
|
() => chickenRepository.confirmAllocation(
|
||||||
|
token: token,
|
||||||
|
allocation: allocationRequest,
|
||||||
|
),
|
||||||
|
throwsA(isA<Exception>()),
|
||||||
|
);
|
||||||
|
|
||||||
|
verify(
|
||||||
|
() => mockRemote.confirmAllocation(
|
||||||
|
token: token,
|
||||||
|
allocation: allocationRequest,
|
||||||
|
),
|
||||||
|
).called(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
221
packages/chicken/test/presentation/utils/string_utils_test.dart
Normal file
221
packages/chicken/test/presentation/utils/string_utils_test.dart
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:rasadyar_chicken/presentation/utils/string_utils.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('XStringUtils', () {
|
||||||
|
group('faAllocationType', () {
|
||||||
|
test('should convert simple string using utilsMap', () {
|
||||||
|
// Arrange
|
||||||
|
const input = 'killhouse';
|
||||||
|
const expected = 'کشتارگاه به';
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = input.faAllocationType;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, equals(expected));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should convert string with underscore using utilsMap', () {
|
||||||
|
// Arrange
|
||||||
|
const input = 'steward_exclusive';
|
||||||
|
const expected = 'مباشر به اختصاصی';
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = input.faAllocationType;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, equals(expected));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return original string when not found in utilsMap', () {
|
||||||
|
// Arrange
|
||||||
|
const input = 'unknown_string';
|
||||||
|
const expected = 'unknown به string';
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = input.faAllocationType;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, equals(expected));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle single word without underscore', () {
|
||||||
|
// Arrange
|
||||||
|
const input = 'free';
|
||||||
|
const expected = 'آزاد به';
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = input.faAllocationType;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, equals(expected));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle multiple underscores correctly', () {
|
||||||
|
// Arrange
|
||||||
|
const input = 'steward_exclusive_guild';
|
||||||
|
const expected = 'مباشر به اختصاصی صنف';
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = input.faAllocationType;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, equals(expected));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('faItem', () {
|
||||||
|
test('should convert string using utilsMap', () {
|
||||||
|
// Arrange
|
||||||
|
const input = 'pending';
|
||||||
|
const expected = 'در انتظار';
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = input.faItem;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, equals(expected));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return original string when not found in utilsMap', () {
|
||||||
|
// Arrange
|
||||||
|
const input = 'unknown_item';
|
||||||
|
const expected = 'unknown_item';
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = input.faItem;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, equals(expected));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle empty string', () {
|
||||||
|
// Arrange
|
||||||
|
const input = '';
|
||||||
|
const expected = '';
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = input.faItem;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, equals(expected));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('buyerIsGuild', () {
|
||||||
|
test('should return true when last part is guild', () {
|
||||||
|
// Arrange
|
||||||
|
const input = 'steward_exclusive_guild';
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = input.buyerIsGuild;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return false when last part is not guild', () {
|
||||||
|
// Arrange
|
||||||
|
const input = 'steward_exclusive_governmental';
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = input.buyerIsGuild;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return false for single word', () {
|
||||||
|
// Arrange
|
||||||
|
const input = 'guild';
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = input.buyerIsGuild;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return false for empty string', () {
|
||||||
|
// Arrange
|
||||||
|
const input = '';
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = input.buyerIsGuild;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, isFalse);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('faTitle', () {
|
||||||
|
test('should convert string using utilsMap', () {
|
||||||
|
// Arrange
|
||||||
|
const input = 'accepted';
|
||||||
|
const expected = 'تایید شده';
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = input.faTitle;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, equals(expected));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return original string when not found in utilsMap', () {
|
||||||
|
// Arrange
|
||||||
|
const input = 'unknown_title';
|
||||||
|
const expected = 'unknown_title';
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = input.faTitle;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, equals(expected));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should handle empty string', () {
|
||||||
|
// Arrange
|
||||||
|
const input = '';
|
||||||
|
const expected = '';
|
||||||
|
|
||||||
|
// Act
|
||||||
|
final result = input.faTitle;
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(result, equals(expected));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('utilsMap', () {
|
||||||
|
test('should contain expected key-value pairs', () {
|
||||||
|
// Assert
|
||||||
|
expect(utilsMap['killhouse'], equals('کشتارگاه'));
|
||||||
|
expect(utilsMap['_'], equals('به'));
|
||||||
|
expect(utilsMap['steward'], equals('مباشر'));
|
||||||
|
expect(utilsMap['exclusive'], equals('اختصاصی'));
|
||||||
|
expect(utilsMap['free'], equals('آزاد'));
|
||||||
|
expect(utilsMap['pending'], equals('در انتظار'));
|
||||||
|
expect(utilsMap['accepted'], equals('تایید شده'));
|
||||||
|
expect(utilsMap['guild'], equals('صنف'));
|
||||||
|
expect(utilsMap['governmental'], equals('دولتی'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should not be empty', () {
|
||||||
|
// Assert
|
||||||
|
expect(utilsMap.isNotEmpty, isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should have consistent key-value pairs', () {
|
||||||
|
// Assert
|
||||||
|
expect(utilsMap.length, equals(9));
|
||||||
|
expect(utilsMap.keys, contains('killhouse'));
|
||||||
|
expect(utilsMap.keys, contains('steward'));
|
||||||
|
expect(utilsMap.keys, contains('guild'));
|
||||||
|
expect(utilsMap.values, contains('کشتارگاه'));
|
||||||
|
expect(utilsMap.values, contains('مباشر'));
|
||||||
|
expect(utilsMap.values, contains('صنف'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
11
packages/chicken/test/run_tests.dart
Normal file
11
packages/chicken/test/run_tests.dart
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('Chicken Package Test Suite', () {
|
||||||
|
test('Test suite placeholder', () {
|
||||||
|
// This file serves as a test runner for the entire chicken package
|
||||||
|
// Individual test files should be run separately
|
||||||
|
expect(true, isTrue);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
32
packages/chicken/test/test_config.dart
Normal file
32
packages/chicken/test/test_config.dart
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
/// Test configuration for the chicken package
|
||||||
|
class TestConfig {
|
||||||
|
static const String testToken = 'test-token-12345';
|
||||||
|
static const String testPhoneNumber = '09123456789';
|
||||||
|
static const String testDeviceName = 'Test Device';
|
||||||
|
|
||||||
|
static const Map<String, dynamic> testAuthRequest = {
|
||||||
|
'username': 'test@example.com',
|
||||||
|
'password': 'testpassword123',
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Map<String, dynamic> testQueryParameters = {
|
||||||
|
'page': '1',
|
||||||
|
'limit': '10',
|
||||||
|
};
|
||||||
|
|
||||||
|
static const String testStartDate = '2024-01-01';
|
||||||
|
static const String testEndDate = '2024-01-31';
|
||||||
|
|
||||||
|
/// Setup method for test initialization
|
||||||
|
static void setupTests() {
|
||||||
|
// Configure test environment
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cleanup method for test teardown
|
||||||
|
static void cleanupTests() {
|
||||||
|
// Clean up test resources
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user