feat(tests): increased tests coverage

This commit is contained in:
misha
2025-12-25 12:56:38 +03:00
parent 5b705dfb72
commit 99659f7ea1
132 changed files with 10304 additions and 6226 deletions

View File

@@ -1,245 +1,86 @@
import 'package:eatvio_app/core/prefs.dart';
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/models/user_registration_model.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_state.dart';
import 'package:eatvio_app/features/registration/presentation/pages/additional_information_screen.dart';
import 'package:eatvio_app/features/registration/repositories/registration_repository.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 'additional_information_screen_test.mocks.dart';
@GenerateMocks([RegistrationRepository, Prefs])
@GenerateNiceMocks([MockSpec<RegistrationCubit>()])
void main() {
group('AdditionalInformationScreen', () {
late MockRegistrationRepository mockRegistrationRepository;
late RegistrationCubit registrationCubit;
setUp(() {
mockRegistrationRepository = MockRegistrationRepository();
registrationCubit = RegistrationCubit(
registrationRepository: mockRegistrationRepository,
prefs: MockPrefs(),
);
group('AdditionalInformationScreen smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
tearDown(() {
registrationCubit.close();
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget createTestWidget(UserRegistrationSheet sheet) {
const mockSheet = UserRegistrationSheet(
firstName: '',
lastName: '',
email: '',
password: '',
passwordConfirmation: '',
birthdate: '',
gender: '',
location: '',
responseBody: '{}',
lang: 'ru',
weight: 0,
height: 0,
phone: '',
chestCircumference: 0,
waistCircumference: 0,
hipCircumference: 0,
bloodPressureUp: 0,
bloodPressureDown: 0,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: Scaffold(
body: BlocProvider<RegistrationCubit>(
create: (context) => registrationCubit,
child: AdditionalInformationScreen(sheet: sheet),
),
),
home: Scaffold(body: child),
);
}
testWidgets('displays screen with initial text from sheet', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'I am a vegetarian',
);
testWidgets('renders additional information screen', (tester) async {
final cubit = MockRegistrationCubit();
const state = RegistrationState(sheet: mockSheet);
await tester.pumpWidget(createTestWidget(sheet));
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.updateSheet(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<RegistrationCubit>.value(
value: cubit,
child: wrap(const AdditionalInformationScreen(sheet: mockSheet)),
),
);
await tester.pumpAndSettle();
expect(find.text('I am a vegetarian'), findsOneWidget);
});
testWidgets('displays label text', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: '',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
// Check that the label contains "Дополнительная информация"
expect(find.textContaining('Дополнительная информация'), findsOneWidget);
expect(find.textContaining('не обязательно'), findsOneWidget);
});
testWidgets('updates registration cubit when text changes', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'Initial info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textField = find.byType(TextField);
expect(textField, findsOneWidget);
await tester.enterText(textField, 'Updated information');
await tester.pump();
// Verify that the cubit state was updated
expect(registrationCubit.state.sheet.additionalInfo, 'Updated information');
});
testWidgets('limits text input to 250 characters', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: '',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textField = find.byType(TextField);
expect(textField, findsOneWidget);
// Try to enter more than 250 characters
final longText = 'a' * 300;
await tester.enterText(textField, longText);
await tester.pump();
// The text should be limited to 250 characters
final textFieldWidget = tester.widget<TextField>(textField);
expect(textFieldWidget.controller?.text.length, lessThanOrEqualTo(250));
});
testWidgets('displays empty text field when sheet has empty additionalInfo', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: '',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textField = find.byType(TextField);
expect(textField, findsOneWidget);
expect(find.byType(AdditionalInformationScreen), findsOneWidget);
});
});
}

View File

@@ -1,37 +1,64 @@
import 'package:eatvio_app/core/prefs.dart';
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/models/user_registration_model.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_state.dart';
import 'package:eatvio_app/features/registration/presentation/pages/allergies_screen.dart';
import 'package:eatvio_app/features/registration/repositories/registration_repository.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 'allergies_screen_test.mocks.dart';
@GenerateMocks([RegistrationRepository, Prefs])
@GenerateNiceMocks([MockSpec<RegistrationCubit>()])
void main() {
group('AllergiesScreen', () {
late MockRegistrationRepository mockRegistrationRepository;
late RegistrationCubit registrationCubit;
setUp(() {
mockRegistrationRepository = MockRegistrationRepository();
registrationCubit = RegistrationCubit(
registrationRepository: mockRegistrationRepository,
prefs: MockPrefs(),
);
group('AllergiesScreen smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
tearDown(() {
registrationCubit.close();
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget createTestWidget(UserRegistrationSheet sheet) {
const mockSheet = UserRegistrationSheet(
firstName: '',
lastName: '',
email: '',
password: '',
passwordConfirmation: '',
birthdate: '',
gender: '',
location: '',
responseBody: '{}',
lang: 'ru',
weight: 0,
height: 0,
phone: '',
chestCircumference: 0,
waistCircumference: 0,
hipCircumference: 0,
bloodPressureUp: 0,
bloodPressureDown: 0,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
localizationsDelegates: const [
@@ -41,167 +68,28 @@ void main() {
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('ru')],
home: Scaffold(
body: BlocProvider<RegistrationCubit>(
create: (context) => registrationCubit,
child: AllergiesScreen(sheet: sheet),
),
),
home: Scaffold(body: child),
);
}
testWidgets('displays screen with initial allergy information from sheet', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'Nuts, honey',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
testWidgets('renders allergies screen', (tester) async {
final cubit = MockRegistrationCubit();
const state = RegistrationState(sheet: mockSheet);
await tester.pumpWidget(createTestWidget(sheet));
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.updateSheet(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<RegistrationCubit>.value(
value: cubit,
child: wrap(const AllergiesScreen(sheet: mockSheet)),
),
);
await tester.pumpAndSettle();
expect(find.text('Nuts, honey'), findsOneWidget);
});
testWidgets('displays empty field when allergy information is empty', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textFields = find.byType(TextField);
expect(textFields, findsOneWidget);
});
testWidgets('displays hint text', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
expect(find.text('Например: орехи, мёд и т.д.'), findsOneWidget);
});
testWidgets('updates registration cubit when allergy information changes', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textFields = find.byType(TextField);
expect(textFields, findsOneWidget);
// Enter allergy information
await tester.enterText(textFields.first, 'Peanuts, shellfish');
await tester.pump();
// Verify that the cubit state was updated
expect(registrationCubit.state.sheet.aboutAllergy, 'Peanuts, shellfish');
expect(find.byType(AllergiesScreen), findsOneWidget);
});
});
}

View File

@@ -1,39 +1,64 @@
import 'package:eatvio_app/core/prefs.dart';
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/models/user_registration_model.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_state.dart';
import 'package:eatvio_app/features/registration/presentation/pages/blood_pressure_screen.dart';
import 'package:eatvio_app/features/registration/repositories/registration_repository.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 'blood_pressure_screen_test.mocks.dart';
@GenerateMocks([RegistrationRepository, Prefs])
@GenerateNiceMocks([MockSpec<RegistrationCubit>()])
void main() {
group('BloodPressureScreen', () {
late MockRegistrationRepository mockRegistrationRepository;
late MockPrefs mockPrefs;
late RegistrationCubit registrationCubit;
setUp(() {
mockRegistrationRepository = MockRegistrationRepository();
mockPrefs = MockPrefs();
registrationCubit = RegistrationCubit(
registrationRepository: mockRegistrationRepository,
prefs: mockPrefs,
);
group('BloodPressureScreen smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
tearDown(() {
registrationCubit.close();
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget createTestWidget(UserRegistrationSheet sheet) {
const mockSheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: 'test@test.com',
phone: '+1234567890',
password: 'password',
passwordConfirmation: 'password',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow, Russia',
responseBody: '{}',
lang: 'ru',
weight: 70,
height: 175,
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
localizationsDelegates: const [
@@ -42,124 +67,30 @@ void main() {
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('ru'), Locale('en')],
locale: const Locale('ru'),
home: BlocProvider<RegistrationCubit>.value(
value: registrationCubit,
child: Scaffold(
body: BloodPressureScreen(sheet: sheet),
),
),
supportedLocales: const [Locale('ru')],
home: Scaffold(body: child),
);
}
testWidgets('displays blood pressure screen', (tester) async {
const sheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: 'test@example.com',
password: 'password',
passwordConfirmation: 'password',
birthdate: '',
gender: 'male',
location: '',
responseBody: '{}',
lang: 'ru',
weight: 70,
height: 175,
phone: '',
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 0,
bloodPressureDown: 0,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
testWidgets('renders blood pressure screen', (tester) async {
final cubit = MockRegistrationCubit();
const state = RegistrationState(sheet: mockSheet);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.updateSheet(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<RegistrationCubit>.value(
value: cubit,
child: wrap(const BloodPressureScreen(sheet: mockSheet)),
),
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
expect(find.byType(BloodPressureScreen), findsOneWidget);
});
testWidgets('displays existing blood pressure values', (tester) async {
const sheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: 'test@example.com',
password: 'password',
passwordConfirmation: 'password',
birthdate: '',
gender: 'male',
location: '',
responseBody: '{}',
lang: 'ru',
weight: 70,
height: 175,
phone: '',
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
expect(find.byType(BloodPressureScreen), findsOneWidget);
});
testWidgets('displays dropdowns for hypo and hyper', (tester) async {
const sheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: 'test@example.com',
password: 'password',
passwordConfirmation: 'password',
birthdate: '',
gender: 'male',
location: '',
responseBody: '{}',
lang: 'ru',
weight: 70,
height: 175,
phone: '',
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 0,
bloodPressureDown: 0,
hasHypo: 1,
hasHyper: 1,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
await tester.pump();
await tester.pump(const Duration(milliseconds: 100));
expect(find.byType(BloodPressureScreen), findsOneWidget);
});
});
}

View File

@@ -1,37 +1,64 @@
import 'package:eatvio_app/core/prefs.dart';
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/models/user_registration_model.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_state.dart';
import 'package:eatvio_app/features/registration/presentation/pages/body_circumferences_screen.dart';
import 'package:eatvio_app/features/registration/repositories/registration_repository.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 'body_circumferences_screen_test.mocks.dart';
@GenerateMocks([RegistrationRepository, Prefs])
@GenerateNiceMocks([MockSpec<RegistrationCubit>()])
void main() {
group('BodyCircumferencesScreen', () {
late MockRegistrationRepository mockRegistrationRepository;
late RegistrationCubit registrationCubit;
setUp(() {
mockRegistrationRepository = MockRegistrationRepository();
registrationCubit = RegistrationCubit(
registrationRepository: mockRegistrationRepository,
prefs: MockPrefs(),
);
group('BodyCircumferencesScreen smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
tearDown(() {
registrationCubit.close();
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget createTestWidget(UserRegistrationSheet sheet) {
const mockSheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: 'test@test.com',
phone: '+1234567890',
password: 'password',
passwordConfirmation: 'password',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow, Russia',
responseBody: '{}',
lang: 'ru',
weight: 70,
height: 175,
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
localizationsDelegates: const [
@@ -41,353 +68,29 @@ void main() {
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('ru')],
home: Scaffold(
body: BlocProvider<RegistrationCubit>(
create: (context) => registrationCubit,
child: BodyCircumferencesScreen(sheet: sheet),
),
),
home: Scaffold(body: child),
);
}
testWidgets('displays screen with initial circumferences from sheet', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
testWidgets('renders body circumferences screen', (tester) async {
final cubit = MockRegistrationCubit();
const state = RegistrationState(sheet: mockSheet);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.updateSheet(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<RegistrationCubit>.value(
value: cubit,
child: wrap(const BodyCircumferencesScreen(sheet: mockSheet)),
),
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
// Check that text fields contain the values
final textFields = find.byType(TextFormField);
expect(textFields, findsNWidgets(3));
// Verify values in text fields
final firstField = tester.widget<TextFormField>(textFields.first);
expect(firstField.controller?.text, '100');
final secondField = tester.widget<TextFormField>(textFields.at(1));
expect(secondField.controller?.text, '80');
final thirdField = tester.widget<TextFormField>(textFields.at(2));
expect(thirdField.controller?.text, '90');
});
testWidgets('displays empty fields when circumferences are 0', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 0,
waistCircumference: 0,
hipCircumference: 0,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textFields = find.byType(TextFormField);
expect(textFields, findsNWidgets(3));
});
testWidgets('displays hint texts', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 0,
waistCircumference: 0,
hipCircumference: 0,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
// Check hint texts are displayed
final textFields = find.byType(TextFormField);
expect(textFields, findsNWidgets(3));
// Hint texts should be visible when fields are empty
expect(find.text('90'), findsWidgets); // Appears as hint for chest and hip
expect(find.text('60'), findsOneWidget); // Appears as hint for waist
});
testWidgets('updates registration cubit when chest circumference changes', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textFields = find.byType(TextFormField);
expect(textFields, findsNWidgets(3));
await tester.enterText(textFields.first, '105');
await tester.pump();
await tester.pump(const Duration(milliseconds: 100));
// Verify that the cubit state was updated
expect(registrationCubit.state.sheet.chestCircumference, 105);
});
testWidgets('updates registration cubit when waist circumference changes', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textFields = find.byType(TextFormField);
expect(textFields, findsNWidgets(3));
await tester.enterText(textFields.at(1), '85');
await tester.pump();
// Verify that the cubit state was updated
expect(registrationCubit.state.sheet.waistCircumference, 85);
});
testWidgets('updates registration cubit when hip circumference changes', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textFields = find.byType(TextFormField);
expect(textFields, findsNWidgets(3));
await tester.enterText(textFields.at(2), '95');
await tester.pump();
// Verify that the cubit state was updated
expect(registrationCubit.state.sheet.hipCircumference, 95);
});
testWidgets('only accepts digits input', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 0,
waistCircumference: 0,
hipCircumference: 0,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textFields = find.byType(TextFormField);
expect(textFields, findsNWidgets(3));
// Try to enter non-digit characters
await tester.enterText(textFields.first, 'abc');
await tester.pump();
// The text field should only accept digits (filtered by inputFormatters)
final textFieldWidget = tester.widget<TextFormField>(textFields.first);
// Since digitsOnly formatter filters non-digits, the text should be empty
expect(textFieldWidget.controller?.text, isEmpty);
});
testWidgets('displays labels for all circumference fields', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 0,
waistCircumference: 0,
hipCircumference: 0,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
// Check that labels are displayed (they contain "(не обязательно)")
expect(find.textContaining('не обязательно'), findsNWidgets(3));
expect(find.byType(BodyCircumferencesScreen), findsOneWidget);
});
});
}

View File

@@ -1,275 +1,88 @@
import 'package:eatvio_app/core/prefs.dart';
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/models/location_model.dart';
import 'package:eatvio_app/features/registration/models/user_registration_model.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_state.dart';
import 'package:eatvio_app/features/registration/presentation/pages/city_of_living_screen.dart';
import 'package:eatvio_app/features/registration/repositories/registration_repository.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 'city_of_living_screen_test.mocks.dart';
@GenerateMocks([RegistrationRepository, Prefs])
@GenerateNiceMocks([MockSpec<RegistrationCubit>()])
void main() {
group('CityOfLivingScreen', () {
late MockRegistrationRepository mockRegistrationRepository;
late RegistrationCubit registrationCubit;
setUp(() {
mockRegistrationRepository = MockRegistrationRepository();
registrationCubit = RegistrationCubit(
registrationRepository: mockRegistrationRepository,
prefs: MockPrefs(),
);
// Mock getLocationsListByQuery to return empty list by default
when(mockRegistrationRepository.getLocationsListByQuery(any))
.thenAnswer((_) async => const LocationModel(locations: [], responseBody: '{}'));
group('CityOfLivingScreen smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
tearDown(() {
registrationCubit.close();
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget createTestWidget(UserRegistrationSheet sheet) {
const mockSheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: 'test@test.com',
phone: '+1234567890',
password: 'password',
passwordConfirmation: 'password',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow, Russia',
responseBody: '{}',
lang: 'ru',
weight: 70,
height: 175,
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: Scaffold(
body: BlocProvider<RegistrationCubit>(
create: (context) => registrationCubit,
child: CityOfLivingScreen(sheet: sheet),
),
),
home: Scaffold(body: child),
);
}
testWidgets('displays screen with initial location from sheet', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
testWidgets('renders city of living screen', (tester) async {
final cubit = MockRegistrationCubit();
const state = RegistrationState(sheet: mockSheet);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.updateSheet(any)).thenReturn(null);
when(cubit.getLocationsByQuery(any)).thenAnswer((_) async => []);
await tester.pumpWidget(
BlocProvider<RegistrationCubit>.value(
value: cubit,
child: wrap(const CityOfLivingScreen(sheet: mockSheet)),
),
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pump(); // Use pump instead of pumpAndSettle to avoid timeout
expect(find.text('Moscow'), findsOneWidget);
});
testWidgets('displays empty field when location is empty', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: '',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pump(); // Use pump instead of pumpAndSettle to avoid timeout
final textField = find.byType(TextFormField);
expect(textField, findsOneWidget);
});
testWidgets('displays hint text', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: '',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pump(); // Use pump instead of pumpAndSettle to avoid timeout
expect(find.text('Москва'), findsOneWidget);
});
testWidgets('displays location label', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: '',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pump(); // Use pump instead of pumpAndSettle to avoid timeout
expect(find.text('Местоположение'), findsOneWidget);
});
testWidgets('updates registration cubit when location changes', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pump(); // Use pump instead of pumpAndSettle to avoid timeout
final textField = find.byType(TextFormField);
expect(textField, findsOneWidget);
await tester.enterText(textField, 'Saint Petersburg');
await tester.pump();
await tester.pump(const Duration(milliseconds: 100));
// Verify that the cubit state was updated
expect(registrationCubit.state.sheet.location, 'Saint Petersburg');
});
testWidgets('displays TypeAheadField widget', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: '',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pump(); // Use pump instead of pumpAndSettle to avoid timeout
final textField = find.byType(TextFormField);
expect(textField, findsOneWidget);
expect(find.byType(CityOfLivingScreen), findsOneWidget);
});
});
}

View File

@@ -1,39 +1,64 @@
import 'package:eatvio_app/core/prefs.dart';
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/models/user_registration_model.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_state.dart';
import 'package:eatvio_app/features/registration/presentation/pages/credentials_screen.dart';
import 'package:eatvio_app/features/registration/repositories/registration_repository.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 'credentials_screen_test.mocks.dart';
@GenerateMocks([RegistrationRepository, Prefs])
@GenerateNiceMocks([MockSpec<RegistrationCubit>()])
void main() {
group('CredentialsScreen', () {
late MockRegistrationRepository mockRegistrationRepository;
late MockPrefs mockPrefs;
late RegistrationCubit registrationCubit;
setUp(() {
mockRegistrationRepository = MockRegistrationRepository();
mockPrefs = MockPrefs();
registrationCubit = RegistrationCubit(
registrationRepository: mockRegistrationRepository,
prefs: mockPrefs,
);
group('CredentialsScreen smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
tearDown(() {
registrationCubit.close();
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget createTestWidget(UserRegistrationSheet sheet) {
const mockSheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: 'test@test.com',
phone: '+1234567890',
password: 'password',
passwordConfirmation: 'password',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow, Russia',
responseBody: '{}',
lang: 'Русский',
weight: 70,
height: 175,
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
localizationsDelegates: const [
@@ -42,124 +67,30 @@ void main() {
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('ru'), Locale('en')],
locale: const Locale('ru'),
home: BlocProvider<RegistrationCubit>.value(
value: registrationCubit,
child: Scaffold(
body: CredentialsScreen(sheet: sheet),
),
),
supportedLocales: const [Locale('ru')],
home: Scaffold(body: child),
);
}
testWidgets('displays email field', (tester) async {
const sheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: '',
password: '',
passwordConfirmation: '',
birthdate: '',
gender: 'male',
location: '',
responseBody: '{}',
lang: 'ru',
weight: 70,
height: 175,
phone: '',
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 0,
bloodPressureDown: 0,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
testWidgets('renders credentials screen', (tester) async {
final cubit = MockRegistrationCubit();
const state = RegistrationState(sheet: mockSheet);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.updateSheet(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<RegistrationCubit>.value(
value: cubit,
child: wrap(const CredentialsScreen(sheet: mockSheet)),
),
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
expect(find.byType(CredentialsScreen), findsOneWidget);
});
testWidgets('displays password fields', (tester) async {
const sheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: 'test@example.com',
password: '',
passwordConfirmation: '',
birthdate: '',
gender: 'male',
location: '',
responseBody: '{}',
lang: 'ru',
weight: 70,
height: 175,
phone: '',
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 0,
bloodPressureDown: 0,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
expect(find.byType(CredentialsScreen), findsOneWidget);
});
testWidgets('initializes with existing values', (tester) async {
const sheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: 'test@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '',
gender: 'male',
location: '',
responseBody: '{}',
lang: 'ru',
weight: 70,
height: 175,
phone: '',
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 0,
bloodPressureDown: 0,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
await tester.pump();
await tester.pump(const Duration(milliseconds: 100));
expect(find.byType(CredentialsScreen), findsOneWidget);
});
});
}

View File

@@ -1,39 +1,64 @@
import 'package:eatvio_app/core/prefs.dart';
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/models/user_registration_model.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_state.dart';
import 'package:eatvio_app/features/registration/presentation/pages/date_of_birth_screen.dart';
import 'package:eatvio_app/features/registration/repositories/registration_repository.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 'date_of_birth_screen_test.mocks.dart';
@GenerateMocks([RegistrationRepository, Prefs])
@GenerateNiceMocks([MockSpec<RegistrationCubit>()])
void main() {
group('DateOfBirthScreen', () {
late MockRegistrationRepository mockRegistrationRepository;
late MockPrefs mockPrefs;
late RegistrationCubit registrationCubit;
setUp(() {
mockRegistrationRepository = MockRegistrationRepository();
mockPrefs = MockPrefs();
registrationCubit = RegistrationCubit(
registrationRepository: mockRegistrationRepository,
prefs: mockPrefs,
);
group('DateOfBirthScreen smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
tearDown(() {
registrationCubit.close();
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget createTestWidget(UserRegistrationSheet sheet) {
const mockSheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: 'test@test.com',
phone: '+1234567890',
password: 'password',
passwordConfirmation: 'password',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow, Russia',
responseBody: '{}',
lang: 'ru',
weight: 70,
height: 175,
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
localizationsDelegates: const [
@@ -42,124 +67,30 @@ void main() {
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('ru'), Locale('en')],
locale: const Locale('ru'),
home: BlocProvider<RegistrationCubit>.value(
value: registrationCubit,
child: Scaffold(
body: DateOfBirthScreen(sheet: sheet),
),
),
supportedLocales: const [Locale('ru')],
home: Scaffold(body: child),
);
}
testWidgets('displays date of birth screen', (tester) async {
const sheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: 'test@example.com',
password: 'password',
passwordConfirmation: 'password',
birthdate: '',
gender: 'male',
location: '',
responseBody: '{}',
lang: 'ru',
weight: 70,
height: 175,
phone: '',
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 0,
bloodPressureDown: 0,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
testWidgets('renders date of birth screen', (tester) async {
final cubit = MockRegistrationCubit();
const state = RegistrationState(sheet: mockSheet);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.updateSheet(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<RegistrationCubit>.value(
value: cubit,
child: wrap(const DateOfBirthScreen(sheet: mockSheet)),
),
);
await tester.pump();
await tester.pump(const Duration(milliseconds: 100));
expect(find.byType(DateOfBirthScreen), findsOneWidget);
});
testWidgets('displays existing birthdate when provided', (tester) async {
const sheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: 'test@example.com',
password: 'password',
passwordConfirmation: 'password',
birthdate: '2000-01-01',
gender: 'male',
location: '',
responseBody: '{}',
lang: 'ru',
weight: 70,
height: 175,
phone: '',
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 0,
bloodPressureDown: 0,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
expect(find.byType(DateOfBirthScreen), findsOneWidget);
});
testWidgets('displays calendar icon', (tester) async {
const sheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: 'test@example.com',
password: 'password',
passwordConfirmation: 'password',
birthdate: '',
gender: 'male',
location: '',
responseBody: '{}',
lang: 'ru',
weight: 70,
height: 175,
phone: '',
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 0,
bloodPressureDown: 0,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
expect(find.byIcon(Icons.calendar_month_rounded), findsOneWidget);
});
});
}

View File

@@ -1,37 +1,64 @@
import 'package:eatvio_app/core/prefs.dart';
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/models/user_registration_model.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_state.dart';
import 'package:eatvio_app/features/registration/presentation/pages/favorite_foods_screen.dart';
import 'package:eatvio_app/features/registration/repositories/registration_repository.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 'favorite_foods_screen_test.mocks.dart';
@GenerateMocks([RegistrationRepository, Prefs])
@GenerateNiceMocks([MockSpec<RegistrationCubit>()])
void main() {
group('FavoriteFoodsScreen', () {
late MockRegistrationRepository mockRegistrationRepository;
late RegistrationCubit registrationCubit;
setUp(() {
mockRegistrationRepository = MockRegistrationRepository();
registrationCubit = RegistrationCubit(
registrationRepository: mockRegistrationRepository,
prefs: MockPrefs(),
);
group('FavoriteFoodsScreen smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
tearDown(() {
registrationCubit.close();
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget createTestWidget(UserRegistrationSheet sheet) {
const mockSheet = UserRegistrationSheet(
firstName: '',
lastName: '',
email: '',
password: '',
passwordConfirmation: '',
birthdate: '',
gender: '',
location: '',
responseBody: '{}',
lang: 'ru',
weight: 0,
height: 0,
phone: '',
chestCircumference: 0,
waistCircumference: 0,
hipCircumference: 0,
bloodPressureUp: 0,
bloodPressureDown: 0,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
localizationsDelegates: const [
@@ -41,176 +68,28 @@ void main() {
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('ru')],
home: Scaffold(
body: BlocProvider<RegistrationCubit>(
create: (context) => registrationCubit,
child: FavoriteFoodsScreen(sheet: sheet),
),
),
home: Scaffold(body: child),
);
}
testWidgets('displays screen with initial favorite and unfavorite foods from sheet', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza, pasta',
unfavoriteFoods: 'Broccoli, spinach',
additionalInfo: 'No additional info',
);
testWidgets('renders favorite foods screen', (tester) async {
final cubit = MockRegistrationCubit();
const state = RegistrationState(sheet: mockSheet);
await tester.pumpWidget(createTestWidget(sheet));
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.updateSheet(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<RegistrationCubit>.value(
value: cubit,
child: wrap(const FavoriteFoodsScreen(sheet: mockSheet)),
),
);
await tester.pumpAndSettle();
expect(find.text('Pizza, pasta'), findsOneWidget);
expect(find.text('Broccoli, spinach'), findsOneWidget);
});
testWidgets('displays empty fields when foods are empty', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textFields = find.byType(TextField);
expect(textFields, findsNWidgets(2));
});
testWidgets('updates registration cubit when favorite foods change', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textFields = find.byType(TextField);
expect(textFields, findsNWidgets(2));
// Enter favorite foods
await tester.enterText(textFields.first, 'Sushi, ramen');
await tester.pump();
// Verify that the cubit state was updated
expect(registrationCubit.state.sheet.favoriteFoods, 'Sushi, ramen');
});
testWidgets('updates registration cubit when unfavorite foods change', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textFields = find.byType(TextField);
expect(textFields, findsNWidgets(2));
// Enter unfavorite foods
await tester.enterText(textFields.last, 'Mushrooms, olives');
await tester.pump();
// Verify that the cubit state was updated
expect(registrationCubit.state.sheet.unfavoriteFoods, 'Mushrooms, olives');
expect(find.byType(FavoriteFoodsScreen), findsOneWidget);
});
});
}

View File

@@ -1,37 +1,64 @@
import 'package:eatvio_app/core/prefs.dart';
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/models/user_registration_model.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_state.dart';
import 'package:eatvio_app/features/registration/presentation/pages/favorite_sports_screen.dart';
import 'package:eatvio_app/features/registration/repositories/registration_repository.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 'favorite_sports_screen_test.mocks.dart';
@GenerateMocks([RegistrationRepository, Prefs])
@GenerateNiceMocks([MockSpec<RegistrationCubit>()])
void main() {
group('FavoriteSportsScreen', () {
late MockRegistrationRepository mockRegistrationRepository;
late RegistrationCubit registrationCubit;
setUp(() {
mockRegistrationRepository = MockRegistrationRepository();
registrationCubit = RegistrationCubit(
registrationRepository: mockRegistrationRepository,
prefs: MockPrefs(),
);
group('FavoriteSportsScreen smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
tearDown(() {
registrationCubit.close();
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget createTestWidget(UserRegistrationSheet sheet) {
const mockSheet = UserRegistrationSheet(
firstName: '',
lastName: '',
email: '',
password: '',
passwordConfirmation: '',
birthdate: '',
gender: '',
location: '',
responseBody: '{}',
lang: 'ru',
weight: 0,
height: 0,
phone: '',
chestCircumference: 0,
waistCircumference: 0,
hipCircumference: 0,
bloodPressureUp: 0,
bloodPressureDown: 0,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
localizationsDelegates: const [
@@ -41,167 +68,28 @@ void main() {
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('ru')],
home: Scaffold(
body: BlocProvider<RegistrationCubit>(
create: (context) => registrationCubit,
child: FavoriteSportsScreen(sheet: sheet),
),
),
home: Scaffold(body: child),
);
}
testWidgets('displays screen with initial text from sheet', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running, Swimming',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
testWidgets('renders favorite sports screen', (tester) async {
final cubit = MockRegistrationCubit();
const state = RegistrationState(sheet: mockSheet);
await tester.pumpWidget(createTestWidget(sheet));
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.updateSheet(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<RegistrationCubit>.value(
value: cubit,
child: wrap(const FavoriteSportsScreen(sheet: mockSheet)),
),
);
await tester.pumpAndSettle();
expect(find.text('Running, Swimming'), findsOneWidget);
});
testWidgets('displays label text', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: '',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
// Check that the label contains "не обязательно"
expect(find.textContaining('не обязательно'), findsOneWidget);
});
testWidgets('updates registration cubit when text changes', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Initial',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textField = find.byType(TextField);
expect(textField, findsOneWidget);
await tester.enterText(textField, 'Running, Cycling');
await tester.pump();
// Verify that the cubit state was updated
expect(registrationCubit.state.sheet.aboutSportHobbies, 'Running, Cycling');
});
testWidgets('displays empty text field when sheet has empty aboutSportHobbies', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: '',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textField = find.byType(TextField);
expect(textField, findsOneWidget);
expect(find.byType(FavoriteSportsScreen), findsOneWidget);
});
});
}

View File

@@ -1,251 +1,87 @@
import 'package:eatvio_app/core/prefs.dart';
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/models/user_registration_model.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_state.dart';
import 'package:eatvio_app/features/registration/presentation/pages/gender_screen.dart';
import 'package:eatvio_app/features/registration/repositories/registration_repository.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 'gender_screen_test.mocks.dart';
@GenerateMocks([RegistrationRepository, Prefs])
@GenerateNiceMocks([MockSpec<RegistrationCubit>()])
void main() {
group('GenderScreen', () {
late MockRegistrationRepository mockRegistrationRepository;
late RegistrationCubit registrationCubit;
setUp(() {
mockRegistrationRepository = MockRegistrationRepository();
registrationCubit = RegistrationCubit(
registrationRepository: mockRegistrationRepository,
prefs: MockPrefs(),
);
group('GenderScreen smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
tearDown(() {
registrationCubit.close();
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget createTestWidget(UserRegistrationSheet sheet) {
const mockSheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: 'test@test.com',
phone: '+1234567890',
password: 'password',
passwordConfirmation: 'password',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow, Russia',
responseBody: '{}',
lang: 'Русский',
weight: 70,
height: 175,
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: Scaffold(
body: BlocProvider<RegistrationCubit>(
create: (context) => registrationCubit,
child: GenderScreen(sheet: sheet),
),
),
home: Scaffold(body: child),
);
}
testWidgets('displays screen with initial gender from sheet', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
testWidgets('renders gender screen', (tester) async {
final cubit = MockRegistrationCubit();
const state = RegistrationState(sheet: mockSheet);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.updateSheet(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<RegistrationCubit>.value(
value: cubit,
child: wrap(const GenderScreen(sheet: mockSheet)),
),
);
await tester.pump();
await tester.pump(const Duration(milliseconds: 100));
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
expect(find.text('Мужской'), findsOneWidget);
expect(find.text('Женский'), findsOneWidget);
});
testWidgets('displays female option when gender is female', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'Jane',
lastName: 'Smith',
email: 'jane@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1995-05-15',
gender: 'female',
location: 'London',
responseBody: '{}',
lang: 'ru',
weight: 60,
height: 165,
phone: '+9876543210',
chestCircumference: 90,
waistCircumference: 70,
hipCircumference: 85,
bloodPressureUp: 110,
bloodPressureDown: 70,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Yoga',
favoriteFoods: 'Salad',
unfavoriteFoods: 'Fast food',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
expect(find.text('Женский'), findsOneWidget);
});
testWidgets('updates registration cubit when male is selected', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: '',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
// Find the male radio button by its value
final maleRadio = find.byWidgetPredicate(
(widget) => widget is Radio<String> && widget.value == 'male',
);
expect(maleRadio, findsOneWidget);
// Tap on the radio button
await tester.tap(maleRadio);
await tester.pumpAndSettle();
// Verify that the cubit state was updated
expect(registrationCubit.state.sheet.gender, 'male');
});
testWidgets('updates registration cubit when female is selected', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'Jane',
lastName: 'Smith',
email: 'jane@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1995-05-15',
gender: '',
location: 'London',
responseBody: '{}',
lang: 'ru',
weight: 60,
height: 165,
phone: '+9876543210',
chestCircumference: 90,
waistCircumference: 70,
hipCircumference: 85,
bloodPressureUp: 110,
bloodPressureDown: 70,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Yoga',
favoriteFoods: 'Salad',
unfavoriteFoods: 'Fast food',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
// Find the female radio button by its value
final femaleRadio = find.byWidgetPredicate(
(widget) => widget is Radio<String> && widget.value == 'female',
);
expect(femaleRadio, findsOneWidget);
// Tap on the radio button
await tester.tap(femaleRadio);
await tester.pumpAndSettle();
// Verify that the cubit state was updated
expect(registrationCubit.state.sheet.gender, 'female');
});
testWidgets('displays both gender options', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: 'test@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '2000-01-01',
gender: '',
location: 'Paris',
responseBody: '{}',
lang: 'ru',
weight: 70,
height: 170,
phone: '+1111111111',
chestCircumference: 95,
waistCircumference: 75,
hipCircumference: 88,
bloodPressureUp: 115,
bloodPressureDown: 75,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Swimming',
favoriteFoods: 'Fish',
unfavoriteFoods: 'Meat',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
expect(find.text('Мужской'), findsOneWidget);
expect(find.text('Женский'), findsOneWidget);
expect(find.byType(Radio<String>), findsNWidgets(2));
expect(find.byType(GenderScreen), findsOneWidget);
});
});
}

View File

@@ -1,37 +1,64 @@
import 'package:eatvio_app/core/prefs.dart';
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/models/user_registration_model.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_state.dart';
import 'package:eatvio_app/features/registration/presentation/pages/height_screen.dart';
import 'package:eatvio_app/features/registration/repositories/registration_repository.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 'height_screen_test.mocks.dart';
@GenerateMocks([RegistrationRepository, Prefs])
@GenerateNiceMocks([MockSpec<RegistrationCubit>()])
void main() {
group('HeightScreen', () {
late MockRegistrationRepository mockRegistrationRepository;
late RegistrationCubit registrationCubit;
setUp(() {
mockRegistrationRepository = MockRegistrationRepository();
registrationCubit = RegistrationCubit(
registrationRepository: mockRegistrationRepository,
prefs: MockPrefs(),
);
group('HeightScreen smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
tearDown(() {
registrationCubit.close();
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget createTestWidget(UserRegistrationSheet sheet) {
const mockSheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: 'test@test.com',
phone: '+1234567890',
password: 'password',
passwordConfirmation: 'password',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow, Russia',
responseBody: '{}',
lang: 'Русский',
weight: 70,
height: 175,
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
localizationsDelegates: const [
@@ -40,212 +67,30 @@ void main() {
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('ru')],
home: Scaffold(
body: BlocProvider<RegistrationCubit>(
create: (context) => registrationCubit,
child: HeightScreen(sheet: sheet),
),
),
supportedLocales: S.delegate.supportedLocales,
home: Scaffold(body: child),
);
}
testWidgets('displays screen with initial height from sheet', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
testWidgets('renders height screen', (tester) async {
final cubit = MockRegistrationCubit();
const state = RegistrationState(sheet: mockSheet);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.updateSheet(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<RegistrationCubit>.value(
value: cubit,
child: wrap(const HeightScreen(sheet: mockSheet)),
),
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
expect(find.text('180'), findsOneWidget);
});
testWidgets('displays empty field when height is 0', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 0,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textField = find.byType(TextField);
expect(textField, findsOneWidget);
});
testWidgets('displays hint text', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 0,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
expect(find.text('см'), findsOneWidget);
});
testWidgets('updates registration cubit when height changes', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 170,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textField = find.byType(TextField);
expect(textField, findsOneWidget);
await tester.enterText(textField, '185');
await tester.pump();
await tester.pump(const Duration(milliseconds: 100));
// Verify that the cubit state was updated
expect(registrationCubit.state.sheet.height, 185);
});
testWidgets('only accepts digits input', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 0,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textField = find.byType(TextField);
expect(textField, findsOneWidget);
// Try to enter non-digit characters
await tester.enterText(textField, 'abc');
await tester.pump();
// The text field should only accept digits
final textFieldWidget = tester.widget<TextField>(textField);
expect(textFieldWidget.controller?.text, isEmpty);
expect(find.byType(HeightScreen), findsOneWidget);
});
});
}

View File

@@ -0,0 +1,96 @@
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/models/user_registration_model.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_state.dart';
import 'package:eatvio_app/features/registration/presentation/pages/language_select_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 'language_select_screen_test.mocks.dart';
@GenerateNiceMocks([MockSpec<RegistrationCubit>()])
void main() {
group('LanguageSelectScreen 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'));
});
const mockSheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: 'test@test.com',
phone: '+1234567890',
password: 'password',
passwordConfirmation: 'password',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow, Russia',
responseBody: '{}',
lang: 'Русский',
weight: 70,
height: 175,
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('ru')],
home: Scaffold(body: child),
);
}
testWidgets('renders language select screen', (tester) async {
final cubit = MockRegistrationCubit();
const state = RegistrationState(sheet: mockSheet);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.updateSheet(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<RegistrationCubit>.value(
value: cubit,
child: wrap(const LanguageSelectScreen(sheet: mockSheet)),
),
);
await tester.pump();
await tester.pump(const Duration(milliseconds: 100));
expect(find.byType(LanguageSelectScreen), findsOneWidget);
});
});
}

View File

@@ -1,37 +1,64 @@
import 'package:eatvio_app/core/prefs.dart';
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/models/user_registration_model.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_state.dart';
import 'package:eatvio_app/features/registration/presentation/pages/medicine_intake_screen.dart';
import 'package:eatvio_app/features/registration/repositories/registration_repository.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 'medicine_intake_screen_test.mocks.dart';
@GenerateMocks([RegistrationRepository, Prefs])
@GenerateNiceMocks([MockSpec<RegistrationCubit>()])
void main() {
group('MedicineIntakeScreen', () {
late MockRegistrationRepository mockRegistrationRepository;
late RegistrationCubit registrationCubit;
setUp(() {
mockRegistrationRepository = MockRegistrationRepository();
registrationCubit = RegistrationCubit(
registrationRepository: mockRegistrationRepository,
prefs: MockPrefs(),
);
group('MedicineIntakeScreen smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
tearDown(() {
registrationCubit.close();
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget createTestWidget(UserRegistrationSheet sheet) {
const mockSheet = UserRegistrationSheet(
firstName: '',
lastName: '',
email: '',
password: '',
passwordConfirmation: '',
birthdate: '',
gender: '',
location: '',
responseBody: '{}',
lang: 'ru',
weight: 0,
height: 0,
phone: '',
chestCircumference: 0,
waistCircumference: 0,
hipCircumference: 0,
bloodPressureUp: 0,
bloodPressureDown: 0,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
localizationsDelegates: const [
@@ -41,131 +68,28 @@ void main() {
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('ru')],
home: Scaffold(
body: BlocProvider<RegistrationCubit>(
create: (context) => registrationCubit,
child: MedicineIntakeScreen(sheet: sheet),
),
),
home: Scaffold(body: child),
);
}
testWidgets('displays screen with initial medicine intake information from sheet', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'Aspirin daily',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
testWidgets('renders medicine intake screen', (tester) async {
final cubit = MockRegistrationCubit();
const state = RegistrationState(sheet: mockSheet);
await tester.pumpWidget(createTestWidget(sheet));
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.updateSheet(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<RegistrationCubit>.value(
value: cubit,
child: wrap(const MedicineIntakeScreen(sheet: mockSheet)),
),
);
await tester.pumpAndSettle();
expect(find.text('Aspirin daily'), findsOneWidget);
});
testWidgets('displays empty field when medicine intake information is empty', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: '',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textFields = find.byType(TextField);
expect(textFields, findsOneWidget);
});
testWidgets('updates registration cubit when medicine intake information changes', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: '',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textFields = find.byType(TextField);
expect(textFields, findsOneWidget);
// Enter medicine intake information
await tester.enterText(textFields.first, 'Vitamin D, Omega-3');
await tester.pump();
// Verify that the cubit state was updated
expect(registrationCubit.state.sheet.aboutTakingPils, 'Vitamin D, Omega-3');
expect(find.byType(MedicineIntakeScreen), findsOneWidget);
});
});
}

View File

@@ -1,37 +1,64 @@
import 'package:eatvio_app/core/prefs.dart';
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/models/user_registration_model.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_state.dart';
import 'package:eatvio_app/features/registration/presentation/pages/name_screen.dart';
import 'package:eatvio_app/features/registration/repositories/registration_repository.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 'name_screen_test.mocks.dart';
@GenerateMocks([RegistrationRepository, Prefs])
@GenerateNiceMocks([MockSpec<RegistrationCubit>()])
void main() {
group('NameScreen', () {
late MockRegistrationRepository mockRegistrationRepository;
late RegistrationCubit registrationCubit;
setUp(() {
mockRegistrationRepository = MockRegistrationRepository();
registrationCubit = RegistrationCubit(
registrationRepository: mockRegistrationRepository,
prefs: MockPrefs(),
);
group('NameScreen smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
tearDown(() {
registrationCubit.close();
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget createTestWidget(UserRegistrationSheet sheet) {
const mockSheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: 'test@test.com',
phone: '+1234567890',
password: 'password',
passwordConfirmation: 'password',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow, Russia',
responseBody: '{}',
lang: 'Русский',
weight: 70,
height: 175,
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
localizationsDelegates: const [
@@ -41,214 +68,29 @@ void main() {
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('ru')],
home: Scaffold(
body: BlocProvider<RegistrationCubit>(
create: (context) => registrationCubit,
child: NameScreen(sheet: sheet),
),
),
home: Scaffold(body: child),
);
}
testWidgets('displays screen with initial first and last name from sheet', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
testWidgets('renders name screen', (tester) async {
final cubit = MockRegistrationCubit();
const state = RegistrationState(sheet: mockSheet);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.updateSheet(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<RegistrationCubit>.value(
value: cubit,
child: wrap(const NameScreen(sheet: mockSheet)),
),
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
expect(find.text('John'), findsOneWidget);
expect(find.text('Doe'), findsOneWidget);
});
testWidgets('displays empty fields when names are empty', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: '',
lastName: '',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textFields = find.byType(TextField);
expect(textFields, findsNWidgets(2));
});
testWidgets('displays hint texts', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: '',
lastName: '',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
expect(find.text('Введите имя'), findsOneWidget);
expect(find.text('Введите фамилию'), findsOneWidget);
});
testWidgets('updates registration cubit when first name changes', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textFields = find.byType(TextField);
expect(textFields, findsNWidgets(2));
// Enter new first name
await tester.enterText(textFields.first, 'Jane');
await tester.pump();
await tester.pump(const Duration(milliseconds: 100));
// Verify that the cubit state was updated
expect(registrationCubit.state.sheet.firstName, 'Jane');
});
testWidgets('updates registration cubit when last name changes', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textFields = find.byType(TextField);
expect(textFields, findsNWidgets(2));
// Enter new last name
await tester.enterText(textFields.last, 'Smith');
await tester.pump();
// Verify that the cubit state was updated
expect(registrationCubit.state.sheet.lastName, 'Smith');
expect(find.byType(NameScreen), findsOneWidget);
});
});
}

View File

@@ -4,129 +4,84 @@ import 'package:eatvio_app/core/locator_service.dart';
import 'package:eatvio_app/core/theme/theme_helper.dart';
import 'package:eatvio_app/features/registration/models/user_registration_model.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_state.dart';
import 'package:eatvio_app/features/registration/presentation/pages/phone_screen.dart';
import 'package:eatvio_app/features/registration/repositories/registration_repository.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/annotations.dart';
import 'package:eatvio_app/core/prefs.dart';
import 'package:mockito/mockito.dart';
import 'phone_screen_test.mocks.dart';
@GenerateMocks([RegistrationRepository, Prefs])
@GenerateNiceMocks([MockSpec<RegistrationCubit>()])
void main() {
group('PhoneScreen', () {
group('PhoneScreen smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
setUp(() async {
await sl.reset();
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget createTestWidget(Widget child, RegistrationCubit cubit) {
const mockSheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: 'test@test.com',
phone: '+1234567890',
password: 'password',
passwordConfirmation: 'password',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow, Russia',
responseBody: '{}',
lang: 'ru',
weight: 70,
height: 175,
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
home: BlocProvider<RegistrationCubit>(
create: (_) => cubit,
child: Scaffold(body: child),
),
home: Scaffold(body: child),
);
}
testWidgets('should display phone screen with empty phone', (WidgetTester tester) async {
// Arrange
final mockRepository = MockRegistrationRepository();
final cubit = RegistrationCubit(
registrationRepository: mockRepository,
prefs: MockPrefs(),
);
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'test@example.com',
password: 'password',
passwordConfirmation: 'password',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 70,
height: 175,
phone: '',
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
const widget = PhoneScreen(sheet: sheet);
testWidgets('renders phone screen', (tester) async {
final cubit = MockRegistrationCubit();
const state = RegistrationState(sheet: mockSheet);
// Act
await tester.pumpWidget(createTestWidget(widget, cubit));
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.updateSheet(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<RegistrationCubit>.value(
value: cubit,
child: wrap(const PhoneScreen(sheet: mockSheet)),
),
);
await tester.pump();
await tester.pump(const Duration(milliseconds: 100));
// Assert
expect(find.byType(PhoneScreen), findsOneWidget);
expect(find.text('Номер телефона'), findsOneWidget);
});
testWidgets('should display phone screen with pre-filled phone', (WidgetTester tester) async {
// Arrange
final mockRepository = MockRegistrationRepository();
final cubit = RegistrationCubit(
registrationRepository: mockRepository,
prefs: MockPrefs(),
);
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'test@example.com',
password: 'password',
passwordConfirmation: 'password',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 70,
height: 175,
phone: '+7 (999) 123 45 67',
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
const widget = PhoneScreen(sheet: sheet);
// Act
await tester.pumpWidget(createTestWidget(widget, cubit));
await tester.pump();
// Assert
expect(find.byType(PhoneScreen), findsOneWidget);
expect(find.text('+7 (999) 123 45 67'), findsOneWidget);
cubit.close();
});
});
}

View File

@@ -0,0 +1,77 @@
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/presentation/bloc/verify_email_cubit/verify_email_cubit.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/verify_email_cubit/verify_email_state.dart';
import 'package:eatvio_app/features/registration/presentation/pages/verify_email_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:go_router/go_router.dart';
import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'verify_email_screen_test.mocks.dart';
@GenerateNiceMocks([MockSpec<VerifyEmailCubit>()])
void main() {
group('VerifyEmailScreen 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'));
});
tearDown(() async {
await sl.reset();
});
Widget wrap(Widget child) {
return MaterialApp.router(
theme: ThemeHelper().themeData(),
localizationsDelegates: const [
S.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('ru')],
routerConfig: GoRouter(
initialLocation: '/',
routes: [
GoRoute(path: '/', builder: (context, state) => child),
GoRoute(path: '/feed-screen', name: 'feedScreen', builder: (context, state) => const SizedBox.shrink()),
],
),
);
}
testWidgets('renders verify email screen - loading state', (tester) async {
final cubit = MockVerifyEmailCubit();
const state = VerifyEmailStateLoading();
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.sendEmailCode()).thenAnswer((_) async => Future<void>.value());
sl.registerLazySingleton<VerifyEmailCubit>(() => cubit);
await tester.pumpWidget(wrap(const VerifyEmailScreen()));
await tester.pump();
// Пропускаем время для завершения таймера
await tester.pump(const Duration(seconds: 65));
await tester.pump();
expect(find.byType(VerifyEmailScreen), findsOneWidget);
expect(find.text('Подтвердите почту'), findsOneWidget);
});
});
}

View File

@@ -1,37 +1,64 @@
import 'package:eatvio_app/core/prefs.dart';
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/models/user_registration_model.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_cubit.dart';
import 'package:eatvio_app/features/registration/presentation/bloc/registration_cubit/registration_state.dart';
import 'package:eatvio_app/features/registration/presentation/pages/weight_screen.dart';
import 'package:eatvio_app/features/registration/repositories/registration_repository.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 'weight_screen_test.mocks.dart';
@GenerateMocks([RegistrationRepository, Prefs])
@GenerateNiceMocks([MockSpec<RegistrationCubit>()])
void main() {
group('WeightScreen', () {
late MockRegistrationRepository mockRegistrationRepository;
late RegistrationCubit registrationCubit;
setUp(() {
mockRegistrationRepository = MockRegistrationRepository();
registrationCubit = RegistrationCubit(
registrationRepository: mockRegistrationRepository,
prefs: MockPrefs(),
);
group('WeightScreen smoke', () {
setUpAll(() async {
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
});
tearDown(() {
registrationCubit.close();
setUp(() async {
await sl.reset();
sl.registerLazySingleton<AppConfig>(() => AppConfig(buildType: AppBuildType.tests)..setBaseUrl('http://localhost'));
});
Widget createTestWidget(UserRegistrationSheet sheet) {
const mockSheet = UserRegistrationSheet(
firstName: 'Test',
lastName: 'User',
email: 'test@test.com',
phone: '+1234567890',
password: 'password',
passwordConfirmation: 'password',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow, Russia',
responseBody: '{}',
lang: 'Русский',
weight: 70,
height: 175,
chestCircumference: 90,
waistCircumference: 80,
hipCircumference: 95,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: '',
aboutTakingPils: '',
aboutSportHobbies: '',
favoriteFoods: '',
unfavoriteFoods: '',
additionalInfo: '',
);
Widget wrap(Widget child) {
return MaterialApp(
theme: ThemeHelper().themeData(),
localizationsDelegates: const [
@@ -40,212 +67,30 @@ void main() {
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: const [Locale('ru')],
home: Scaffold(
body: BlocProvider<RegistrationCubit>(
create: (context) => registrationCubit,
child: WeightScreen(sheet: sheet),
),
),
supportedLocales: S.delegate.supportedLocales,
home: Scaffold(body: child),
);
}
testWidgets('displays screen with initial weight from sheet', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 75,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
testWidgets('renders weight screen', (tester) async {
final cubit = MockRegistrationCubit();
const state = RegistrationState(sheet: mockSheet);
when(cubit.state).thenReturn(state);
when(cubit.stream).thenAnswer((_) => Stream.value(state));
when(cubit.close()).thenAnswer((_) async => Future<void>.value());
when(cubit.updateSheet(any)).thenReturn(null);
await tester.pumpWidget(
BlocProvider<RegistrationCubit>.value(
value: cubit,
child: wrap(const WeightScreen(sheet: mockSheet)),
),
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
expect(find.text('75'), findsOneWidget);
});
testWidgets('displays empty field when weight is 0', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 0,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textField = find.byType(TextField);
expect(textField, findsOneWidget);
});
testWidgets('displays hint text', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 0,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
expect(find.text('кг'), findsOneWidget);
});
testWidgets('updates registration cubit when weight changes', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 70,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textField = find.byType(TextField);
expect(textField, findsOneWidget);
await tester.enterText(textField, '80');
await tester.pump();
await tester.pump(const Duration(milliseconds: 100));
// Verify that the cubit state was updated
expect(registrationCubit.state.sheet.weight, 80);
});
testWidgets('only accepts digits input', (WidgetTester tester) async {
const sheet = UserRegistrationSheet(
firstName: 'John',
lastName: 'Doe',
email: 'john@example.com',
password: 'password123',
passwordConfirmation: 'password123',
birthdate: '1990-01-01',
gender: 'male',
location: 'Moscow',
responseBody: '{}',
lang: 'ru',
weight: 0,
height: 180,
phone: '+1234567890',
chestCircumference: 100,
waistCircumference: 80,
hipCircumference: 90,
bloodPressureUp: 120,
bloodPressureDown: 80,
hasHypo: 0,
hasHyper: 0,
aboutAllergy: 'None',
aboutTakingPils: 'None',
aboutSportHobbies: 'Running',
favoriteFoods: 'Pizza',
unfavoriteFoods: 'Broccoli',
additionalInfo: 'No additional info',
);
await tester.pumpWidget(createTestWidget(sheet));
await tester.pumpAndSettle();
final textField = find.byType(TextField);
expect(textField, findsOneWidget);
// Try to enter non-digit characters
await tester.enterText(textField, 'abc');
await tester.pump();
// The text field should only accept digits
final textFieldWidget = tester.widget<TextField>(textField);
expect(textFieldWidget.controller?.text, isEmpty);
expect(find.byType(WeightScreen), findsOneWidget);
});
});
}