feat(tests): test coverage is 70.4

This commit is contained in:
misha
2026-01-23 12:40:17 +03:00
parent f6809a06b3
commit 92205c09d6
38 changed files with 1829 additions and 133 deletions

View File

@@ -0,0 +1,150 @@
import 'package:eatvio_app/features/auth/models/oauth_verification_confirm_request.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('OAuthVerificationConfirmRequest', () {
test('creates instance with required fields', () {
const request = OAuthVerificationConfirmRequest(
accessToken: 'access_token_123',
refreshToken: 'refresh_token_123',
clientId: 'client_id_123',
provider: 'vk',
id: 'user_id_123',
code: 'code_123',
verificationType: 'email',
firstName: 'John',
lastName: 'Doe',
dateOfBirth: '1990-01-01',
gender: 'male',
weight: 70,
height: 180,
);
expect(request.accessToken, 'access_token_123');
expect(request.refreshToken, 'refresh_token_123');
expect(request.clientId, 'client_id_123');
expect(request.provider, 'vk');
expect(request.id, 'user_id_123');
expect(request.code, 'code_123');
expect(request.verificationType, 'email');
expect(request.firstName, 'John');
expect(request.lastName, 'Doe');
expect(request.dateOfBirth, '1990-01-01');
expect(request.gender, 'male');
expect(request.weight, 70);
expect(request.height, 180);
});
test('creates instance with optional email', () {
const request = OAuthVerificationConfirmRequest(
accessToken: 'access_token_123',
refreshToken: 'refresh_token_123',
clientId: 'client_id_123',
provider: 'vk',
id: 'user_id_123',
email: 'test@example.com',
code: 'code_123',
verificationType: 'email',
firstName: 'John',
lastName: 'Doe',
dateOfBirth: '1990-01-01',
gender: 'male',
weight: 70,
height: 180,
);
expect(request.email, 'test@example.com');
});
test('creates instance with optional phone', () {
const request = OAuthVerificationConfirmRequest(
accessToken: 'access_token_123',
refreshToken: 'refresh_token_123',
clientId: 'client_id_123',
provider: 'vk',
id: 'user_id_123',
phone: '+79991234567',
code: 'code_123',
verificationType: 'phone',
firstName: 'John',
lastName: 'Doe',
dateOfBirth: '1990-01-01',
gender: 'male',
weight: 70,
height: 180,
);
expect(request.phone, '+79991234567');
});
test('fromJson creates instance from JSON', () {
final json = {
'access_token': 'access_token_123',
'refresh_token': 'refresh_token_123',
'client_id': 'client_id_123',
'provider': 'vk',
'id': 'user_id_123',
'code': 'code_123',
'verification_type': 'email',
'first_name': 'John',
'last_name': 'Doe',
'date_of_birth': '1990-01-01',
'gender': 'male',
'weight': 70,
'height': 180,
};
final request = OAuthVerificationConfirmRequest.fromJson(json);
expect(request.accessToken, 'access_token_123');
expect(request.refreshToken, 'refresh_token_123');
expect(request.clientId, 'client_id_123');
expect(request.provider, 'vk');
expect(request.id, 'user_id_123');
expect(request.code, 'code_123');
expect(request.verificationType, 'email');
expect(request.firstName, 'John');
expect(request.lastName, 'Doe');
expect(request.dateOfBirth, '1990-01-01');
expect(request.gender, 'male');
expect(request.weight, 70);
expect(request.height, 180);
});
test('toJson converts instance to JSON', () {
const request = OAuthVerificationConfirmRequest(
accessToken: 'access_token_123',
refreshToken: 'refresh_token_123',
clientId: 'client_id_123',
provider: 'vk',
id: 'user_id_123',
email: 'test@example.com',
code: 'code_123',
verificationType: 'email',
firstName: 'John',
lastName: 'Doe',
dateOfBirth: '1990-01-01',
gender: 'male',
weight: 70,
height: 180,
);
final json = request.toJson();
expect(json['access_token'], 'access_token_123');
expect(json['refresh_token'], 'refresh_token_123');
expect(json['client_id'], 'client_id_123');
expect(json['provider'], 'vk');
expect(json['id'], 'user_id_123');
expect(json['email'], 'test@example.com');
expect(json['code'], 'code_123');
expect(json['verification_type'], 'email');
expect(json['first_name'], 'John');
expect(json['last_name'], 'Doe');
expect(json['date_of_birth'], '1990-01-01');
expect(json['gender'], 'male');
expect(json['weight'], 70);
expect(json['height'], 180);
});
});
}

View File

@@ -0,0 +1,97 @@
import 'package:eatvio_app/features/auth/models/oauth_verification_confirm_response.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('OAuthVerificationConfirmResponse', () {
test('creates instance with required fields', () {
const response = OAuthVerificationConfirmResponse(
success: true,
message: 'Success',
token: 'token_123',
user: {'id': 1, 'name': 'John'},
isNewUser: false,
);
expect(response.success, true);
expect(response.message, 'Success');
expect(response.token, 'token_123');
expect(response.user, {'id': 1, 'name': 'John'});
expect(response.isNewUser, false);
});
test('creates instance with isNewUser true', () {
const response = OAuthVerificationConfirmResponse(
success: true,
message: 'New user created',
token: 'token_123',
user: {'id': 1, 'name': 'John'},
isNewUser: true,
);
expect(response.isNewUser, true);
});
test('fromJson creates instance from JSON', () {
final json = {
'success': true,
'message': 'Success',
'token': 'token_123',
'user': {'id': 1, 'name': 'John'},
'is_new_user': false,
};
final response = OAuthVerificationConfirmResponse.fromJson(json);
expect(response.success, true);
expect(response.message, 'Success');
expect(response.token, 'token_123');
expect(response.user, {'id': 1, 'name': 'John'});
expect(response.isNewUser, false);
});
test('toJson converts instance to JSON', () {
const response = OAuthVerificationConfirmResponse(
success: true,
message: 'Success',
token: 'token_123',
user: {'id': 1, 'name': 'John'},
isNewUser: false,
);
final json = response.toJson();
expect(json['success'], true);
expect(json['message'], 'Success');
expect(json['token'], 'token_123');
expect(json['user'], {'id': 1, 'name': 'John'});
expect(json['is_new_user'], false);
});
test('equality works correctly', () {
const response1 = OAuthVerificationConfirmResponse(
success: true,
message: 'Success',
token: 'token_123',
user: {'id': 1},
isNewUser: false,
);
const response2 = OAuthVerificationConfirmResponse(
success: true,
message: 'Success',
token: 'token_123',
user: {'id': 1},
isNewUser: false,
);
const response3 = OAuthVerificationConfirmResponse(
success: false,
message: 'Error',
token: 'token_123',
user: {'id': 1},
isNewUser: false,
);
expect(response1, equals(response2));
expect(response1, isNot(equals(response3)));
});
});
}

View File

@@ -0,0 +1,58 @@
import 'package:eatvio_app/features/auth/models/oauth_verification_request_response.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('OAuthVerificationRequestResponse', () {
test('creates instance with required fields', () {
const response = OAuthVerificationRequestResponse(
email: 'test@example.com',
status: 'pending',
);
expect(response.email, 'test@example.com');
expect(response.status, 'pending');
});
test('fromJson creates instance from JSON', () {
final json = {
'email': 'test@example.com',
'status': 'pending',
};
final response = OAuthVerificationRequestResponse.fromJson(json);
expect(response.email, 'test@example.com');
expect(response.status, 'pending');
});
test('toJson converts instance to JSON', () {
const response = OAuthVerificationRequestResponse(
email: 'test@example.com',
status: 'pending',
);
final json = response.toJson();
expect(json['email'], 'test@example.com');
expect(json['status'], 'pending');
});
test('equality works correctly', () {
const response1 = OAuthVerificationRequestResponse(
email: 'test@example.com',
status: 'pending',
);
const response2 = OAuthVerificationRequestResponse(
email: 'test@example.com',
status: 'pending',
);
const response3 = OAuthVerificationRequestResponse(
email: 'other@example.com',
status: 'pending',
);
expect(response1, equals(response2));
expect(response1, isNot(equals(response3)));
});
});
}

View File

@@ -0,0 +1,43 @@
import 'package:eatvio_app/core/app_config.dart';
import 'package:eatvio_app/core/app_initializer.dart';
import 'package:eatvio_app/core/locator_service.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/features/auth/presentation/pages/scan_qr_code_screen.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('ScanQRCodeScreen smoke', () {
setUpAll(() async {
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'));
});
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: child,
);
}
testWidgets('renders scan QR code screen', (tester) async {
await tester.pumpWidget(wrap(const ScanQRCodeScreen()));
await tester.pumpAndSettle();
expect(find.byType(ScanQRCodeScreen), findsOneWidget);
expect(find.text('Сканирование QR-кода'), findsOneWidget);
});
testWidgets('displays QR scanner UI', (tester) async {
await tester.pumpWidget(wrap(const ScanQRCodeScreen()));
await tester.pumpAndSettle();
expect(find.byType(ScanQRCodeScreen), findsOneWidget);
});
});
}

View File

@@ -17,6 +17,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:go_router/go_router.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:network_image_mock/network_image_mock.dart';
import 'blog_post_screen_smoke_test.mocks.dart';
@@ -105,5 +106,58 @@ void main() {
expect(find.byType(BlogPostScreen), findsOneWidget);
});
testWidgets('renders error state', (tester) async {
await mockNetworkImagesFor(() async {
final blogPostCubit = MockBlogPostCubit();
final feedCubit = MockFeedCubit();
final commentsCubit = MockCommentsCubit();
final state = BlogPostState(isLoading: false, blogPostModel: null, error: 'Test error');
when(blogPostCubit.state).thenReturn(state);
when(blogPostCubit.stream).thenAnswer((_) => Stream.value(state));
when(blogPostCubit.close()).thenAnswer((_) async => Future<void>.value());
when(feedCubit.viewPost(any)).thenAnswer((_) async => Future<void>.value());
when(feedCubit.stream).thenAnswer((_) => const Stream.empty());
when(feedCubit.close()).thenAnswer((_) async => Future<void>.value());
when(commentsCubit.state).thenReturn(const CommentsState());
when(commentsCubit.stream).thenAnswer((_) => const Stream<CommentsState>.empty());
when(commentsCubit.close()).thenAnswer((_) async => Future<void>.value());
when(commentsCubit.getComments(any, any, any)).thenAnswer((_) async => Future<void>.value());
registerMocks(blogPostCubit, commentsCubit);
await tester.pumpWidget(wrap(blogPostCubit, feedCubit, commentsCubit, const BlogPostScreen(id: 1)));
await tester.pump();
expect(find.byType(BlogPostScreen), findsOneWidget);
});
});
testWidgets('renders loaded state', (tester) async {
await mockNetworkImagesFor(() async {
final blogPostCubit = MockBlogPostCubit();
final feedCubit = MockFeedCubit();
final commentsCubit = MockCommentsCubit();
final state = BlogPostState(isLoading: false, blogPostModel: null, error: null);
when(blogPostCubit.state).thenReturn(state);
when(blogPostCubit.stream).thenAnswer((_) => Stream.value(state));
when(blogPostCubit.close()).thenAnswer((_) async => Future<void>.value());
when(feedCubit.viewPost(any)).thenAnswer((_) async => Future<void>.value());
when(feedCubit.stream).thenAnswer((_) => const Stream.empty());
when(feedCubit.close()).thenAnswer((_) async => Future<void>.value());
when(commentsCubit.state).thenReturn(const CommentsState());
when(commentsCubit.stream).thenAnswer((_) => const Stream<CommentsState>.empty());
when(commentsCubit.close()).thenAnswer((_) async => Future<void>.value());
when(commentsCubit.getComments(any, any, any)).thenAnswer((_) async => Future<void>.value());
registerMocks(blogPostCubit, commentsCubit);
await tester.pumpWidget(wrap(blogPostCubit, feedCubit, commentsCubit, const BlogPostScreen(id: 1)));
await tester.pump();
expect(find.byType(BlogPostScreen), findsOneWidget);
});
});
});
}

View File

@@ -0,0 +1,89 @@
import 'package:eatvio_app/core/app_config.dart';
import 'package:eatvio_app/core/app_initializer.dart';
import 'package:eatvio_app/core/enums/base_state.dart';
import 'package:eatvio_app/core/locator_service.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/features/consultations/presentation/cubit/consultations_cubit.dart';
import 'package:eatvio_app/features/consultations/presentation/cubit/consultations_state.dart';
import 'package:eatvio_app/features/consultations/presentation/pages/consultations_screen.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:go_router/go_router.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'consultations_screen_smoke_test.mocks.dart';
@GenerateNiceMocks([MockSpec<ConsultationsCubit>()])
void main() {
group('ConsultationsScreen smoke', () {
setUpAll(() async {
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'));
});
Widget wrap(Widget child, ConsultationsCubit cubit) {
return MaterialApp.router(
theme: ThemeHelper().themeData(),
routerConfig: GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => Scaffold(
body: BlocProvider<ConsultationsCubit>.value(value: cubit, child: child),
),
),
],
),
);
}
testWidgets('renders consultations screen', (tester) async {
final cubit = MockConsultationsCubit();
final state = ConsultationsState(state: BaseState.initial, consultations: []);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
await tester.pumpWidget(wrap(const ConsultationsContent(), cubit));
await tester.pump();
expect(find.byType(ConsultationsContent), findsOneWidget);
});
testWidgets('displays consultations title', (tester) async {
final cubit = MockConsultationsCubit();
final state = ConsultationsState(state: BaseState.success, consultations: []);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
await tester.pumpWidget(wrap(const ConsultationsContent(), cubit));
await tester.pump();
expect(find.text('Консультации'), findsOneWidget);
});
testWidgets('displays archive button when loaded', (tester) async {
final cubit = MockConsultationsCubit();
final state = ConsultationsState(state: BaseState.success, consultations: []);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
await tester.pumpWidget(wrap(const ConsultationsContent(), cubit));
await tester.pump();
expect(find.text('Архив консультаций'), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,43 @@
import 'package:eatvio_app/core/app_config.dart';
import 'package:eatvio_app/core/app_initializer.dart';
import 'package:eatvio_app/core/locator_service.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/features/dev_tools/presentation/dev_tools_screen.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('DevToolsScreen smoke', () {
setUpAll(() async {
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'));
});
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: child,
);
}
testWidgets('renders dev tools screen', (tester) async {
await tester.pumpWidget(wrap(const DevToolsScreen()));
await tester.pump();
expect(find.byType(DevToolsScreen), findsOneWidget);
expect(find.text('Для разработчиков'), findsOneWidget);
});
testWidgets('displays dev tools screen content', (tester) async {
await tester.pumpWidget(wrap(const DevToolsScreen()));
await tester.pump();
expect(find.byType(DevToolsScreenContent), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,45 @@
import 'package:eatvio_app/core/app_config.dart';
import 'package:eatvio_app/core/app_initializer.dart';
import 'package:eatvio_app/core/locator_service.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/features/diary/presentation/pages/barcode_scanner_screen.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('BarcodeScannerScreen smoke', () {
setUpAll(() async {
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'));
});
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: child,
);
}
testWidgets('renders barcode scanner screen', (tester) async {
await tester.pumpWidget(wrap(const BarcodeScannerScreen()));
await tester.pumpAndSettle();
expect(find.byType(BarcodeScannerScreen), findsOneWidget);
expect(find.text('Сканирование штрихкода'), findsOneWidget);
expect(find.text('Наведите камеру на штрихкод'), findsOneWidget);
});
testWidgets('displays barcode scanner UI elements', (tester) async {
await tester.pumpWidget(wrap(const BarcodeScannerScreen()));
await tester.pumpAndSettle();
expect(find.text('Найденный штрихкод'), findsOneWidget);
expect(find.text('Наведите камеру на штрихкод'), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,82 @@
import 'package:eatvio_app/core/app_config.dart';
import 'package:eatvio_app/core/app_initializer.dart';
import 'package:eatvio_app/core/locator_service.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/features/menu/presentation/blocked_user_cubit/blocked_users_cubit.dart';
import 'package:eatvio_app/features/menu/presentation/blocked_user_cubit/blocked_users_state.dart';
import 'package:eatvio_app/features/menu/presentation/pages/blocked_users_screen.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'blocked_users_screen_smoke_test.mocks.dart';
@GenerateNiceMocks([MockSpec<BlockedUsersCubit>()])
void main() {
group('BlockedUsersScreen smoke', () {
setUpAll(() async {
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'));
});
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('ru')],
home: child,
);
}
testWidgets('renders blocked users screen with loading state', (tester) async {
final cubit = MockBlockedUsersCubit();
const state = BlockedUsersStateLoading();
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.getBlockedUsers()).thenAnswer((_) async => Future<void>.value());
// Регистрируем cubit в sl, так как BlockedUsersScreen использует sl<BlockedUsersCubit>()
sl.registerFactory<BlockedUsersCubit>(() => cubit);
await tester.pumpWidget(wrap(const BlockedUsersScreen()));
await tester.pump();
expect(find.byType(BlockedUsersScreen), findsOneWidget);
expect(find.byType(CircularProgressIndicator), findsOneWidget);
});
testWidgets('renders blocked users screen with loaded state', (tester) async {
final cubit = MockBlockedUsersCubit();
const state = BlockedUsersStateLoaded(profilesList: []);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.getBlockedUsers()).thenAnswer((_) async => Future<void>.value());
// Регистрируем cubit в sl, так как BlockedUsersScreen использует sl<BlockedUsersCubit>()
sl.registerFactory<BlockedUsersCubit>(() => cubit);
await tester.pumpWidget(wrap(const BlockedUsersScreen()));
await tester.pump();
expect(find.byType(BlockedUsersScreen), findsOneWidget);
expect(find.text('Чёрный список'), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,88 @@
import 'package:eatvio_app/core/app_config.dart';
import 'package:eatvio_app/core/app_initializer.dart';
import 'package:eatvio_app/core/locator_service.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/features/personal_diet_suggestion/cubit/personal_diet_suggestion_cubit.dart';
import 'package:eatvio_app/features/personal_diet_suggestion/cubit/personal_diet_suggestion_state.dart';
import 'package:eatvio_app/features/personal_diet_suggestion/presentation/personal_diet_suggestion_screen.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'personal_diet_suggestion_screen_smoke_test.mocks.dart';
@GenerateNiceMocks([MockSpec<PersonalDietSuggestionCubit>()])
void main() {
group('PersonalDietSuggestionScreen smoke', () {
setUpAll(() async {
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'));
});
Widget wrap(Widget child, PersonalDietSuggestionCubit cubit) {
return MaterialApp(
theme: ThemeHelper().themeData(),
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('ru')],
home: Scaffold(
body: BlocProvider<PersonalDietSuggestionCubit>.value(
value: cubit,
child: child,
),
),
);
}
testWidgets('renders personal diet suggestion screen', (tester) async {
final cubit = MockPersonalDietSuggestionCubit();
final state = PersonalDietSuggestionState(
isLoading: true,
dietName: 'Test Diet',
consultationsWithDiet: [],
consultationsWithoutDiet: [],
);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
await tester.pumpWidget(wrap(const PersonalDietSuggestionScreenContent(), cubit));
await tester.pump();
expect(find.byType(PersonalDietSuggestionScreenContent), findsOneWidget);
});
testWidgets('displays diet name in app bar', (tester) async {
final cubit = MockPersonalDietSuggestionCubit();
final state = PersonalDietSuggestionState(
isLoading: false,
dietName: 'Test Diet Name',
consultationsWithDiet: [],
consultationsWithoutDiet: [],
);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
await tester.pumpWidget(wrap(const PersonalDietSuggestionScreenContent(), cubit));
await tester.pump();
expect(find.textContaining('Test Diet Name'), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,70 @@
import 'package:eatvio_app/core/app_config.dart';
import 'package:eatvio_app/core/app_initializer.dart';
import 'package:eatvio_app/core/locator_service.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/features/recipe/presentation/cubit/my_recipes_cubit/my_recieps_cubit.dart';
import 'package:eatvio_app/features/recipe/presentation/cubit/my_recipes_cubit/my_recipes_state.dart';
import 'package:eatvio_app/features/recipe/presentation/pages/my_recipes_screen.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'my_recipes_screen_smoke_test.mocks.dart';
@GenerateNiceMocks([MockSpec<MyRecipesCubit>()])
void main() {
group('MyRecipesScreen smoke', () {
setUpAll(() async {
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'));
});
Widget wrap(Widget child) {
return MaterialApp(theme: ThemeHelper().themeData(), home: child);
}
testWidgets('renders my recipes screen', (tester) async {
final cubit = MockMyRecipesCubit();
const state = MyRecipesStateLoading();
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.getMyRecipes()).thenAnswer((_) async => Future<void>.value());
// Регистрируем cubit в sl, так как MyRecipesScreen использует sl<MyRecipesCubit>()
sl.registerFactory<MyRecipesCubit>(() => cubit);
await tester.pumpWidget(wrap(const MyRecipesScreen()));
await tester.pump();
expect(find.byType(MyRecipesScreen), findsOneWidget);
expect(find.text('Мои рецепты'), findsOneWidget);
});
testWidgets('renders my recipes screen with loaded state', (tester) async {
final cubit = MockMyRecipesCubit();
const state = MyRecipesStateLoaded(recipes: [], selectedState: 'all');
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.getMyRecipes()).thenAnswer((_) async => Future<void>.value());
// Регистрируем cubit в sl, так как MyRecipesScreen использует sl<MyRecipesCubit>()
sl.registerFactory<MyRecipesCubit>(() => cubit);
await tester.pumpWidget(wrap(const MyRecipesScreen()));
await tester.pump();
expect(find.byType(MyRecipesScreen), findsOneWidget);
expect(find.text('Мои рецепты'), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,79 @@
import 'package:eatvio_app/core/app_config.dart';
import 'package:eatvio_app/core/app_initializer.dart';
import 'package:eatvio_app/core/locator_service.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/features/registration_v2/cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration_v2/cubit/registration_state.dart';
import 'package:eatvio_app/features/registration_v2/presentation/pages/registration_v2_page.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'registration_v2_page_smoke_test.mocks.dart';
@GenerateNiceMocks([MockSpec<RegistrationCubitV2>()])
void main() {
group('RegistrationV2Page smoke', () {
setUpAll(() async {
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'));
});
Widget wrap(Widget child, RegistrationCubitV2 cubit) {
sl.registerLazySingleton<RegistrationCubitV2>(() => cubit);
return MaterialApp(
theme: ThemeHelper().themeData(),
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('ru')],
home: Scaffold(
body: BlocProvider<RegistrationCubitV2>.value(
value: cubit,
child: child,
),
),
);
}
testWidgets('renders registration v2 page', (tester) async {
final cubit = MockRegistrationCubitV2();
const state = RegistrationStateV2(step: 0);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
await tester.pumpWidget(wrap(const RegistrationV2Page(), cubit));
await tester.pump();
expect(find.byType(RegistrationV2Page), findsOneWidget);
});
testWidgets('displays step progress', (tester) async {
final cubit = MockRegistrationCubitV2();
const state = RegistrationStateV2(step: 0);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
await tester.pumpWidget(wrap(const RegistrationV2Page(), cubit));
await tester.pump();
expect(find.byType(RegistrationV2PageContent), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,66 @@
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/features/registration_v2/cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration_v2/cubit/registration_state.dart';
import 'package:eatvio_app/features/registration_v2/presentation/widgets/phisical_activity.dart';
import 'package:eatvio_app/generated/l10n.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'step_widget_test.mocks.dart';
void main() {
group('PhisicalActivity', () {
late MockRegistrationCubitV2 mockCubit;
setUp(() {
mockCubit = MockRegistrationCubitV2();
});
Widget createTestWidget() {
return MaterialApp(
theme: ThemeHelper().themeData(),
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('ru'), Locale('en')],
locale: const Locale('ru'),
home: BlocProvider<RegistrationCubitV2>.value(
value: mockCubit,
child: const Scaffold(
body: PhisicalActivity(),
),
),
);
}
testWidgets('displays phisical activity widget', (tester) async {
when(mockCubit.state).thenReturn(
const RegistrationStateV2(activityCoefficient: 1.2),
);
when(mockCubit.stream).thenAnswer((_) => Stream.value(const RegistrationStateV2(activityCoefficient: 1.2)));
await tester.pumpWidget(createTestWidget());
await tester.pump();
expect(find.byType(PhisicalActivity), findsOneWidget);
});
testWidgets('displays phisical activity with different coefficient', (tester) async {
when(mockCubit.state).thenReturn(
const RegistrationStateV2(activityCoefficient: 1.55),
);
when(mockCubit.stream).thenAnswer((_) => Stream.value(const RegistrationStateV2(activityCoefficient: 1.55)));
await tester.pumpWidget(createTestWidget());
await tester.pump();
expect(find.byType(PhisicalActivity), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,84 @@
import 'package:eatvio_app/core/app_config.dart';
import 'package:eatvio_app/core/app_initializer.dart';
import 'package:eatvio_app/core/locator_service.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/features/registration_v2/cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration_v2/cubit/registration_state.dart';
import 'package:eatvio_app/features/registration_v2/presentation/widgets/step_progress.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'step_progress_test.mocks.dart';
@GenerateNiceMocks([MockSpec<RegistrationCubitV2>()])
void main() {
group('StepProgress smoke', () {
setUpAll(() async {
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'));
});
Widget wrap(Widget child, RegistrationCubitV2 cubit) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: Scaffold(
body: BlocProvider<RegistrationCubitV2>.value(
value: cubit,
child: child,
),
),
);
}
testWidgets('renders step progress widget', (tester) async {
final cubit = MockRegistrationCubitV2();
const state = RegistrationStateV2(step: 0);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
await tester.pumpWidget(wrap(const StepProgress(), cubit));
await tester.pump();
expect(find.byType(StepProgress), findsOneWidget);
expect(find.byType(LinearProgressIndicator), findsOneWidget);
});
testWidgets('displays progress indicator for step 0', (tester) async {
final cubit = MockRegistrationCubitV2();
const state = RegistrationStateV2(step: 0);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
await tester.pumpWidget(wrap(const StepProgress(), cubit));
await tester.pump();
expect(find.byType(LinearProgressIndicator), findsOneWidget);
});
testWidgets('displays progress indicator for step 1', (tester) async {
final cubit = MockRegistrationCubitV2();
const state = RegistrationStateV2(step: 1);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
await tester.pumpWidget(wrap(const StepProgress(), cubit));
await tester.pump();
expect(find.byType(LinearProgressIndicator), findsOneWidget);
});
});
}

View File

@@ -1,11 +1,14 @@
import 'package:dio/dio.dart';
import 'package:eatvio_app/features/registration_v2/models/registration_model.dart';
import 'package:eatvio_app/features/registration_v2/repositories/registration_repository_v2.dart';
import 'package:eatvio_app/features/registration_v2/services/registration_service_v2.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
class MockRegistrationServiceV2 extends Mock implements RegistrationServiceV2 {}
import 'registration_repository_v2_test.mocks.dart';
@GenerateMocks([RegistrationServiceV2])
void main() {
group('RegistrationRepositoryV2', () {
late RegistrationRepositoryV2 repository;
@@ -16,73 +19,79 @@ void main() {
repository = RegistrationRepositoryV2(registrationService: mockService);
});
test('register - успешная регистрация возвращает токен', () async {
const token = 'test-token-123';
test('register - успешная регистрация', () async {
const token = 'test_token_123';
final registrationModel = RegistrationModel(
firstName: 'Test',
lastName: 'User',
firstName: 'John',
lastName: 'Doe',
email: 'test@example.com',
phone: '+1234567890',
phone: '+79991234567',
gender: 'male',
password: 'password123',
confirmPassword: 'password123',
weight: 70,
height: 175,
activityCoefficient: 1.5,
height: 180,
activityCoefficient: 1.55,
birthday: '1990-01-01',
);
when(() => mockService.register(model: any(named: 'model')))
when(mockService.register(model: anyNamed('model')))
.thenAnswer((_) async => {'token': token});
final result = await repository.register(registrationModel: registrationModel);
expect(result, token);
verify(() => mockService.register(model: any(named: 'model'))).called(1);
verify(mockService.register(model: anyNamed('model'))).called(1);
});
test('register - возвращает null если токена нет', () async {
test('register - обработка ошибки', () async {
final registrationModel = RegistrationModel(
firstName: 'Test',
lastName: 'User',
firstName: 'John',
lastName: 'Doe',
email: 'test@example.com',
phone: '+1234567890',
phone: '+79991234567',
gender: 'male',
password: 'password123',
confirmPassword: 'password123',
weight: 70,
height: 175,
activityCoefficient: 1.5,
height: 180,
activityCoefficient: 1.55,
birthday: '1990-01-01',
);
when(() => mockService.register(model: any(named: 'model')))
when(mockService.register(model: anyNamed('model')))
.thenThrow(DioException(
requestOptions: RequestOptions(path: '/api/register'),
response: Response(
requestOptions: RequestOptions(path: '/api/register'),
statusCode: 400,
),
));
expect(() => repository.register(registrationModel: registrationModel), throwsA(isA<DioException>()));
});
test('register - возвращает null если токен отсутствует', () async {
final registrationModel = RegistrationModel(
firstName: 'John',
lastName: 'Doe',
email: 'test@example.com',
phone: '+79991234567',
gender: 'male',
password: 'password123',
confirmPassword: 'password123',
weight: 70,
height: 180,
activityCoefficient: 1.55,
birthday: '1990-01-01',
);
when(mockService.register(model: anyNamed('model')))
.thenAnswer((_) async => {});
final result = await repository.register(registrationModel: registrationModel);
expect(result, null);
});
test('register - пробрасывает ошибку', () async {
final registrationModel = RegistrationModel(
firstName: 'Test',
lastName: 'User',
email: 'test@example.com',
phone: '+1234567890',
gender: 'male',
password: 'password123',
confirmPassword: 'password123',
weight: 70,
height: 175,
activityCoefficient: 1.5,
birthday: '1990-01-01',
);
when(() => mockService.register(model: any(named: 'model')))
.thenThrow(Exception('Error'));
expect(() => repository.register(registrationModel: registrationModel), throwsException);
expect(result, isNull);
});
});
}

View File

@@ -0,0 +1,53 @@
import 'package:eatvio_app/core/app_config.dart';
import 'package:eatvio_app/core/app_initializer.dart';
import 'package:eatvio_app/core/locator_service.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/features/update_screen/presentation/update_screen.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
group('UpdateScreen smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost\nAPP_STORE_URL=https://apps.apple.com\nRUSTORE_URL=https://apps.rustore.ru');
});
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: child,
);
}
testWidgets('renders update screen', (tester) async {
await tester.pumpWidget(wrap(const UpdateScreen()));
await tester.pump();
expect(find.byType(UpdateScreen), findsOneWidget);
expect(find.text('Пора обновиться! ⚡'), findsOneWidget);
expect(find.text('Обновить'), findsOneWidget);
});
testWidgets('displays update message', (tester) async {
await tester.pumpWidget(wrap(const UpdateScreen()));
await tester.pump();
// Проверяем наличие текста об обновлении (может быть в многострочном тексте)
expect(find.textContaining('обновление'), findsWidgets);
});
testWidgets('displays update button', (tester) async {
await tester.pumpWidget(wrap(const UpdateScreen()));
await tester.pump();
expect(find.text('Обновить'), findsOneWidget);
expect(find.byType(InkWell), findsOneWidget);
});
});
}