forked from eatvio/eatvio_app
feat(insights): added kbju fetching for analitics
This commit is contained in:
@@ -4,9 +4,11 @@ import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/chat/repositories/chat_repository.dart';
|
||||
import 'package:eatvio_app/features/consultant/become_consultant/repositories/consultant_repository.dart';
|
||||
import 'package:eatvio_app/features/insights/presentation/widgets/insights_card.dart';
|
||||
import 'package:eatvio_app/features/insights/repositories/insights_repository.dart';
|
||||
import 'package:eatvio_app/features/profile/models/profile_model.dart';
|
||||
import 'package:eatvio_app/features/profile/presentation/bloc/plans_cubit/plans_cubit.dart' as profile_plans;
|
||||
import 'package:eatvio_app/features/profile/presentation/bloc/plans_cubit/plans_cubit.dart'
|
||||
as profile_plans;
|
||||
import 'package:eatvio_app/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart';
|
||||
import 'package:eatvio_app/features/profile/presentation/pages/profile_screen.dart';
|
||||
import 'package:eatvio_app/features/profile/repositories/profile_repository.dart';
|
||||
@@ -20,9 +22,15 @@ import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:network_image_mock/network_image_mock.dart';
|
||||
|
||||
import '../../../../fixtures/doubles/insights_doubles.dart';
|
||||
import 'profile_screen_smoke_test.mocks.dart';
|
||||
|
||||
@GenerateNiceMocks([MockSpec<ProfileRepository>(), MockSpec<ChatRepository>(), MockSpec<ConsultantRepository>(), MockSpec<PlansRepository>()])
|
||||
@GenerateNiceMocks([
|
||||
MockSpec<ProfileRepository>(),
|
||||
MockSpec<ChatRepository>(),
|
||||
MockSpec<ConsultantRepository>(),
|
||||
MockSpec<PlansRepository>(),
|
||||
])
|
||||
void main() {
|
||||
group('ProfileScreen smoke', () {
|
||||
late MockProfileRepository profileRepository;
|
||||
@@ -31,12 +39,18 @@ void main() {
|
||||
late MockPlansRepository plansRepository;
|
||||
|
||||
setUpAll(() async {
|
||||
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
|
||||
dotenv.loadFromString(
|
||||
envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost',
|
||||
);
|
||||
});
|
||||
|
||||
setUp(() async {
|
||||
await sl.reset();
|
||||
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
|
||||
sl.registerLazySingleton<AppConfig>(
|
||||
() =>
|
||||
AppConfig(buildType: AppBuildType.tests)
|
||||
..setBaseUrl('http://localhost'),
|
||||
);
|
||||
|
||||
profileRepository = MockProfileRepository();
|
||||
chatRepository = MockChatRepository();
|
||||
@@ -44,13 +58,25 @@ void main() {
|
||||
plansRepository = MockPlansRepository();
|
||||
|
||||
sl.registerLazySingleton<ProfileRepository>(() => profileRepository);
|
||||
sl.registerLazySingleton<InsightsRepository>(() => InsightsRepository(profileRepository: profileRepository));
|
||||
sl.registerLazySingleton<InsightsRepository>(
|
||||
() => FakeInsightsRepository(),
|
||||
);
|
||||
sl.registerLazySingleton<ChatRepository>(() => chatRepository);
|
||||
sl.registerLazySingleton<ConsultantRepository>(() => consultantRepository);
|
||||
sl.registerLazySingleton<ConsultantRepository>(
|
||||
() => consultantRepository,
|
||||
);
|
||||
sl.registerLazySingleton<PlansRepository>(() => plansRepository);
|
||||
|
||||
sl.registerFactory<ProfileCubit>(() => ProfileCubit(profileRepository: sl(), chatRepository: sl(), consultantRepository: sl()));
|
||||
sl.registerFactory<profile_plans.PlansCubit>(() => profile_plans.PlansCubit(plansRepository: sl()));
|
||||
sl.registerFactory<ProfileCubit>(
|
||||
() => ProfileCubit(
|
||||
profileRepository: sl(),
|
||||
chatRepository: sl(),
|
||||
consultantRepository: sl(),
|
||||
),
|
||||
);
|
||||
sl.registerFactory<profile_plans.PlansCubit>(
|
||||
() => profile_plans.PlansCubit(plansRepository: sl()),
|
||||
);
|
||||
});
|
||||
|
||||
Widget wrap(Widget child) {
|
||||
@@ -115,8 +141,12 @@ void main() {
|
||||
);
|
||||
|
||||
when(profileRepository.getMyProfile()).thenAnswer((_) async => profile);
|
||||
when(profileRepository.getMyProfileDetails()).thenAnswer((_) async => profileDetails);
|
||||
when(profileRepository.getBlogPostsByAuthorSlug(slug: anyNamed('slug'))).thenAnswer((_) async => []);
|
||||
when(
|
||||
profileRepository.getMyProfileDetails(),
|
||||
).thenAnswer((_) async => profileDetails);
|
||||
when(
|
||||
profileRepository.getBlogPostsByAuthorSlug(slug: anyNamed('slug')),
|
||||
).thenAnswer((_) async => []);
|
||||
|
||||
await mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(wrap(const ProfileScreen()));
|
||||
@@ -127,8 +157,12 @@ void main() {
|
||||
});
|
||||
|
||||
testWidgets('renders error state', (tester) async {
|
||||
when(profileRepository.getMyProfile()).thenThrow(Exception('Error loading profile'));
|
||||
when(profileRepository.getMyProfileDetails()).thenThrow(Exception('Error'));
|
||||
when(
|
||||
profileRepository.getMyProfile(),
|
||||
).thenThrow(Exception('Error loading profile'));
|
||||
when(
|
||||
profileRepository.getMyProfileDetails(),
|
||||
).thenThrow(Exception('Error'));
|
||||
|
||||
await tester.pumpWidget(wrap(const ProfileScreen()));
|
||||
await tester.pumpAndSettle();
|
||||
@@ -183,11 +217,19 @@ void main() {
|
||||
activityCoefficient: 1.5,
|
||||
);
|
||||
|
||||
when(profileRepository.getProfileBySlug(any)).thenAnswer((_) async => profile);
|
||||
when(
|
||||
profileRepository.getProfileBySlug(any),
|
||||
).thenAnswer((_) async => profile);
|
||||
when(profileRepository.getMyProfile()).thenAnswer((_) async => profile);
|
||||
when(profileRepository.getMyProfileDetails()).thenAnswer((_) async => profileDetails);
|
||||
when(profileRepository.getProfileDetailsBySlug(any)).thenAnswer((_) async => profileDetails);
|
||||
when(profileRepository.getBlogPostsByAuthorSlug(slug: anyNamed('slug'))).thenAnswer((_) async => []);
|
||||
when(
|
||||
profileRepository.getMyProfileDetails(),
|
||||
).thenAnswer((_) async => profileDetails);
|
||||
when(
|
||||
profileRepository.getProfileDetailsBySlug(any),
|
||||
).thenAnswer((_) async => profileDetails);
|
||||
when(
|
||||
profileRepository.getBlogPostsByAuthorSlug(slug: anyNamed('slug')),
|
||||
).thenAnswer((_) async => []);
|
||||
|
||||
await mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(wrap(const ProfileScreen(slug: 'test-user')));
|
||||
@@ -195,7 +237,159 @@ void main() {
|
||||
});
|
||||
|
||||
expect(find.byType(ProfileScreen), findsOneWidget);
|
||||
expect(find.text('Пользователь ограничил доступ к своей странице'), findsOneWidget);
|
||||
expect(
|
||||
find.text('Пользователь ограничил доступ к своей странице'),
|
||||
findsOneWidget,
|
||||
);
|
||||
});
|
||||
group('аналитика (InsightsCard)', () {
|
||||
ProfileModel profileOf(
|
||||
String slug, {
|
||||
bool blockedByMe = false,
|
||||
bool blockedByAuthor = false,
|
||||
}) => ProfileModel(
|
||||
id: 1,
|
||||
name: 'Test User',
|
||||
email: 'test@example.com',
|
||||
phoneConfirmationState: 'confirmed',
|
||||
slug: slug,
|
||||
isPublicProfile: true,
|
||||
isBlockedByMe: blockedByMe,
|
||||
isBlockedByAuthor: blockedByAuthor,
|
||||
isBlockedByUser: false,
|
||||
isEntitySubscribedByMe: false,
|
||||
profilePhotoUrl: '',
|
||||
roles: const [],
|
||||
badges: const [],
|
||||
subscriptions: const [],
|
||||
subscribers: const [],
|
||||
);
|
||||
|
||||
const details = ProfileDetailsModel(
|
||||
firstName: 'Test',
|
||||
lastName: 'User',
|
||||
birthdate: '1990-01-01',
|
||||
gender: 'male',
|
||||
country: 'Russia',
|
||||
city: 'Moscow',
|
||||
lang: 'ru',
|
||||
weight: 70.0,
|
||||
height: 175,
|
||||
chestCircumference: 100,
|
||||
waistCircumference: 80,
|
||||
hipCircumference: 90,
|
||||
bloodPressureUp: 120,
|
||||
bloodPressureDown: 80,
|
||||
hasHypo: false,
|
||||
hasHyper: false,
|
||||
aboutAlergy: '',
|
||||
aboutTakingPils: '',
|
||||
aboutSportHobbies: '',
|
||||
favoriteFoods: '',
|
||||
unfavoriteFoods: '',
|
||||
additionalInfo: '',
|
||||
isMoodFillable: true,
|
||||
isBedtimeFillable: true,
|
||||
activityCoefficient: 1.5,
|
||||
);
|
||||
|
||||
Future<FakeInsightsRepository> pumpProfile(
|
||||
WidgetTester tester, {
|
||||
required ProfileModel viewed,
|
||||
String? slug,
|
||||
Object? insightsError,
|
||||
}) async {
|
||||
final insights = FakeInsightsRepository(error: insightsError);
|
||||
sl.unregister<InsightsRepository>();
|
||||
sl.registerLazySingleton<InsightsRepository>(() => insights);
|
||||
when(
|
||||
profileRepository.getProfileBySlug(any),
|
||||
).thenAnswer((_) async => viewed);
|
||||
when(
|
||||
profileRepository.getMyProfile(),
|
||||
).thenAnswer((_) async => profileOf('me'));
|
||||
when(
|
||||
profileRepository.getMyProfileDetails(),
|
||||
).thenAnswer((_) async => details);
|
||||
when(
|
||||
profileRepository.getProfileDetailsBySlug(any),
|
||||
).thenAnswer((_) async => details);
|
||||
when(
|
||||
profileRepository.getBlogPostsByAuthorSlug(slug: anyNamed('slug')),
|
||||
).thenAnswer((_) async => []);
|
||||
|
||||
await mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(wrap(ProfileScreen(slug: slug)));
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
return insights;
|
||||
}
|
||||
|
||||
testWidgets('собственный профиль: свои данные и кнопка добавления', (
|
||||
tester,
|
||||
) async {
|
||||
final insights = await pumpProfile(tester, viewed: profileOf('me'));
|
||||
|
||||
final card = tester.widget<InsightsCard>(find.byType(InsightsCard));
|
||||
expect(card.slug, isNull);
|
||||
expect(card.canAdd, isTrue);
|
||||
expect(insights.serverRequests.single.slug, isNull);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'чужой профиль (консультант → клиент): данные по slug без кнопки добавления',
|
||||
(tester) async {
|
||||
final insights = await pumpProfile(
|
||||
tester,
|
||||
viewed: profileOf('client'),
|
||||
slug: 'client',
|
||||
);
|
||||
|
||||
final card = tester.widget<InsightsCard>(find.byType(InsightsCard));
|
||||
expect(card.slug, 'client');
|
||||
expect(card.canAdd, isFalse);
|
||||
expect(insights.serverRequests.single.slug, 'client');
|
||||
expect(find.byKey(const Key('insights_card')), findsOneWidget);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets('чужой профиль: 403 скрывает блок', (tester) async {
|
||||
await pumpProfile(
|
||||
tester,
|
||||
viewed: profileOf('client'),
|
||||
slug: 'client',
|
||||
insightsError: const InsightsForbidden(),
|
||||
);
|
||||
|
||||
expect(find.byKey(const Key('insights_card')), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'профиль, заблокированный мной, не показывает аналитику и не запрашивает её',
|
||||
(tester) async {
|
||||
final insights = await pumpProfile(
|
||||
tester,
|
||||
viewed: profileOf('client', blockedByMe: true),
|
||||
slug: 'client',
|
||||
);
|
||||
|
||||
expect(find.byType(InsightsCard), findsNothing);
|
||||
expect(insights.serverRequests, isEmpty);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets('профиль, ограничивший доступ, не показывает аналитику', (
|
||||
tester,
|
||||
) async {
|
||||
final insights = await pumpProfile(
|
||||
tester,
|
||||
viewed: profileOf('client', blockedByAuthor: true),
|
||||
slug: 'client',
|
||||
);
|
||||
|
||||
expect(find.byType(InsightsCard), findsNothing);
|
||||
expect(insights.serverRequests, isEmpty);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user