forked from eatvio/eatvio_app
chore(version): update app version to 1.3.5+85 and improve test coverage reporting in CI
This commit is contained in:
85
test/features/auth/entities/auth_result_entity_test.dart
Normal file
85
test/features/auth/entities/auth_result_entity_test.dart
Normal file
@@ -0,0 +1,85 @@
|
||||
import 'package:eatvio_app/features/auth/entities/auth_result_entity.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:vk_id/vk_id.dart';
|
||||
|
||||
void main() {
|
||||
group('AuthResultEntity', () {
|
||||
test('создает экземпляр с данными', () {
|
||||
const entity = AuthResultEntity(
|
||||
accessToken: 'token',
|
||||
userId: 'user123',
|
||||
clientId: 'client123',
|
||||
refreshToken: 'refresh',
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
email: 'john@example.com',
|
||||
phone: '+1234567890',
|
||||
gender: GenderEnum.male,
|
||||
birthDate: '1990-01-01',
|
||||
);
|
||||
|
||||
expect(entity.accessToken, 'token');
|
||||
expect(entity.userId, 'user123');
|
||||
expect(entity.gender, GenderEnum.male);
|
||||
});
|
||||
|
||||
test('создает экземпляр с минимальными данными', () {
|
||||
const entity = AuthResultEntity(
|
||||
accessToken: 'token',
|
||||
userId: 'user123',
|
||||
clientId: 'client123',
|
||||
);
|
||||
|
||||
expect(entity.accessToken, 'token');
|
||||
expect(entity.refreshToken, null);
|
||||
expect(entity.gender, null);
|
||||
});
|
||||
});
|
||||
|
||||
group('GenderEnum', () {
|
||||
test('fromVkGender - преобразует VkSex.male в GenderEnum.male', () {
|
||||
final result = GenderEnum.fromVkGender(VkSex.male);
|
||||
expect(result, GenderEnum.male);
|
||||
});
|
||||
|
||||
test('fromVkGender - преобразует VkSex.female в GenderEnum.female', () {
|
||||
final result = GenderEnum.fromVkGender(VkSex.female);
|
||||
expect(result, GenderEnum.female);
|
||||
});
|
||||
|
||||
test('fromVkGender - преобразует VkSex.notStated в GenderEnum.notSet', () {
|
||||
final result = GenderEnum.fromVkGender(VkSex.notStated);
|
||||
expect(result, GenderEnum.notSet);
|
||||
});
|
||||
|
||||
test('fromVkGender - возвращает null для null', () {
|
||||
final result = GenderEnum.fromVkGender(null);
|
||||
expect(result, null);
|
||||
});
|
||||
|
||||
test('fromString - преобразует "male" в GenderEnum.male', () {
|
||||
final result = GenderEnum.fromString('male');
|
||||
expect(result, GenderEnum.male);
|
||||
});
|
||||
|
||||
test('fromString - преобразует "female" в GenderEnum.female', () {
|
||||
final result = GenderEnum.fromString('female');
|
||||
expect(result, GenderEnum.female);
|
||||
});
|
||||
|
||||
test('fromString - преобразует "notSet" в GenderEnum.notSet', () {
|
||||
final result = GenderEnum.fromString('notSet');
|
||||
expect(result, GenderEnum.notSet);
|
||||
});
|
||||
|
||||
test('fromString - возвращает null для неизвестного значения', () {
|
||||
final result = GenderEnum.fromString('unknown');
|
||||
expect(result, null);
|
||||
});
|
||||
|
||||
test('fromString - возвращает null для null', () {
|
||||
final result = GenderEnum.fromString(null);
|
||||
expect(result, null);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -4,158 +4,169 @@ import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart';
|
||||
import 'package:eatvio_app/features/feed/repositories/feed_repository.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
|
||||
import 'blog_post_cubit_test.mocks.dart';
|
||||
class MockFeedRepository extends Mock implements FeedRepository {}
|
||||
|
||||
@GenerateNiceMocks([MockSpec<FeedRepository>()])
|
||||
void main() {
|
||||
group('BlogPostCubit', () {
|
||||
BlogPostCubit? blogPostCubit;
|
||||
late MockFeedRepository mockFeedRepository;
|
||||
late BlogPostCubit cubit;
|
||||
late MockFeedRepository mockRepository;
|
||||
|
||||
setUp(() {
|
||||
mockFeedRepository = MockFeedRepository();
|
||||
mockRepository = MockFeedRepository();
|
||||
cubit = BlogPostCubit(mockRepository);
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
if (blogPostCubit != null && !blogPostCubit!.isClosed) {
|
||||
await blogPostCubit!.close();
|
||||
blogPostCubit = null;
|
||||
}
|
||||
tearDown(() {
|
||||
cubit.close();
|
||||
});
|
||||
|
||||
test('начальное состояние - пустое', () {
|
||||
blogPostCubit = BlogPostCubit(mockFeedRepository);
|
||||
|
||||
expect(blogPostCubit!.state, isA<BlogPostState>());
|
||||
expect(blogPostCubit!.state.isLoading, isFalse);
|
||||
expect(blogPostCubit!.state.blogPostModel, isNull);
|
||||
test('начальное состояние - BlogPostState с isLoading: false', () {
|
||||
expect(cubit.state, isA<BlogPostState>());
|
||||
expect(cubit.state.isLoading, false);
|
||||
});
|
||||
|
||||
test('getBlogPost - успешная загрузка поста', () async {
|
||||
blogPostCubit = BlogPostCubit(mockFeedRepository);
|
||||
|
||||
final testPost = FeedBlogPostModel(
|
||||
id: 1,
|
||||
state: 'published',
|
||||
image: 'https://example.com/image.jpg',
|
||||
description: 'Test description',
|
||||
author: const Author(
|
||||
authorSlug: 'author',
|
||||
authorName: 'Author Name',
|
||||
authorProfileIcon: 'https://example.com/icon.jpg',
|
||||
authorIsMe: false,
|
||||
isEntitySubscribedByMe: null,
|
||||
authorPlaceInRating: null,
|
||||
),
|
||||
const postId = 1;
|
||||
final mockPost = FeedBlogPostModel(
|
||||
id: postId,
|
||||
title: 'Test Post',
|
||||
state: 'active',
|
||||
image: '',
|
||||
description: 'Test Content',
|
||||
videoUrl: '',
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
title: 'Test Post',
|
||||
totalLikes: 10,
|
||||
totalViews: 100,
|
||||
totalComments: 5,
|
||||
totalLikes: 0,
|
||||
totalViews: 0,
|
||||
totalComments: 0,
|
||||
wasLikedByMe: false,
|
||||
author: const Author(authorName: 'Test Author', authorSlug: 'test-author', authorProfileIcon: '', authorIsMe: false),
|
||||
);
|
||||
|
||||
when(mockFeedRepository.getBlogPost(id: 1))
|
||||
.thenAnswer((_) async => testPost);
|
||||
when(() => mockRepository.getBlogPost(id: postId)).thenAnswer((_) async => mockPost);
|
||||
|
||||
await blogPostCubit!.getBlogPost(1);
|
||||
await cubit.getBlogPost(postId);
|
||||
|
||||
expect(blogPostCubit!.state.blogPostModel, isNotNull);
|
||||
expect(blogPostCubit!.state.blogPostModel!.id, 1);
|
||||
expect(blogPostCubit!.state.isLoading, isFalse);
|
||||
expect(cubit.state.isLoading, false);
|
||||
expect(cubit.state.blogPostModel, mockPost);
|
||||
verify(() => mockRepository.getBlogPost(id: postId)).called(1);
|
||||
});
|
||||
|
||||
test('getBlogPost - обработка ошибки', () async {
|
||||
blogPostCubit = BlogPostCubit(mockFeedRepository);
|
||||
const postId = 1;
|
||||
|
||||
when(mockFeedRepository.getBlogPost(id: anyNamed('id')))
|
||||
.thenThrow(Exception('Ошибка загрузки'));
|
||||
when(() => mockRepository.getBlogPost(id: postId)).thenThrow(Exception('Error'));
|
||||
|
||||
await blogPostCubit!.getBlogPost(1);
|
||||
await cubit.getBlogPost(postId);
|
||||
|
||||
expect(blogPostCubit!.state.isLoading, isFalse);
|
||||
expect(cubit.state.isLoading, false);
|
||||
expect(cubit.state.blogPostModel, null);
|
||||
});
|
||||
|
||||
test('toggleLike - лайк поста', () async {
|
||||
blogPostCubit = BlogPostCubit(mockFeedRepository);
|
||||
|
||||
final testPost = FeedBlogPostModel(
|
||||
id: 1,
|
||||
state: 'published',
|
||||
image: 'https://example.com/image.jpg',
|
||||
description: 'Test description',
|
||||
author: const Author(
|
||||
authorSlug: 'author',
|
||||
authorName: 'Author Name',
|
||||
authorProfileIcon: 'https://example.com/icon.jpg',
|
||||
authorIsMe: false,
|
||||
isEntitySubscribedByMe: null,
|
||||
authorPlaceInRating: null,
|
||||
),
|
||||
const postId = 1;
|
||||
final mockPost = FeedBlogPostModel(
|
||||
id: postId,
|
||||
title: 'Test Post',
|
||||
state: 'active',
|
||||
image: '',
|
||||
description: 'Test Content',
|
||||
videoUrl: '',
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
title: 'Test Post',
|
||||
totalLikes: 10,
|
||||
totalViews: 100,
|
||||
totalComments: 5,
|
||||
totalLikes: 5,
|
||||
totalViews: 0,
|
||||
totalComments: 0,
|
||||
wasLikedByMe: false,
|
||||
author: const Author(authorName: 'Test Author', authorSlug: 'test-author', authorProfileIcon: '', authorIsMe: false),
|
||||
);
|
||||
|
||||
when(mockFeedRepository.getBlogPost(id: 1))
|
||||
.thenAnswer((_) async => testPost);
|
||||
when(mockFeedRepository.likeBlogPost(id: 1))
|
||||
.thenAnswer((_) async => {});
|
||||
when(() => mockRepository.likeBlogPost(id: postId)).thenAnswer((_) async => {});
|
||||
|
||||
await blogPostCubit!.getBlogPost(1);
|
||||
await blogPostCubit!.toggleLike();
|
||||
// Сначала загружаем пост
|
||||
when(() => mockRepository.getBlogPost(id: postId)).thenAnswer((_) async => mockPost);
|
||||
await cubit.getBlogPost(postId);
|
||||
|
||||
expect(blogPostCubit!.state.blogPostModel!.wasLikedByMe, isTrue);
|
||||
expect(blogPostCubit!.state.blogPostModel!.totalLikes, 11);
|
||||
// Затем лайкаем
|
||||
await cubit.toggleLike();
|
||||
|
||||
expect(cubit.state.blogPostModel?.wasLikedByMe, true);
|
||||
expect(cubit.state.blogPostModel?.totalLikes, 6);
|
||||
verify(() => mockRepository.likeBlogPost(id: postId)).called(1);
|
||||
});
|
||||
|
||||
test('toggleLike - убирает лайк', () async {
|
||||
blogPostCubit = BlogPostCubit(mockFeedRepository);
|
||||
|
||||
final testPost = FeedBlogPostModel(
|
||||
id: 1,
|
||||
state: 'published',
|
||||
image: 'https://example.com/image.jpg',
|
||||
description: 'Test description',
|
||||
author: const Author(
|
||||
authorSlug: 'author',
|
||||
authorName: 'Author Name',
|
||||
authorProfileIcon: 'https://example.com/icon.jpg',
|
||||
authorIsMe: false,
|
||||
isEntitySubscribedByMe: null,
|
||||
authorPlaceInRating: null,
|
||||
),
|
||||
const postId = 1;
|
||||
final mockPost = FeedBlogPostModel(
|
||||
id: postId,
|
||||
title: 'Test Post',
|
||||
state: 'active',
|
||||
image: '',
|
||||
description: 'Test Content',
|
||||
videoUrl: '',
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
title: 'Test Post',
|
||||
totalLikes: 10,
|
||||
totalViews: 100,
|
||||
totalComments: 5,
|
||||
totalLikes: 5,
|
||||
totalViews: 0,
|
||||
totalComments: 0,
|
||||
wasLikedByMe: true,
|
||||
author: const Author(authorName: 'Test Author', authorSlug: 'test-author', authorProfileIcon: '', authorIsMe: false),
|
||||
);
|
||||
|
||||
when(mockFeedRepository.getBlogPost(id: 1))
|
||||
.thenAnswer((_) async => testPost);
|
||||
when(mockFeedRepository.unlikedBlogPost(id: 1))
|
||||
.thenAnswer((_) async => {});
|
||||
when(() => mockRepository.unlikedBlogPost(id: postId)).thenAnswer((_) async => {});
|
||||
|
||||
await blogPostCubit!.getBlogPost(1);
|
||||
await blogPostCubit!.toggleLike();
|
||||
// Сначала загружаем пост
|
||||
when(() => mockRepository.getBlogPost(id: postId)).thenAnswer((_) async => mockPost);
|
||||
await cubit.getBlogPost(postId);
|
||||
|
||||
expect(blogPostCubit!.state.blogPostModel!.wasLikedByMe, isFalse);
|
||||
expect(blogPostCubit!.state.blogPostModel!.totalLikes, 9);
|
||||
// Затем убираем лайк
|
||||
await cubit.toggleLike();
|
||||
|
||||
expect(cubit.state.blogPostModel?.wasLikedByMe, false);
|
||||
expect(cubit.state.blogPostModel?.totalLikes, 4);
|
||||
verify(() => mockRepository.unlikedBlogPost(id: postId)).called(1);
|
||||
});
|
||||
|
||||
test('toggleLike - откат при ошибке', () async {
|
||||
const postId = 1;
|
||||
final mockPost = FeedBlogPostModel(
|
||||
id: postId,
|
||||
title: 'Test Post',
|
||||
state: 'active',
|
||||
image: '',
|
||||
description: 'Test Content',
|
||||
videoUrl: '',
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
totalLikes: 5,
|
||||
totalViews: 0,
|
||||
totalComments: 0,
|
||||
wasLikedByMe: false,
|
||||
author: const Author(authorName: 'Test Author', authorSlug: 'test-author', authorProfileIcon: '', authorIsMe: false),
|
||||
);
|
||||
|
||||
when(() => mockRepository.likeBlogPost(id: postId)).thenThrow(Exception('Error'));
|
||||
|
||||
// Сначала загружаем пост
|
||||
when(() => mockRepository.getBlogPost(id: postId)).thenAnswer((_) async => mockPost);
|
||||
await cubit.getBlogPost(postId);
|
||||
|
||||
// Затем пытаемся лайкнуть (с ошибкой)
|
||||
await cubit.toggleLike();
|
||||
|
||||
// Должен откатиться к исходному состоянию
|
||||
expect(cubit.state.blogPostModel?.wasLikedByMe, false);
|
||||
expect(cubit.state.blogPostModel?.totalLikes, 5);
|
||||
});
|
||||
|
||||
test('toggleLike - ничего не делает если пост не загружен', () async {
|
||||
await cubit.toggleLike();
|
||||
|
||||
expect(cubit.state.blogPostModel, null);
|
||||
verifyNever(() => mockRepository.likeBlogPost(id: any(named: 'id')));
|
||||
verifyNever(() => mockRepository.unlikedBlogPost(id: any(named: 'id')));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
import 'package:eatvio_app/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_cubit.dart';
|
||||
import 'package:eatvio_app/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_state.dart';
|
||||
import 'package:eatvio_app/features/blog_post_create/repositories/blog_post_repository.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
|
||||
class MockBlogPostRepository extends Mock implements BlogPostRepository {}
|
||||
|
||||
void main() {
|
||||
group('BlogPostCreateCubit', () {
|
||||
late BlogPostCreateCubit cubit;
|
||||
late MockBlogPostRepository mockRepository;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockBlogPostRepository();
|
||||
cubit = BlogPostCreateCubit(blogPostRepository: mockRepository);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
cubit.close();
|
||||
});
|
||||
|
||||
test('начальное состояние - BlogPostCreateState', () {
|
||||
expect(cubit.state, isA<BlogPostCreateState>());
|
||||
});
|
||||
|
||||
test('createBlogPost - успешное создание', () async {
|
||||
when(() => mockRepository.createBlogPost(any(), any(), any(), any()))
|
||||
.thenAnswer((_) async => {});
|
||||
|
||||
final result = await cubit.createBlogPost();
|
||||
|
||||
expect(result, true);
|
||||
expect(cubit.state, isA<BlogPostCreateStateLoaded>());
|
||||
verify(() => mockRepository.createBlogPost(null, null, null, null)).called(1);
|
||||
});
|
||||
|
||||
test('createBlogPost - обработка ошибки', () async {
|
||||
when(() => mockRepository.createBlogPost(any(), any(), any(), any()))
|
||||
.thenThrow(Exception('Error'));
|
||||
|
||||
final result = await cubit.createBlogPost();
|
||||
|
||||
expect(result, false);
|
||||
expect(cubit.state, isA<BlogPostCreateStateError>());
|
||||
final errorState = cubit.state as BlogPostCreateStateError;
|
||||
expect(errorState.errorMessage, contains('Error'));
|
||||
});
|
||||
|
||||
test('updateBlogPost - успешное обновление', () async {
|
||||
const id = 1;
|
||||
const title = 'Updated Title';
|
||||
|
||||
when(() => mockRepository.updateBlogPost(any(), any(), any(), any(), any(), any()))
|
||||
.thenAnswer((_) async => {});
|
||||
|
||||
final result = await cubit.updateBlogPost(id: id, title: title);
|
||||
|
||||
expect(result, true);
|
||||
expect(cubit.state, isA<BlogPostCreateStateLoaded>());
|
||||
verify(() => mockRepository.updateBlogPost(id, title, null, null, null, null)).called(1);
|
||||
});
|
||||
|
||||
test('updateBlogPost - обработка ошибки', () async {
|
||||
const id = 1;
|
||||
|
||||
when(() => mockRepository.updateBlogPost(any(), any(), any(), any(), any(), any()))
|
||||
.thenThrow(Exception('Error'));
|
||||
|
||||
final result = await cubit.updateBlogPost(id: id);
|
||||
|
||||
expect(result, false);
|
||||
expect(cubit.state, isA<BlogPostCreateStateError>());
|
||||
});
|
||||
|
||||
test('deleteBlogPost - успешное удаление', () async {
|
||||
const id = 1;
|
||||
|
||||
when(() => mockRepository.deleteBlogPost(id))
|
||||
.thenAnswer((_) async => {});
|
||||
|
||||
final result = await cubit.deleteBlogPost(id);
|
||||
|
||||
expect(result, true);
|
||||
verify(() => mockRepository.deleteBlogPost(id)).called(1);
|
||||
});
|
||||
|
||||
test('deleteBlogPost - обработка ошибки', () async {
|
||||
const id = 1;
|
||||
|
||||
when(() => mockRepository.deleteBlogPost(id))
|
||||
.thenThrow(Exception('Error'));
|
||||
|
||||
final result = await cubit.deleteBlogPost(id);
|
||||
|
||||
expect(result, false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,376 @@
|
||||
import 'package:eatvio_app/app_keys.dart';
|
||||
import 'package:eatvio_app/core/app_initializer.dart';
|
||||
import 'package:eatvio_app/core/di/app_config_registration.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/core/widgets/custom_text_form_field.dart';
|
||||
import 'package:eatvio_app/core/widgets/loader.dart';
|
||||
import 'package:eatvio_app/features/blog_post_create/bloc/blog_post_create_cubit/blog_post_create_cubit.dart';
|
||||
import 'package:eatvio_app/features/blog_post_create/presentation/pages/blog_post_create_screen.dart';
|
||||
import 'package:eatvio_app/features/blog_post_create/repositories/blog_post_repository.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/feed/models/feed_blog_post_model.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/feed_cubit/feed_state.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:network_image_mock/network_image_mock.dart';
|
||||
|
||||
import 'blog_post_create_screen_test.mocks.dart';
|
||||
|
||||
@GenerateMocks([BlogPostRepository, BlogPostCreateCubit, FeedCubit])
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('BlogPostCreateScreen', () {
|
||||
late MockBlogPostRepository mockBlogPostRepository;
|
||||
late BlogPostCreateCubit blogPostCreateCubit;
|
||||
late MockFeedCubit mockFeedCubit;
|
||||
|
||||
setUp(() async {
|
||||
await sl.reset();
|
||||
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
|
||||
AppConfigRegistration.registerAppConfig(buildType: AppBuildType.tests);
|
||||
mockBlogPostRepository = MockBlogPostRepository();
|
||||
blogPostCreateCubit = BlogPostCreateCubit(blogPostRepository: mockBlogPostRepository);
|
||||
mockFeedCubit = MockFeedCubit();
|
||||
when(mockFeedCubit.state).thenReturn(const FeedState.loading());
|
||||
when(mockFeedCubit.stream).thenAnswer((_) => Stream.value(const FeedState.loading()));
|
||||
sl.registerLazySingleton<FeedCubit>(() => mockFeedCubit);
|
||||
sl.registerLazySingleton<BlogPostCreateCubit>(() => blogPostCreateCubit);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
blogPostCreateCubit.close();
|
||||
});
|
||||
|
||||
Widget createTestWidget({FeedBlogPostModel? feedBlogPostModel, bool canPop = false}) {
|
||||
final router = GoRouter(
|
||||
initialLocation: '/blog-post-create',
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/home',
|
||||
builder: (context, state) => Scaffold(
|
||||
body: Center(child: Text('Home')),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/blog-post-create',
|
||||
builder: (context, state) => MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider<BlogPostCreateCubit>.value(
|
||||
value: blogPostCreateCubit,
|
||||
),
|
||||
BlocProvider<FeedCubit>.value(
|
||||
value: mockFeedCubit,
|
||||
),
|
||||
],
|
||||
child: BlogPostCreateScreen(feedBlogPostModel: feedBlogPostModel),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
return MaterialApp.router(
|
||||
routerConfig: router,
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [Locale('ru'), Locale('en')],
|
||||
locale: const Locale('ru'),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays all form fields when creating new blog post', (tester) async {
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Заголовок'), findsOneWidget);
|
||||
expect(find.text('Описание'), findsOneWidget);
|
||||
expect(find.text('Изображение поста'), findsOneWidget);
|
||||
expect(find.text('Ссылка на видео'), findsOneWidget);
|
||||
expect(find.byKey(AppKeys.blogPostCreateScreenTitleTextField), findsOneWidget);
|
||||
expect(find.byKey(AppKeys.blogPostCreateScreenContentTextField), findsOneWidget);
|
||||
expect(find.byKey(AppKeys.blogPostCreateScreenVideoLinkTextField), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('pre-fills form fields when editing existing blog post', (tester) async {
|
||||
final existingPost = FeedBlogPostModel(
|
||||
id: 1,
|
||||
title: 'Test Title',
|
||||
description: 'Test Description',
|
||||
videoUrl: 'https://youtube.com/watch?v=test',
|
||||
image: '', // Changed: removed image so video field is visible
|
||||
state: 'published',
|
||||
author: const Author(
|
||||
authorSlug: 'test-author',
|
||||
authorName: 'Test Author',
|
||||
authorProfileIcon: 'avatar.jpg',
|
||||
authorIsMe: true,
|
||||
),
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
totalLikes: 0,
|
||||
totalViews: 0,
|
||||
totalComments: 0,
|
||||
wasLikedByMe: false,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(createTestWidget(feedBlogPostModel: existingPost));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final titleField = tester.widget<CustomTextFormField>(find.byKey(AppKeys.blogPostCreateScreenTitleTextField));
|
||||
expect(titleField.controller?.text, 'Test Title');
|
||||
|
||||
final descriptionField = tester.widget<CustomTextFormField>(find.byKey(AppKeys.blogPostCreateScreenContentTextField));
|
||||
expect(descriptionField.controller?.text, 'Test Description');
|
||||
|
||||
// Only check video field if it's visible (when image is null)
|
||||
final videoFieldFinder = find.byKey(AppKeys.blogPostCreateScreenVideoLinkTextField);
|
||||
if (videoFieldFinder.evaluate().isNotEmpty) {
|
||||
final videoField = tester.widget<CustomTextFormField>(videoFieldFinder);
|
||||
expect(videoField.controller?.text, 'https://youtube.com/watch?v=test');
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('hides video field when image is present', (tester) async {
|
||||
await mockNetworkImagesFor(() async {
|
||||
final existingPost = FeedBlogPostModel(
|
||||
id: 1,
|
||||
title: 'Test Title',
|
||||
description: 'Test Description',
|
||||
videoUrl: '',
|
||||
image: 'http://localhost/storage/test_image.jpg',
|
||||
state: 'published',
|
||||
author: const Author(
|
||||
authorSlug: 'test-author',
|
||||
authorName: 'Test Author',
|
||||
authorProfileIcon: 'http://localhost/storage/avatar.jpg',
|
||||
authorIsMe: true,
|
||||
),
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
totalLikes: 0,
|
||||
totalViews: 0,
|
||||
totalComments: 0,
|
||||
wasLikedByMe: false,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(createTestWidget(feedBlogPostModel: existingPost));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Ссылка на видео'), findsNothing);
|
||||
expect(find.byKey(AppKeys.blogPostCreateScreenVideoLinkTextField), findsNothing);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('hides image field when video URL is present', (tester) async {
|
||||
final existingPost = FeedBlogPostModel(
|
||||
id: 1,
|
||||
title: 'Test Title',
|
||||
description: 'Test Description',
|
||||
videoUrl: 'https://youtube.com/watch?v=test',
|
||||
image: '',
|
||||
state: 'published',
|
||||
author: const Author(
|
||||
authorSlug: 'test-author',
|
||||
authorName: 'Test Author',
|
||||
authorProfileIcon: 'avatar.jpg',
|
||||
authorIsMe: true,
|
||||
),
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
totalLikes: 0,
|
||||
totalViews: 0,
|
||||
totalComments: 0,
|
||||
wasLikedByMe: false,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(createTestWidget(feedBlogPostModel: existingPost));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Изображение поста'), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('allows entering text in title field', (tester) async {
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.enterText(find.byKey(AppKeys.blogPostCreateScreenTitleTextField), 'New Title');
|
||||
await tester.pump();
|
||||
|
||||
final titleField = tester.widget<CustomTextFormField>(find.byKey(AppKeys.blogPostCreateScreenTitleTextField));
|
||||
expect(titleField.controller?.text, 'New Title');
|
||||
});
|
||||
|
||||
testWidgets('allows entering text in description field', (tester) async {
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.enterText(find.byKey(AppKeys.blogPostCreateScreenContentTextField), 'New Description');
|
||||
await tester.pump();
|
||||
|
||||
final descriptionField = tester.widget<CustomTextFormField>(find.byKey(AppKeys.blogPostCreateScreenContentTextField));
|
||||
expect(descriptionField.controller?.text, 'New Description');
|
||||
});
|
||||
|
||||
testWidgets('allows entering text in video URL field', (tester) async {
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.enterText(find.byKey(AppKeys.blogPostCreateScreenVideoLinkTextField), 'https://youtube.com/watch?v=new');
|
||||
await tester.pump();
|
||||
|
||||
final videoField = tester.widget<CustomTextFormField>(find.byKey(AppKeys.blogPostCreateScreenVideoLinkTextField));
|
||||
expect(videoField.controller?.text, 'https://youtube.com/watch?v=new');
|
||||
});
|
||||
|
||||
testWidgets('displays create button', (tester) async {
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Создать'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('shows loading state when creating blog post', (tester) async {
|
||||
when(mockBlogPostRepository.createBlogPost(any, any, any, any)).thenAnswer((_) async {
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
return;
|
||||
});
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.enterText(find.byKey(AppKeys.blogPostCreateScreenTitleTextField), 'Test Title');
|
||||
await tester.enterText(find.byKey(AppKeys.blogPostCreateScreenContentTextField), 'Test Description');
|
||||
await tester.pump();
|
||||
|
||||
// Tap create button - find by text and scroll if needed
|
||||
final createButton = find.text('Создать');
|
||||
await tester.ensureVisible(createButton);
|
||||
await tester.tap(createButton);
|
||||
await tester.pump();
|
||||
|
||||
// Check for Loader widget (not CircularProgressIndicator)
|
||||
expect(find.byType(Loader), findsWidgets);
|
||||
|
||||
// Wait for timer to complete
|
||||
await tester.pump(const Duration(milliseconds: 150));
|
||||
await tester.pumpAndSettle();
|
||||
});
|
||||
|
||||
testWidgets('calls FeedCubit.loadFeedBlogPostList when blog post is created successfully', (tester) async {
|
||||
when(mockBlogPostRepository.createBlogPost(any, any, any, any)).thenAnswer((_) async {
|
||||
return;
|
||||
});
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final titleField = find.byKey(AppKeys.blogPostCreateScreenTitleTextField);
|
||||
final contentField = find.byKey(AppKeys.blogPostCreateScreenContentTextField);
|
||||
|
||||
await tester.ensureVisible(titleField);
|
||||
await tester.ensureVisible(contentField);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.enterText(titleField, 'Test Title');
|
||||
await tester.enterText(contentField, 'Test Description');
|
||||
await tester.pump();
|
||||
|
||||
final createButton = find.text('Создать');
|
||||
await tester.ensureVisible(createButton);
|
||||
await tester.tap(createButton, warnIfMissed: false);
|
||||
await tester.pump();
|
||||
|
||||
// Wait for async operation
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
verify(mockFeedCubit.loadFeedBlogPostList()).called(1);
|
||||
});
|
||||
|
||||
testWidgets('calls updateBlogPost when editing existing post', (tester) async {
|
||||
await mockNetworkImagesFor(() async {
|
||||
when(mockBlogPostRepository.updateBlogPost(any, any, any, any, any, any)).thenAnswer((_) async {
|
||||
return;
|
||||
});
|
||||
|
||||
final existingPost = FeedBlogPostModel(
|
||||
id: 1,
|
||||
title: 'Test Title',
|
||||
description: 'Test Description',
|
||||
videoUrl: '',
|
||||
image: 'http://localhost/storage/test_image.jpg',
|
||||
state: 'published',
|
||||
author: const Author(
|
||||
authorSlug: 'test-author',
|
||||
authorName: 'Test Author',
|
||||
authorProfileIcon: 'http://localhost/storage/avatar.jpg',
|
||||
authorIsMe: true,
|
||||
),
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
totalLikes: 0,
|
||||
totalViews: 0,
|
||||
totalComments: 0,
|
||||
wasLikedByMe: false,
|
||||
);
|
||||
|
||||
await tester.pumpWidget(createTestWidget(feedBlogPostModel: existingPost, canPop: true));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
final titleField = find.byKey(AppKeys.blogPostCreateScreenTitleTextField);
|
||||
expect(titleField, findsOneWidget);
|
||||
|
||||
await tester.enterText(titleField, 'Updated Title');
|
||||
await tester.pump();
|
||||
|
||||
// Find and tap create button - ensure it's visible
|
||||
final createButton = find.text('Создать');
|
||||
await tester.ensureVisible(createButton);
|
||||
await tester.tap(createButton, warnIfMissed: false);
|
||||
await tester.pump();
|
||||
|
||||
// Wait for async operation
|
||||
await tester.pump(const Duration(milliseconds: 200));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
verify(mockBlogPostRepository.updateBlogPost(
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
any,
|
||||
)).called(1);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('displays AppBar', (tester) async {
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(AppBar), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('has scrollable body', (tester) async {
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(SingleChildScrollView), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eatvio_app/features/blog_post_create/repositories/blog_post_repository.dart';
|
||||
import 'package:eatvio_app/features/blog_post_create/services/blog_post_service.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
|
||||
class MockBlogPostService extends Mock implements BlogPostService {}
|
||||
|
||||
class FakeFormData extends Fake implements FormData {}
|
||||
|
||||
void main() {
|
||||
group('BlogPostRepository', () {
|
||||
late BlogPostRepository repository;
|
||||
late MockBlogPostService mockService;
|
||||
|
||||
setUpAll(() {
|
||||
registerFallbackValue(FakeFormData());
|
||||
});
|
||||
|
||||
setUp(() {
|
||||
mockService = MockBlogPostService();
|
||||
repository = BlogPostRepository(blogPostService: mockService);
|
||||
});
|
||||
|
||||
test('deleteBlogPost вызывает сервис', () async {
|
||||
const id = 1;
|
||||
|
||||
when(() => mockService.deleteBlogPost(id: id)).thenAnswer((_) async => {});
|
||||
|
||||
await repository.deleteBlogPost(id);
|
||||
|
||||
verify(() => mockService.deleteBlogPost(id: id)).called(1);
|
||||
});
|
||||
|
||||
test('createBlogPost вызывает сервис с FormData', () async {
|
||||
const title = 'Test Title';
|
||||
const description = 'Test Description';
|
||||
|
||||
when(() => mockService.createBlogPost(formData: any(named: 'formData'))).thenAnswer((_) async => {});
|
||||
|
||||
await repository.createBlogPost(title, null, description, null);
|
||||
|
||||
verify(() => mockService.createBlogPost(formData: any(named: 'formData'))).called(1);
|
||||
});
|
||||
|
||||
test('updateBlogPost вызывает сервис с FormData', () async {
|
||||
const id = 1;
|
||||
const title = 'Updated Title';
|
||||
|
||||
when(
|
||||
() => mockService.updateBlogPost(
|
||||
id: id,
|
||||
formData: any(named: 'formData'),
|
||||
),
|
||||
).thenAnswer((_) async => {});
|
||||
|
||||
await repository.updateBlogPost(id, title, null, null, null, null);
|
||||
|
||||
verify(
|
||||
() => mockService.updateBlogPost(
|
||||
id: id,
|
||||
formData: any(named: 'formData'),
|
||||
),
|
||||
).called(1);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -4,39 +4,36 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('NewMessagesCubit', () {
|
||||
late NewMessagesCubit newMessagesCubit;
|
||||
late NewMessagesCubit cubit;
|
||||
|
||||
setUp(() {
|
||||
newMessagesCubit = NewMessagesCubit();
|
||||
cubit = NewMessagesCubit();
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
if (!newMessagesCubit.isClosed) {
|
||||
await newMessagesCubit.close();
|
||||
}
|
||||
tearDown(() {
|
||||
cubit.close();
|
||||
});
|
||||
|
||||
test('начальное состояние - NewMessagesState.empty', () {
|
||||
expect(newMessagesCubit.state, const NewMessagesState.empty());
|
||||
test('начальное состояние - empty', () {
|
||||
expect(cubit.state, isA<NewMessagesStateEmpty>());
|
||||
});
|
||||
|
||||
test('incrementCounter - увеличивает счётчик сообщений', () {
|
||||
newMessagesCubit.incrementCounter();
|
||||
test('incrementCounter увеличивает счетчик и эмитит loaded состояние', () {
|
||||
cubit.incrementCounter();
|
||||
|
||||
expect(newMessagesCubit.state, isA<NewMessagesStateLoaded>());
|
||||
final loadedState = newMessagesCubit.state as NewMessagesStateLoaded;
|
||||
expect(cubit.state, isA<NewMessagesStateLoaded>());
|
||||
final loadedState = cubit.state as NewMessagesStateLoaded;
|
||||
expect(loadedState.messagesCount, 1);
|
||||
});
|
||||
|
||||
test('incrementCounter - увеличивает счётчик несколько раз', () {
|
||||
newMessagesCubit.incrementCounter();
|
||||
newMessagesCubit.incrementCounter();
|
||||
newMessagesCubit.incrementCounter();
|
||||
test('incrementCounter увеличивает счетчик несколько раз', () {
|
||||
cubit.incrementCounter();
|
||||
cubit.incrementCounter();
|
||||
cubit.incrementCounter();
|
||||
|
||||
expect(newMessagesCubit.state, isA<NewMessagesStateLoaded>());
|
||||
final loadedState = newMessagesCubit.state as NewMessagesStateLoaded;
|
||||
expect(cubit.state, isA<NewMessagesStateLoaded>());
|
||||
final loadedState = cubit.state as NewMessagesStateLoaded;
|
||||
expect(loadedState.messagesCount, 3);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,30 +3,42 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('CalendarModel', () {
|
||||
test('создает CalendarModel с правильными значениями', () {
|
||||
test('создает экземпляр с данными', () {
|
||||
const model = CalendarModel(
|
||||
date: '2024-01-01',
|
||||
date: '2024-01-15',
|
||||
isCurrentDayIncludedInTheChosenDietProgression: true,
|
||||
diary: null,
|
||||
);
|
||||
|
||||
expect(model.date, '2024-01-01');
|
||||
expect(model.isCurrentDayIncludedInTheChosenDietProgression, isTrue);
|
||||
expect(model.diary, isNull);
|
||||
expect(model.date, '2024-01-15');
|
||||
expect(model.isCurrentDayIncludedInTheChosenDietProgression, true);
|
||||
expect(model.diary, null);
|
||||
});
|
||||
|
||||
test('fromJson создает CalendarModel из JSON', () {
|
||||
test('fromJson создает модель из JSON', () {
|
||||
final json = {
|
||||
'date': '2024-01-01',
|
||||
'date': '2024-01-15',
|
||||
'is_current_day_included_in_the_chosen_diet_progression': true,
|
||||
'diary': null,
|
||||
};
|
||||
|
||||
final model = CalendarModel.fromJson(json);
|
||||
|
||||
expect(model.date, '2024-01-01');
|
||||
expect(model.isCurrentDayIncludedInTheChosenDietProgression, isTrue);
|
||||
expect(model.date, '2024-01-15');
|
||||
expect(model.isCurrentDayIncludedInTheChosenDietProgression, true);
|
||||
});
|
||||
|
||||
test('toJson преобразует модель в JSON', () {
|
||||
const model = CalendarModel(
|
||||
date: '2024-01-15',
|
||||
isCurrentDayIncludedInTheChosenDietProgression: true,
|
||||
diary: null,
|
||||
);
|
||||
|
||||
final json = model.toJson();
|
||||
|
||||
expect(json['date'], '2024-01-15');
|
||||
expect(json['is_current_day_included_in_the_chosen_diet_progression'], true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,62 +3,51 @@ import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_cubit.da
|
||||
import 'package:eatvio_app/features/calendar/presentation/bloc/calendar_state.dart';
|
||||
import 'package:eatvio_app/features/calendar/repositories/calendar_repository.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
|
||||
import 'calendar_cubit_test.mocks.dart';
|
||||
class MockCalendarRepository extends Mock implements CalendarRepository {}
|
||||
|
||||
@GenerateNiceMocks([MockSpec<CalendarRepository>()])
|
||||
void main() {
|
||||
group('CalendarCubit', () {
|
||||
CalendarCubit? cubit;
|
||||
late CalendarCubit cubit;
|
||||
late MockCalendarRepository mockRepository;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockCalendarRepository();
|
||||
cubit = CalendarCubit(calendarRepository: mockRepository);
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
if (cubit != null && !cubit!.isClosed) {
|
||||
await cubit!.close();
|
||||
cubit = null;
|
||||
}
|
||||
tearDown(() {
|
||||
cubit.close();
|
||||
});
|
||||
|
||||
test('начальное состояние - loading', () {
|
||||
cubit = CalendarCubit(calendarRepository: mockRepository);
|
||||
|
||||
expect(cubit!.state, isA<CalendarStateLoading>());
|
||||
expect(cubit.state, isA<CalendarStateLoading>());
|
||||
});
|
||||
|
||||
test('loadCalendarList - успешная загрузка календаря', () async {
|
||||
cubit = CalendarCubit(calendarRepository: mockRepository);
|
||||
test('loadCalendarList - успешная загрузка', () async {
|
||||
final mockCalendarList = <CalendarModel>[];
|
||||
|
||||
const testCalendar = CalendarModel(
|
||||
date: '2024-01-01',
|
||||
isCurrentDayIncludedInTheChosenDietProgression: true,
|
||||
);
|
||||
when(() => mockRepository.getCalendar())
|
||||
.thenAnswer((_) async => mockCalendarList);
|
||||
|
||||
when(mockRepository.getCalendar())
|
||||
.thenAnswer((_) async => [testCalendar]);
|
||||
await cubit.loadCalendarList();
|
||||
|
||||
await cubit!.loadCalendarList();
|
||||
|
||||
expect(cubit!.state, isA<CalendarStateLoaded>());
|
||||
final loadedState = cubit!.state as CalendarStateLoaded;
|
||||
expect(loadedState.calendarList.length, 1);
|
||||
expect(cubit.state, isA<CalendarStateLoaded>());
|
||||
final loadedState = cubit.state as CalendarStateLoaded;
|
||||
expect(loadedState.calendarList, mockCalendarList);
|
||||
verify(() => mockRepository.getCalendar()).called(1);
|
||||
});
|
||||
|
||||
test('loadCalendarList - обработка ошибки', () async {
|
||||
cubit = CalendarCubit(calendarRepository: mockRepository);
|
||||
when(() => mockRepository.getCalendar())
|
||||
.thenThrow(Exception('Error'));
|
||||
|
||||
when(mockRepository.getCalendar())
|
||||
.thenThrow(Exception('Ошибка загрузки'));
|
||||
await cubit.loadCalendarList();
|
||||
|
||||
await cubit!.loadCalendarList();
|
||||
|
||||
expect(cubit!.state, isA<CalendarStateError>());
|
||||
expect(cubit.state, isA<CalendarStateError>());
|
||||
final errorState = cubit.state as CalendarStateError;
|
||||
expect(errorState.errorMessage, isNotEmpty);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
import 'package:eatvio_app/core/app_initializer.dart';
|
||||
import 'package:eatvio_app/core/di/app_config_registration.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/cancel_plan_bottom_sheet/cancel_plan_bottom_sheet.dart';
|
||||
import 'package:eatvio_app/features/cancel_plan_bottom_sheet/cubit/cancel_plan_cubit.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'cancel_plan_bottom_sheet_test.mocks.dart';
|
||||
|
||||
@GenerateMocks([CancelPlanCubit])
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('CancelPlanBottomSheet', () {
|
||||
late MockCancelPlanCubit mockCancelPlanCubit;
|
||||
|
||||
setUp(() async {
|
||||
await sl.reset();
|
||||
AppConfigRegistration.registerAppConfig(buildType: AppBuildType.tests);
|
||||
mockCancelPlanCubit = MockCancelPlanCubit();
|
||||
});
|
||||
|
||||
Widget createTestWidget({
|
||||
bool enableForm = false,
|
||||
required int planId,
|
||||
}) {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [Locale('ru'), Locale('en')],
|
||||
locale: const Locale('ru'),
|
||||
home: BlocProvider<CancelPlanCubit>.value(
|
||||
value: mockCancelPlanCubit,
|
||||
child: Scaffold(
|
||||
body: CancelPlanBottomSheet(
|
||||
enableForm: enableForm,
|
||||
planId: planId,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays cancel plan bottom sheet without form', (tester) async {
|
||||
when(mockCancelPlanCubit.cancelChosenPlan(id: anyNamed('id')))
|
||||
.thenAnswer((_) async => true);
|
||||
|
||||
await tester.pumpWidget(createTestWidget(planId: 1));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(CancelPlanBottomSheet), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays cancel plan bottom sheet with form', (tester) async {
|
||||
when(mockCancelPlanCubit.cancelChosenPlan(
|
||||
id: anyNamed('id'),
|
||||
reason: anyNamed('reason'),
|
||||
price: anyNamed('price'),
|
||||
)).thenAnswer((_) async => true);
|
||||
|
||||
await tester.pumpWidget(createTestWidget(enableForm: true, planId: 1));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(CancelPlanBottomSheet), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays form fields when enableForm is true', (tester) async {
|
||||
when(mockCancelPlanCubit.cancelChosenPlan(
|
||||
id: anyNamed('id'),
|
||||
reason: anyNamed('reason'),
|
||||
price: anyNamed('price'),
|
||||
)).thenAnswer((_) async => true);
|
||||
|
||||
await tester.pumpWidget(createTestWidget(enableForm: true, planId: 1));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(CancelPlanBottomSheet), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,84 +1,81 @@
|
||||
import 'package:eatvio_app/features/cancel_plan_bottom_sheet/cubit/cancel_plan_cubit.dart';
|
||||
import 'package:eatvio_app/features/cancel_plan_bottom_sheet/cubit/cancel_plan_state.dart';
|
||||
import 'package:eatvio_app/features/cancel_plan_bottom_sheet/models/cancelation_model.dart';
|
||||
import 'package:eatvio_app/features/cancel_plan_bottom_sheet/repository/cancel_plan_repository.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
|
||||
import 'cancel_plan_cubit_test.mocks.dart';
|
||||
class MockCancelPlanRepository extends Mock implements CancelPlanRepository {}
|
||||
|
||||
@GenerateNiceMocks([MockSpec<CancelPlanRepository>()])
|
||||
void main() {
|
||||
group('CancelPlanCubit', () {
|
||||
CancelPlanCubit? cubit;
|
||||
late CancelPlanCubit cubit;
|
||||
late MockCancelPlanRepository mockRepository;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockCancelPlanRepository();
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
if (cubit != null && !cubit!.isClosed) {
|
||||
await cubit!.close();
|
||||
cubit = null;
|
||||
}
|
||||
});
|
||||
|
||||
test('начальное состояние - пустое', () {
|
||||
cubit = CancelPlanCubit(cancelPlanRepository: mockRepository);
|
||||
|
||||
expect(cubit!.state, isA<CancelPlanState>());
|
||||
});
|
||||
|
||||
test('cancelChosenPlan - успешная отмена плана без причины', () async {
|
||||
cubit = CancelPlanCubit(cancelPlanRepository: mockRepository);
|
||||
|
||||
when(mockRepository.cancelChosenPlan(
|
||||
id: 1,
|
||||
body: anyNamed('body'),
|
||||
)).thenAnswer((_) async => {});
|
||||
|
||||
final result = await cubit!.cancelChosenPlan(id: 1);
|
||||
|
||||
expect(result, isTrue);
|
||||
verify(mockRepository.cancelChosenPlan(id: 1, body: null)).called(1);
|
||||
tearDown(() {
|
||||
cubit.close();
|
||||
});
|
||||
|
||||
test('cancelChosenPlan - успешная отмена плана с причиной', () async {
|
||||
cubit = CancelPlanCubit(cancelPlanRepository: mockRepository);
|
||||
|
||||
when(mockRepository.cancelChosenPlan(
|
||||
id: anyNamed('id'),
|
||||
body: anyNamed('body'),
|
||||
)).thenAnswer((_) async => {});
|
||||
|
||||
final result = await cubit!.cancelChosenPlan(
|
||||
id: 1,
|
||||
reason: 'Test reason',
|
||||
price: 1000,
|
||||
);
|
||||
|
||||
expect(result, isTrue);
|
||||
verify(mockRepository.cancelChosenPlan(
|
||||
id: 1,
|
||||
body: anyNamed('body'),
|
||||
)).called(1);
|
||||
test('начальное состояние - CancelPlanState', () {
|
||||
expect(cubit.state, isA<CancelPlanState>());
|
||||
});
|
||||
|
||||
test('cancelChosenPlan - обработка ошибки', () async {
|
||||
cubit = CancelPlanCubit(cancelPlanRepository: mockRepository);
|
||||
test('cancelChosenPlan - успешная отмена без причины', () async {
|
||||
const planId = 1;
|
||||
|
||||
when(mockRepository.cancelChosenPlan(
|
||||
id: anyNamed('id'),
|
||||
body: anyNamed('body'),
|
||||
)).thenAnswer((_) async {
|
||||
throw Exception('Ошибка отмены');
|
||||
});
|
||||
when(() => mockRepository.cancelChosenPlan(id: planId, body: null))
|
||||
.thenAnswer((_) async => {});
|
||||
|
||||
final result = await cubit!.cancelChosenPlan(id: 1);
|
||||
final result = await cubit.cancelChosenPlan(id: planId);
|
||||
|
||||
expect(result, isFalse);
|
||||
expect(result, true);
|
||||
verify(() => mockRepository.cancelChosenPlan(id: planId, body: null)).called(1);
|
||||
});
|
||||
|
||||
test('cancelChosenPlan - успешная отмена с причиной и ценой', () async {
|
||||
const planId = 1;
|
||||
const reason = 'Test reason';
|
||||
const price = 1000;
|
||||
final body = CancelationModel(description: reason, price: price);
|
||||
|
||||
when(() => mockRepository.cancelChosenPlan(id: planId, body: body))
|
||||
.thenAnswer((_) async => {});
|
||||
|
||||
final result = await cubit.cancelChosenPlan(id: planId, reason: reason, price: price);
|
||||
|
||||
expect(result, true);
|
||||
verify(() => mockRepository.cancelChosenPlan(id: planId, body: body)).called(1);
|
||||
});
|
||||
|
||||
test('cancelChosenPlan - возвращает false при ошибке', () async {
|
||||
const planId = 1;
|
||||
|
||||
when(() => mockRepository.cancelChosenPlan(id: planId, body: null))
|
||||
.thenThrow(Exception('Error'));
|
||||
|
||||
final result = await cubit.cancelChosenPlan(id: planId);
|
||||
|
||||
expect(result, false);
|
||||
});
|
||||
|
||||
test('cancelChosenPlan - не создает body если reason или price null', () async {
|
||||
const planId = 1;
|
||||
|
||||
when(() => mockRepository.cancelChosenPlan(id: planId, body: null))
|
||||
.thenAnswer((_) async => {});
|
||||
|
||||
// Только reason
|
||||
await cubit.cancelChosenPlan(id: planId, reason: 'reason');
|
||||
verify(() => mockRepository.cancelChosenPlan(id: planId, body: null)).called(1);
|
||||
|
||||
// Только price
|
||||
await cubit.cancelChosenPlan(id: planId, price: 100);
|
||||
verify(() => mockRepository.cancelChosenPlan(id: planId, body: null)).called(1);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,27 +3,28 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('CancelationModel', () {
|
||||
test('создает CancelationModel с правильными значениями', () {
|
||||
final model = CancelationModel(
|
||||
description: 'Test reason',
|
||||
price: 1000,
|
||||
);
|
||||
test('создает экземпляр с description и price', () {
|
||||
final model = CancelationModel(description: 'Test reason', price: 1000);
|
||||
|
||||
expect(model.description, 'Test reason');
|
||||
expect(model.price, 1000);
|
||||
});
|
||||
|
||||
test('fromJson создает CancelationModel из JSON', () {
|
||||
final json = {
|
||||
'description': 'Test reason',
|
||||
'price': 1000,
|
||||
};
|
||||
test('fromJson создает модель из JSON', () {
|
||||
final json = {'description': 'Test reason', 'price': 1000};
|
||||
|
||||
final model = CancelationModel.fromJson(json);
|
||||
|
||||
expect(model.description, 'Test reason');
|
||||
expect(model.price, 1000);
|
||||
});
|
||||
|
||||
test('toJson преобразует модель в JSON', () {
|
||||
final model = CancelationModel(description: 'Test reason', price: 1000);
|
||||
final json = model.toJson();
|
||||
|
||||
expect(json['description'], 'Test reason');
|
||||
expect(json['price'], 1000);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,258 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/chat/models/chat_message_model.dart';
|
||||
import 'package:eatvio_app/features/chat/models/chat_room_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/chat_entry_widget.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:network_image_mock/network_image_mock.dart';
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('ChatEntryWidget', () {
|
||||
Widget createTestWidget(ChatRoom chatRoom) {
|
||||
return MaterialApp.router(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [Locale('ru'), Locale('en')],
|
||||
locale: const Locale('ru'),
|
||||
routerConfig: GoRouter(
|
||||
initialLocation: '/',
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/',
|
||||
builder: (context, state) => Scaffold(
|
||||
body: ChatEntryWidget(chatRoom: chatRoom),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/chatScreen',
|
||||
name: 'chatScreen',
|
||||
builder: (context, state) => Scaffold(
|
||||
appBar: AppBar(title: const Text('Chat')),
|
||||
body: Center(child: Text('Chat: ${state.extra}')),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays chat room with user name', (tester) async {
|
||||
final chatRoom = ChatRoom(
|
||||
id: 'test-id',
|
||||
users: Users(
|
||||
fromChatUser: ChatUser(
|
||||
id: 1,
|
||||
name: 'From User',
|
||||
profilePhotoPath: null,
|
||||
profilePhotoUrl: 'http://localhost/photo.jpg',
|
||||
),
|
||||
toChatUser: ChatUser(
|
||||
id: 2,
|
||||
name: 'Test User',
|
||||
profilePhotoPath: null,
|
||||
profilePhotoUrl: 'http://localhost/photo.jpg',
|
||||
),
|
||||
),
|
||||
unreadMessagesCount: 0,
|
||||
lastMessage: null,
|
||||
chosenPlan: null,
|
||||
);
|
||||
|
||||
mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(createTestWidget(chatRoom));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Test User'), findsOneWidget);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('displays chat room with last message', (tester) async {
|
||||
final chatRoom = ChatRoom(
|
||||
id: 'test-id',
|
||||
users: Users(
|
||||
fromChatUser: ChatUser(
|
||||
id: 1,
|
||||
name: 'From User',
|
||||
profilePhotoPath: null,
|
||||
profilePhotoUrl: 'http://localhost/photo.jpg',
|
||||
),
|
||||
toChatUser: ChatUser(
|
||||
id: 2,
|
||||
name: 'Test User',
|
||||
profilePhotoPath: null,
|
||||
profilePhotoUrl: 'http://localhost/photo.jpg',
|
||||
),
|
||||
),
|
||||
unreadMessagesCount: 0,
|
||||
lastMessage: ChatMessageModel(
|
||||
id: 1,
|
||||
data: 'Test message',
|
||||
updatedAt: DateTime.now(),
|
||||
isCurrentUserAuthor: false,
|
||||
mediaData: null,
|
||||
authorId: 1,
|
||||
isRead: false,
|
||||
roomId: 'test-id',
|
||||
),
|
||||
chosenPlan: null,
|
||||
);
|
||||
|
||||
mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(createTestWidget(chatRoom));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Test message'), findsOneWidget);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('displays chat room with unread messages count', (tester) async {
|
||||
final chatRoom = ChatRoom(
|
||||
id: 'test-id',
|
||||
users: Users(
|
||||
fromChatUser: ChatUser(
|
||||
id: 1,
|
||||
name: 'From User',
|
||||
profilePhotoPath: null,
|
||||
profilePhotoUrl: 'http://localhost/photo.jpg',
|
||||
),
|
||||
toChatUser: ChatUser(
|
||||
id: 2,
|
||||
name: 'Test User',
|
||||
profilePhotoPath: null,
|
||||
profilePhotoUrl: 'http://localhost/photo.jpg',
|
||||
),
|
||||
),
|
||||
unreadMessagesCount: 5,
|
||||
lastMessage: null,
|
||||
chosenPlan: null,
|
||||
);
|
||||
|
||||
mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(createTestWidget(chatRoom));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('5'), findsOneWidget);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('displays message from current user', (tester) async {
|
||||
final chatRoom = ChatRoom(
|
||||
id: 'test-id',
|
||||
users: Users(
|
||||
fromChatUser: ChatUser(
|
||||
id: 1,
|
||||
name: 'From User',
|
||||
profilePhotoPath: null,
|
||||
profilePhotoUrl: 'http://localhost/photo.jpg',
|
||||
),
|
||||
toChatUser: ChatUser(
|
||||
id: 2,
|
||||
name: 'Test User',
|
||||
profilePhotoPath: null,
|
||||
profilePhotoUrl: 'http://localhost/photo.jpg',
|
||||
),
|
||||
),
|
||||
unreadMessagesCount: 0,
|
||||
lastMessage: ChatMessageModel(
|
||||
id: 1,
|
||||
data: 'Test message',
|
||||
updatedAt: DateTime.now(),
|
||||
isCurrentUserAuthor: true,
|
||||
mediaData: null,
|
||||
authorId: 1,
|
||||
isRead: false,
|
||||
roomId: 'test-id',
|
||||
),
|
||||
chosenPlan: null,
|
||||
);
|
||||
|
||||
mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(createTestWidget(chatRoom));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.textContaining('Вы:'), findsOneWidget);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('displays media attachment message', (tester) async {
|
||||
final chatRoom = ChatRoom(
|
||||
id: 'test-id',
|
||||
users: Users(
|
||||
fromChatUser: ChatUser(
|
||||
id: 1,
|
||||
name: 'From User',
|
||||
profilePhotoPath: null,
|
||||
profilePhotoUrl: 'http://localhost/photo.jpg',
|
||||
),
|
||||
toChatUser: ChatUser(
|
||||
id: 2,
|
||||
name: 'Test User',
|
||||
profilePhotoPath: null,
|
||||
profilePhotoUrl: 'http://localhost/photo.jpg',
|
||||
),
|
||||
),
|
||||
unreadMessagesCount: 0,
|
||||
lastMessage: ChatMessageModel(
|
||||
id: 1,
|
||||
data: 'Test message',
|
||||
updatedAt: DateTime.now(),
|
||||
isCurrentUserAuthor: false,
|
||||
mediaData: [{'type': 'image', 'url': 'https://example.com/image.jpg'}],
|
||||
authorId: 1,
|
||||
isRead: false,
|
||||
roomId: 'test-id',
|
||||
),
|
||||
chosenPlan: null,
|
||||
);
|
||||
|
||||
mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(createTestWidget(chatRoom));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.textContaining('📎 Вложение'), findsOneWidget);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('truncates long user names', (tester) async {
|
||||
final longName = 'A' * 30;
|
||||
final chatRoom = ChatRoom(
|
||||
id: 'test-id',
|
||||
users: Users(
|
||||
fromChatUser: ChatUser(
|
||||
id: 1,
|
||||
name: 'From User',
|
||||
profilePhotoPath: null,
|
||||
profilePhotoUrl: 'http://localhost/photo.jpg',
|
||||
),
|
||||
toChatUser: ChatUser(
|
||||
id: 2,
|
||||
name: longName,
|
||||
profilePhotoPath: null,
|
||||
profilePhotoUrl: 'http://localhost/photo.jpg',
|
||||
),
|
||||
),
|
||||
unreadMessagesCount: 0,
|
||||
lastMessage: null,
|
||||
chosenPlan: null,
|
||||
);
|
||||
|
||||
mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(createTestWidget(chatRoom));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.textContaining('...'), findsOneWidget);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,117 +1,108 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/chat/presentation/widgets/chat_search_bar_widget.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('ChatSearchBarWidget Tests', () {
|
||||
Widget createTestWidget(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),
|
||||
group('ChatSearchBarWidget', () {
|
||||
testWidgets('displays search bar with default icon', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: ChatSearchBarWidget(
|
||||
onSuffixIconTap: () {},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('ChatSearchBarWidget - отображается с дефолтными значениями', (WidgetTester tester) async {
|
||||
final widget = ChatSearchBarWidget(onSuffixIconTap: () {});
|
||||
|
||||
await tester.pumpWidget(createTestWidget(widget));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(TextFormField), findsOneWidget);
|
||||
expect(find.byType(ChatSearchBarWidget), findsOneWidget);
|
||||
expect(find.byIcon(Icons.search), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('ChatSearchBarWidget - вызывает onSuffixIconTap при нажатии на иконку очистки', (WidgetTester tester) async {
|
||||
testWidgets('displays custom hint text', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: ChatSearchBarWidget(
|
||||
hintText: 'Search messages',
|
||||
onSuffixIconTap: () {},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(ChatSearchBarWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('calls onSuffixIconTap when clear button is tapped', (tester) async {
|
||||
bool suffixTapped = false;
|
||||
final controller = TextEditingController(text: 'test');
|
||||
final widget = ChatSearchBarWidget(
|
||||
controller: controller,
|
||||
onSuffixIconTap: () {
|
||||
suffixTapped = true;
|
||||
},
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: ChatSearchBarWidget(
|
||||
controller: controller,
|
||||
onSuffixIconTap: () {
|
||||
suffixTapped = true;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(createTestWidget(widget));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Находим иконку очистки и нажимаем на неё
|
||||
final clearIcon = find.byIcon(Icons.clear);
|
||||
expect(clearIcon, findsOneWidget);
|
||||
await tester.tap(clearIcon);
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.byIcon(Icons.clear));
|
||||
await tester.pump();
|
||||
|
||||
expect(suffixTapped, isTrue);
|
||||
expect(controller.text, isEmpty);
|
||||
});
|
||||
|
||||
testWidgets('ChatSearchBarWidget - вызывает onChanged при вводе текста', (WidgetTester tester) async {
|
||||
testWidgets('clears controller when clear button is tapped', (tester) async {
|
||||
final controller = TextEditingController(text: 'test');
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: ChatSearchBarWidget(
|
||||
controller: controller,
|
||||
onSuffixIconTap: () {},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(controller.text, 'test');
|
||||
await tester.tap(find.byIcon(Icons.clear));
|
||||
await tester.pump();
|
||||
|
||||
expect(controller.text, '');
|
||||
});
|
||||
|
||||
testWidgets('calls onChanged when text is entered', (tester) async {
|
||||
String? changedValue;
|
||||
final controller = TextEditingController();
|
||||
final widget = ChatSearchBarWidget(
|
||||
controller: controller,
|
||||
onChanged: (value) {
|
||||
changedValue = value;
|
||||
},
|
||||
onSuffixIconTap: () {},
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: ChatSearchBarWidget(
|
||||
controller: controller,
|
||||
onChanged: (value) {
|
||||
changedValue = value;
|
||||
},
|
||||
onSuffixIconTap: () {},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(createTestWidget(widget));
|
||||
await tester.pumpAndSettle();
|
||||
await tester.enterText(find.byType(TextFormField), 'test');
|
||||
await tester.pump();
|
||||
|
||||
await tester.enterText(find.byType(TextFormField), 'test query');
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(changedValue, equals('test query'));
|
||||
});
|
||||
|
||||
testWidgets('ChatSearchBarWidget - отображает кастомный hintText', (WidgetTester tester) async {
|
||||
const hintText = 'Search chats...';
|
||||
final widget = ChatSearchBarWidget(hintText: hintText, onSuffixIconTap: () {});
|
||||
|
||||
await tester.pumpWidget(createTestWidget(widget));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text(hintText), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('ChatSearchBarWidget - использует кастомный prefix', (WidgetTester tester) async {
|
||||
const customPrefix = Icon(Icons.filter_list);
|
||||
final widget = ChatSearchBarWidget(prefix: customPrefix, onSuffixIconTap: () {});
|
||||
|
||||
await tester.pumpWidget(createTestWidget(widget));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byIcon(Icons.filter_list), findsOneWidget);
|
||||
expect(find.byIcon(Icons.search), findsNothing);
|
||||
});
|
||||
|
||||
testWidgets('ChatSearchBarWidget - использует кастомный suffix', (WidgetTester tester) async {
|
||||
bool suffixTapped = false;
|
||||
final customSuffix = IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: () {
|
||||
suffixTapped = true;
|
||||
},
|
||||
);
|
||||
final widget = ChatSearchBarWidget(suffix: customSuffix, onSuffixIconTap: () {});
|
||||
|
||||
await tester.pumpWidget(createTestWidget(widget));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byIcon(Icons.close));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(suffixTapped, isTrue);
|
||||
expect(changedValue, 'test');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,34 +3,45 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('ComplainModel', () {
|
||||
test('создает ComplainModel с дефолтными значениями', () {
|
||||
test('создает экземпляр с дефолтными значениями', () {
|
||||
const model = ComplainModel();
|
||||
|
||||
expect(model.description, isNull);
|
||||
expect(model.tags, isEmpty);
|
||||
expect(model.description, null);
|
||||
expect(model.tags, []);
|
||||
});
|
||||
|
||||
test('создает ComplainModel с описанием и тегами', () {
|
||||
test('создает экземпляр с description и tags', () {
|
||||
const model = ComplainModel(
|
||||
description: 'Test complaint',
|
||||
description: 'Test description',
|
||||
tags: ['tag1', 'tag2'],
|
||||
);
|
||||
|
||||
expect(model.description, 'Test complaint');
|
||||
expect(model.description, 'Test description');
|
||||
expect(model.tags, ['tag1', 'tag2']);
|
||||
});
|
||||
|
||||
test('fromJson создает ComplainModel из JSON', () {
|
||||
test('fromJson создает модель из JSON', () {
|
||||
final json = {
|
||||
'description': 'Test complaint',
|
||||
'description': 'Test description',
|
||||
'tags': ['tag1', 'tag2'],
|
||||
};
|
||||
|
||||
final model = ComplainModel.fromJson(json);
|
||||
|
||||
expect(model.description, 'Test complaint');
|
||||
expect(model.description, 'Test description');
|
||||
expect(model.tags, ['tag1', 'tag2']);
|
||||
});
|
||||
|
||||
test('toJson преобразует модель в JSON', () {
|
||||
const model = ComplainModel(
|
||||
description: 'Test description',
|
||||
tags: ['tag1', 'tag2'],
|
||||
);
|
||||
|
||||
final json = model.toJson();
|
||||
|
||||
expect(json['description'], 'Test description');
|
||||
expect(json['tags'], ['tag1', 'tag2']);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,143 +1,124 @@
|
||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||
import 'package:eatvio_app/features/complaining/models/complain_model.dart';
|
||||
import 'package:eatvio_app/features/complaining/presentation/complaining_bottom_sheet.dart';
|
||||
import 'package:eatvio_app/features/complaining/presentation/cubit/complaining_cubit.dart';
|
||||
import 'package:eatvio_app/features/complaining/presentation/cubit/complaining_state.dart';
|
||||
import 'package:eatvio_app/features/complaining/repositories/complaining_repository.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
|
||||
import 'complaining_cubit_test.mocks.dart';
|
||||
class MockComplainingRepository extends Mock implements ComplainingRepository {}
|
||||
|
||||
@GenerateNiceMocks([MockSpec<ComplainingRepository>()])
|
||||
void main() {
|
||||
group('ComplainingCubit', () {
|
||||
ComplainingCubit? complainingCubit;
|
||||
late ComplainingCubit cubit;
|
||||
late MockComplainingRepository mockRepository;
|
||||
|
||||
setUpAll(() {
|
||||
registerFallbackValue(const ComplainModel());
|
||||
});
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockComplainingRepository();
|
||||
cubit = ComplainingCubit(repository: mockRepository);
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
if (complainingCubit != null && !complainingCubit!.isClosed) {
|
||||
await complainingCubit!.close();
|
||||
complainingCubit = null;
|
||||
}
|
||||
tearDown(() {
|
||||
cubit.close();
|
||||
});
|
||||
|
||||
test('начальное состояние - пустое', () {
|
||||
complainingCubit = ComplainingCubit(repository: mockRepository);
|
||||
|
||||
expect(complainingCubit!.state.contentType, isNull);
|
||||
expect(complainingCubit!.state.category, isNull);
|
||||
expect(complainingCubit!.state.wasSentSuccessfully, isNull);
|
||||
test('начальное состояние - ComplainingState', () {
|
||||
expect(cubit.state, isA<ComplainingState>());
|
||||
});
|
||||
|
||||
test('setContentTypeAndIdentifier - устанавливает тип контента и идентификатор', () {
|
||||
complainingCubit = ComplainingCubit(repository: mockRepository);
|
||||
|
||||
complainingCubit!.setContentTypeAndIdentifier(
|
||||
test('setContentTypeAndIdentifier устанавливает тип и идентификатор', () {
|
||||
cubit.setContentTypeAndIdentifier(
|
||||
contentType: ComplainedContent.diet,
|
||||
id: 1,
|
||||
);
|
||||
|
||||
expect(complainingCubit!.state.contentType, ComplainedContent.diet);
|
||||
expect(complainingCubit!.state.contentId, 1);
|
||||
expect(cubit.state.contentType, ComplainedContent.diet);
|
||||
expect(cubit.state.contentId, 1);
|
||||
});
|
||||
|
||||
test('setCategory - устанавливает категорию жалобы', () {
|
||||
complainingCubit = ComplainingCubit(repository: mockRepository);
|
||||
|
||||
complainingCubit!.setCategory(ComplainType.spam);
|
||||
|
||||
expect(complainingCubit!.state.category, ComplainType.spam);
|
||||
});
|
||||
|
||||
test('setTags - устанавливает теги', () {
|
||||
complainingCubit = ComplainingCubit(repository: mockRepository);
|
||||
|
||||
complainingCubit!.setTags(['tag1', 'tag2']);
|
||||
|
||||
expect(complainingCubit!.state.complainInfo.tags, ['tag1', 'tag2']);
|
||||
});
|
||||
|
||||
test('toggleDescription - переключает описание', () {
|
||||
complainingCubit = ComplainingCubit(repository: mockRepository);
|
||||
|
||||
complainingCubit!.toggleDescription();
|
||||
expect(complainingCubit!.state.complainInfo.description, '');
|
||||
|
||||
complainingCubit!.toggleDescription();
|
||||
expect(complainingCubit!.state.complainInfo.description, isNull);
|
||||
});
|
||||
|
||||
test('setDescription - устанавливает описание', () {
|
||||
complainingCubit = ComplainingCubit(repository: mockRepository);
|
||||
|
||||
complainingCubit!.setDescription('Test description');
|
||||
|
||||
expect(complainingCubit!.state.complainInfo.description, 'Test description');
|
||||
});
|
||||
|
||||
test('complain - отправляет жалобу на диету', () async {
|
||||
complainingCubit = ComplainingCubit(repository: mockRepository);
|
||||
|
||||
complainingCubit!.setContentTypeAndIdentifier(
|
||||
contentType: ComplainedContent.diet,
|
||||
id: 1,
|
||||
);
|
||||
complainingCubit!.setCategory(ComplainType.spam);
|
||||
|
||||
when(mockRepository.sendDietComplain(
|
||||
id: 1,
|
||||
category: anyNamed('category'),
|
||||
body: anyNamed('body'),
|
||||
)).thenAnswer((_) async => {});
|
||||
|
||||
await complainingCubit!.complain();
|
||||
|
||||
expect(complainingCubit!.state.wasSentSuccessfully, isTrue);
|
||||
});
|
||||
|
||||
test('complain - отправляет жалобу на план', () async {
|
||||
complainingCubit = ComplainingCubit(repository: mockRepository);
|
||||
|
||||
complainingCubit!.setContentTypeAndIdentifier(
|
||||
test('setContentTypeAndIdentifier устанавливает slug', () {
|
||||
cubit.setContentTypeAndIdentifier(
|
||||
contentType: ComplainedContent.plan,
|
||||
slug: 'test-plan',
|
||||
slug: 'test-slug',
|
||||
);
|
||||
complainingCubit!.setCategory(ComplainType.spam);
|
||||
|
||||
when(mockRepository.sendPlanComplain(
|
||||
slug: 'test-plan',
|
||||
category: anyNamed('category'),
|
||||
body: anyNamed('body'),
|
||||
)).thenAnswer((_) async => {});
|
||||
|
||||
await complainingCubit!.complain();
|
||||
|
||||
expect(complainingCubit!.state.wasSentSuccessfully, isTrue);
|
||||
expect(cubit.state.contentType, ComplainedContent.plan);
|
||||
expect(cubit.state.contentSlug, 'test-slug');
|
||||
});
|
||||
|
||||
test('complain - обработка ошибки', () async {
|
||||
complainingCubit = ComplainingCubit(repository: mockRepository);
|
||||
test('setCategory устанавливает категорию', () {
|
||||
cubit.setCategory(ComplainType.spam);
|
||||
|
||||
complainingCubit!.setContentTypeAndIdentifier(
|
||||
contentType: ComplainedContent.diet,
|
||||
id: 1,
|
||||
);
|
||||
complainingCubit!.setCategory(ComplainType.spam);
|
||||
expect(cubit.state.category, ComplainType.spam);
|
||||
});
|
||||
|
||||
when(mockRepository.sendDietComplain(
|
||||
id: anyNamed('id'),
|
||||
category: anyNamed('category'),
|
||||
body: anyNamed('body'),
|
||||
)).thenThrow(Exception('Ошибка отправки'));
|
||||
test('setTags устанавливает теги', () {
|
||||
final tags = ['tag1', 'tag2'];
|
||||
cubit.setTags(tags);
|
||||
|
||||
await complainingCubit!.complain();
|
||||
expect(cubit.state.complainInfo.tags, tags);
|
||||
});
|
||||
|
||||
expect(complainingCubit!.state.wasSentSuccessfully, isFalse);
|
||||
test('toggleDescription переключает описание', () {
|
||||
// Включает описание
|
||||
cubit.toggleDescription();
|
||||
expect(cubit.state.complainInfo.description, '');
|
||||
|
||||
// Выключает описание
|
||||
cubit.toggleDescription();
|
||||
expect(cubit.state.complainInfo.description, null);
|
||||
});
|
||||
|
||||
test('setDescription устанавливает описание', () {
|
||||
const description = 'Test description';
|
||||
cubit.setDescription(description);
|
||||
|
||||
expect(cubit.state.complainInfo.description, description);
|
||||
});
|
||||
|
||||
test('complain - отправляет жалобу на diet', () async {
|
||||
const id = 1;
|
||||
|
||||
when(() => mockRepository.sendDietComplain(
|
||||
id: id,
|
||||
category: any(named: 'category'),
|
||||
body: any(named: 'body'),
|
||||
)).thenAnswer((_) async => {});
|
||||
|
||||
cubit.setContentTypeAndIdentifier(contentType: ComplainedContent.diet, id: id);
|
||||
cubit.setCategory(ComplainType.spam);
|
||||
cubit.setTags(['tag1']);
|
||||
|
||||
await cubit.complain();
|
||||
|
||||
expect(cubit.state.wasSentSuccessfully, true);
|
||||
verify(() => mockRepository.sendDietComplain(
|
||||
id: id,
|
||||
category: any(named: 'category'),
|
||||
body: any(named: 'body'),
|
||||
)).called(1);
|
||||
});
|
||||
|
||||
test('complain - возвращает false при ошибке', () async {
|
||||
const id = 1;
|
||||
|
||||
when(() => mockRepository.sendDietComplain(
|
||||
id: id,
|
||||
category: any(named: 'category'),
|
||||
body: any(named: 'body'),
|
||||
)).thenThrow(Exception('Error'));
|
||||
|
||||
cubit.setContentTypeAndIdentifier(contentType: ComplainedContent.diet, id: id);
|
||||
cubit.setCategory(ComplainType.spam);
|
||||
|
||||
await cubit.complain();
|
||||
|
||||
expect(cubit.state.wasSentSuccessfully, false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,10 @@ import 'package:eatvio_app/features/consultant_rating/models/statistics_model.da
|
||||
import 'package:eatvio_app/features/consultant_rating/repositories/consultant_rating_repository.dart';
|
||||
import 'package:eatvio_app/features/consultant_rating/services/consultant_rating_service.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
|
||||
import 'consultant_rating_repository_test.mocks.dart';
|
||||
class MockConsultantRatingService extends Mock implements ConsultantRatingService {}
|
||||
|
||||
@GenerateNiceMocks([MockSpec<ConsultantRatingService>()])
|
||||
void main() {
|
||||
group('ConsultantRatingRepository', () {
|
||||
late ConsultantRatingRepository repository;
|
||||
@@ -19,47 +17,49 @@ void main() {
|
||||
repository = ConsultantRatingRepository(mockService);
|
||||
});
|
||||
|
||||
test('getConsultantStatistics - успешное получение статистики', () async {
|
||||
final expectedStats = StatisticsModel(
|
||||
countReferal: 10,
|
||||
blogPostsCount: 5,
|
||||
recipesCount: 3,
|
||||
dietsCount: 2,
|
||||
consultationsCount: 15,
|
||||
qwe: 1,
|
||||
refLink: 'https://example.com/ref',
|
||||
);
|
||||
test('getConsultantStatistics - успешный запрос', () async {
|
||||
final mockStatistics = StatisticsModel();
|
||||
|
||||
when(mockService.getConsultantStatistics(date: null))
|
||||
.thenAnswer((_) async => expectedStats);
|
||||
when(() => mockService.getConsultantStatistics(date: any(named: 'date')))
|
||||
.thenAnswer((_) async => mockStatistics);
|
||||
|
||||
final result = await repository.getConsultantStatistics();
|
||||
|
||||
expect(result, equals(expectedStats));
|
||||
expect(result.countReferal, 10);
|
||||
verify(mockService.getConsultantStatistics(date: null)).called(1);
|
||||
expect(result, mockStatistics);
|
||||
verify(() => mockService.getConsultantStatistics(date: null)).called(1);
|
||||
});
|
||||
|
||||
test('getScoreLogs - успешное получение логов', () async {
|
||||
final expectedLogs = [
|
||||
RatingModel(
|
||||
date: DateTime(2024, 1, 1),
|
||||
type: RatingEnum.addedRecipe,
|
||||
amount: 10,
|
||||
),
|
||||
];
|
||||
test('getConsultantStatistics - с датой', () async {
|
||||
const date = '2024-01-01';
|
||||
final mockStatistics = StatisticsModel();
|
||||
|
||||
final pagination = RatingPaginationModel(data: expectedLogs);
|
||||
when(() => mockService.getConsultantStatistics(date: date))
|
||||
.thenAnswer((_) async => mockStatistics);
|
||||
|
||||
when(mockService.getScoreLogs(date: null))
|
||||
.thenAnswer((_) async => pagination);
|
||||
final result = await repository.getConsultantStatistics(date: date);
|
||||
|
||||
expect(result, mockStatistics);
|
||||
verify(() => mockService.getConsultantStatistics(date: date)).called(1);
|
||||
});
|
||||
|
||||
test('getScoreLogs - успешный запрос', () async {
|
||||
final mockRatings = <RatingModel>[];
|
||||
final mockPagination = RatingPaginationModel(data: mockRatings);
|
||||
|
||||
when(() => mockService.getScoreLogs(date: any(named: 'date')))
|
||||
.thenAnswer((_) async => mockPagination);
|
||||
|
||||
final result = await repository.getScoreLogs();
|
||||
|
||||
expect(result.length, 1);
|
||||
expect(result.first.amount, 10);
|
||||
verify(mockService.getScoreLogs(date: null)).called(1);
|
||||
expect(result, mockRatings);
|
||||
verify(() => mockService.getScoreLogs(date: null)).called(1);
|
||||
});
|
||||
|
||||
test('getScoreLogs - пробрасывает ошибку', () async {
|
||||
when(() => mockService.getScoreLogs(date: any(named: 'date')))
|
||||
.thenThrow(Exception('Error'));
|
||||
|
||||
expect(() => repository.getScoreLogs(), throwsException);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,80 +1,51 @@
|
||||
import 'package:eatvio_app/core/enums/base_state.dart';
|
||||
import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
|
||||
import 'package:eatvio_app/features/consultations/presentation/cubit/consultations_cubit.dart';
|
||||
import 'package:eatvio_app/features/consultations/presentation/cubit/consultations_state.dart';
|
||||
import 'package:eatvio_app/features/consultations/repositories/consultations_repository.dart';
|
||||
import 'package:eatvio_app/features/plans/enums/chosen_plan_state_enum.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
|
||||
import 'consultations_cubit_test.mocks.dart';
|
||||
class MockConsultationsRepository extends Mock implements ConsultationsRepository {}
|
||||
|
||||
@GenerateNiceMocks([MockSpec<ConsultationsRepository>()])
|
||||
void main() {
|
||||
group('ConsultationsCubit', () {
|
||||
ConsultationsCubit? cubit;
|
||||
late ConsultationsCubit cubit;
|
||||
late MockConsultationsRepository mockRepository;
|
||||
|
||||
setUp(() {
|
||||
mockRepository = MockConsultationsRepository();
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
if (cubit != null && !cubit!.isClosed) {
|
||||
await cubit!.close();
|
||||
cubit = null;
|
||||
}
|
||||
});
|
||||
|
||||
test('начальное состояние - initial', () {
|
||||
cubit = ConsultationsCubit(consultationsRepository: mockRepository);
|
||||
|
||||
expect(cubit!.state.state, BaseState.initial);
|
||||
expect(cubit!.state.consultations, isEmpty);
|
||||
});
|
||||
|
||||
test('loadConsultations - успешная загрузка консультаций', () async {
|
||||
cubit = ConsultationsCubit(consultationsRepository: mockRepository);
|
||||
tearDown(() {
|
||||
cubit.close();
|
||||
});
|
||||
|
||||
final testConsultations = [
|
||||
ConsultationModel(
|
||||
id: 1,
|
||||
chosenPlanState: ChosenPlanStateEnum.stateInProgress,
|
||||
planTitle: 'Test Plan',
|
||||
userName: 'Test User',
|
||||
userSlug: 'test-user',
|
||||
consultantPayment: 1000.0,
|
||||
duration: 30,
|
||||
currentDiaryDay: 1,
|
||||
userProfilePhotoUrl: 'https://example.com/photo.jpg',
|
||||
consultationOptionPrice: 5000,
|
||||
startDate: DateTime(2024, 1, 1),
|
||||
endDate: DateTime(2024, 1, 31),
|
||||
consultantId: 1,
|
||||
diaries: [],
|
||||
personalDietId: null,
|
||||
),
|
||||
];
|
||||
test('начальное состояние - ComplaintsState', () {
|
||||
expect(cubit.state, isA<ConsultationsState>());
|
||||
});
|
||||
|
||||
when(mockRepository.getConsultations())
|
||||
.thenAnswer((_) async => testConsultations);
|
||||
test('loadConsultations - успешная загрузка', () async {
|
||||
final mockConsultations = <ConsultationModel>[];
|
||||
|
||||
await cubit!.loadConsultations();
|
||||
when(() => mockRepository.getConsultations())
|
||||
.thenAnswer((_) async => mockConsultations);
|
||||
|
||||
expect(cubit!.state.state, BaseState.success);
|
||||
expect(cubit!.state.consultations.length, 1);
|
||||
await cubit.loadConsultations();
|
||||
|
||||
expect(cubit.state.state, BaseState.success);
|
||||
expect(cubit.state.consultations, mockConsultations);
|
||||
verify(() => mockRepository.getConsultations()).called(1);
|
||||
});
|
||||
|
||||
test('loadConsultations - обработка ошибки', () async {
|
||||
cubit = ConsultationsCubit(consultationsRepository: mockRepository);
|
||||
when(() => mockRepository.getConsultations())
|
||||
.thenThrow(Exception('Error'));
|
||||
|
||||
when(mockRepository.getConsultations())
|
||||
.thenThrow(Exception('Ошибка загрузки'));
|
||||
await cubit.loadConsultations();
|
||||
|
||||
await cubit!.loadConsultations();
|
||||
|
||||
expect(cubit!.state.state, BaseState.error);
|
||||
expect(cubit.state.state, BaseState.error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
import 'package:eatvio_app/features/consultations/models/consultation_model.dart';
|
||||
import 'package:eatvio_app/features/consultations/repositories/consultations_repository.dart';
|
||||
import 'package:eatvio_app/features/consultations/services/consultation_service.dart';
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/models/consultant_finance_model.dart';
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/models/statistic_model.dart';
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/models/user_purchases_model.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
|
||||
class MockConsultationService extends Mock implements ConsultationService {}
|
||||
|
||||
class FakeStatisticModel extends Fake implements StatisticModel {}
|
||||
|
||||
void main() {
|
||||
group('ConsultationsRepository', () {
|
||||
late ConsultationsRepository repository;
|
||||
late MockConsultationService mockService;
|
||||
|
||||
setUpAll(() {
|
||||
registerFallbackValue(FakeStatisticModel());
|
||||
});
|
||||
|
||||
setUp(() {
|
||||
mockService = MockConsultationService();
|
||||
repository = ConsultationsRepository(consultationService: mockService);
|
||||
});
|
||||
|
||||
test('getConsultations - успешный запрос', () async {
|
||||
final mockConsultations = <ConsultationModel>[];
|
||||
final mockPagination = ConsultationPaginationModel(data: mockConsultations);
|
||||
|
||||
when(() => mockService.getConsultations())
|
||||
.thenAnswer((_) async => mockPagination);
|
||||
|
||||
final result = await repository.getConsultations();
|
||||
|
||||
expect(result, mockConsultations);
|
||||
verify(() => mockService.getConsultations()).called(1);
|
||||
});
|
||||
|
||||
test('getConsultations - пробрасывает ошибку', () async {
|
||||
when(() => mockService.getConsultations())
|
||||
.thenThrow(Exception('Error'));
|
||||
|
||||
expect(() => repository.getConsultations(), throwsException);
|
||||
});
|
||||
|
||||
test('getFilteredConsultations - успешный запрос', () async {
|
||||
final mockConsultations = <ConsultationModel>[];
|
||||
final mockPagination = ConsultationPaginationModel(data: mockConsultations);
|
||||
|
||||
when(() => mockService.getFilteredConsultations(
|
||||
state: any(named: 'state'),
|
||||
date: any(named: 'date'),
|
||||
stateComparison: any(named: 'stateComparison'),
|
||||
dateComparison: any(named: 'dateComparison'),
|
||||
))
|
||||
.thenAnswer((_) async => mockPagination);
|
||||
|
||||
final result = await repository.getFilteredConsultations();
|
||||
|
||||
expect(result, mockConsultations);
|
||||
verify(() => mockService.getFilteredConsultations(
|
||||
state: null,
|
||||
date: null,
|
||||
stateComparison: null,
|
||||
dateComparison: null,
|
||||
)).called(1);
|
||||
});
|
||||
|
||||
test('getStatistic - успешный запрос', () async {
|
||||
final mockStatistic = StatisticModel(
|
||||
total: 10,
|
||||
inProgress: 5,
|
||||
finished: 3,
|
||||
canceled: 2,
|
||||
);
|
||||
|
||||
when(() => mockService.getStatistics())
|
||||
.thenAnswer((_) async => mockStatistic);
|
||||
|
||||
final result = await repository.getStatistic();
|
||||
|
||||
expect(result, mockStatistic);
|
||||
verify(() => mockService.getStatistics()).called(1);
|
||||
});
|
||||
|
||||
test('getConsultantFinances - успешный запрос', () async {
|
||||
final mockFinances = <ConsultantFinanceModel>[];
|
||||
|
||||
when(() => mockService.getConsultantFinances(any(), any()))
|
||||
.thenAnswer((_) async => mockFinances);
|
||||
|
||||
final result = await repository.getConsultantFinances(null, null);
|
||||
|
||||
expect(result, mockFinances);
|
||||
verify(() => mockService.getConsultantFinances(null, null)).called(1);
|
||||
});
|
||||
|
||||
test('getUserPurchases - успешный запрос', () async {
|
||||
final mockPurchases = <UserPurchasesModel>[];
|
||||
|
||||
when(() => mockService.getUserPurchases(any(), any()))
|
||||
.thenAnswer((_) async => mockPurchases);
|
||||
|
||||
final result = await repository.getUserPurchases(null, null);
|
||||
|
||||
expect(result, mockPurchases);
|
||||
verify(() => mockService.getUserPurchases(null, null)).called(1);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/widgets/error_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('ValidationErrorWidget', () {
|
||||
testWidgets('displays error message', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: ValidationErrorWidget(error: 'Test error message'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(ValidationErrorWidget), findsOneWidget);
|
||||
expect(find.text('Test error message'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays error icon', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: ValidationErrorWidget(error: 'Test error'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(ValidationErrorWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('handles long error messages', (tester) async {
|
||||
final longError = 'A' * 100;
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: ValidationErrorWidget(error: longError),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(ValidationErrorWidget), findsOneWidget);
|
||||
expect(find.text(longError), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays empty error message', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: ValidationErrorWidget(error: ''),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(ValidationErrorWidget), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_cubit.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/cubit/create_diet_state.dart';
|
||||
import 'package:eatvio_app/features/create_diet/presentation/widgets/status_drop_down_widget.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'status_drop_down_widget_test.mocks.dart';
|
||||
|
||||
@GenerateMocks([CreateDietCubit])
|
||||
void main() {
|
||||
group('StatusDropDownWidget', () {
|
||||
late MockCreateDietCubit mockCubit;
|
||||
|
||||
setUp(() {
|
||||
mockCubit = MockCreateDietCubit();
|
||||
});
|
||||
|
||||
Widget createTestWidget({DietState? dietState}) {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: const [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [Locale('ru')],
|
||||
home: BlocProvider<CreateDietCubit>.value(
|
||||
value: mockCubit,
|
||||
child: Scaffold(
|
||||
body: StatusDropDownWidget(dietState: dietState),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays status dropdown widget', (tester) async {
|
||||
when(mockCubit.state).thenReturn(
|
||||
CreateDietState.initial(),
|
||||
);
|
||||
when(mockCubit.stream).thenAnswer((_) => Stream.value(
|
||||
CreateDietState.initial(),
|
||||
));
|
||||
// ignore: return_of_invalid_type
|
||||
when(mockCubit.setDietState(any)).thenAnswer((_) => () {});
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(StatusDropDownWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays error when dietStateError is present', (tester) async {
|
||||
when(mockCubit.state).thenReturn(
|
||||
CreateDietState.initial().copyWith(
|
||||
dietStateError: 'Error message',
|
||||
),
|
||||
);
|
||||
when(mockCubit.stream).thenAnswer((_) => Stream.value(
|
||||
CreateDietState.initial().copyWith(
|
||||
dietStateError: 'Error message',
|
||||
),
|
||||
));
|
||||
// ignore: return_of_invalid_type
|
||||
when(mockCubit.setDietState(any)).thenAnswer((_) => () {});
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(StatusDropDownWidget), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_cubit.dart';
|
||||
import 'package:eatvio_app/features/create_plan/presentation/cubit/create_plan_state.dart';
|
||||
import 'package:eatvio_app/features/create_plan/presentation/widgets/select_exact_option_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'select_exact_option_widget_test.mocks.dart';
|
||||
|
||||
@GenerateMocks([CreatePlanCubit])
|
||||
void main() {
|
||||
group('SelectExactOptionWidget', () {
|
||||
late MockCreatePlanCubit mockCubit;
|
||||
|
||||
setUp(() {
|
||||
mockCubit = MockCreatePlanCubit();
|
||||
});
|
||||
|
||||
Widget createTestWidget() {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: BlocProvider<CreatePlanCubit>.value(
|
||||
value: mockCubit,
|
||||
child: Scaffold(
|
||||
body: SelectExactOptionWidget(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays select exact option widget', (tester) async {
|
||||
when(mockCubit.state).thenReturn(
|
||||
CreatePlanState.initial(),
|
||||
);
|
||||
when(mockCubit.stream).thenAnswer((_) => Stream.value(
|
||||
CreatePlanState.initial(),
|
||||
));
|
||||
// ignore: return_of_invalid_type
|
||||
when(mockCubit.setSelectedOptionIndex(any)).thenAnswer((_) => () {});
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(SelectExactOptionWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays option buttons 1, 2, 3', (tester) async {
|
||||
when(mockCubit.state).thenReturn(
|
||||
CreatePlanState.initial(),
|
||||
);
|
||||
when(mockCubit.stream).thenAnswer((_) => Stream.value(
|
||||
CreatePlanState.initial(),
|
||||
));
|
||||
// ignore: return_of_invalid_type
|
||||
when(mockCubit.setSelectedOptionIndex(any)).thenAnswer((_) => () {});
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('1'), findsOneWidget);
|
||||
expect(find.text('2'), findsOneWidget);
|
||||
expect(find.text('3'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('calls setSelectedOptionIndex when option is tapped', (tester) async {
|
||||
when(mockCubit.state).thenReturn(
|
||||
CreatePlanState.initial(),
|
||||
);
|
||||
when(mockCubit.stream).thenAnswer((_) => Stream.value(
|
||||
CreatePlanState.initial(),
|
||||
));
|
||||
// ignore: return_of_invalid_type
|
||||
when(mockCubit.setSelectedOptionIndex(any)).thenAnswer((_) => () {});
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.text('1'));
|
||||
await tester.pump();
|
||||
|
||||
verify(mockCubit.setSelectedOptionIndex(0)).called(1);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/create_recipe/entities/recipe_create_entity.dart';
|
||||
import 'package:eatvio_app/features/create_recipe/presentation/bloc/create_recipe_cubit/create_recipe_cubit.dart';
|
||||
import 'package:eatvio_app/features/create_recipe/presentation/bloc/create_recipe_cubit/create_recipe_state.dart';
|
||||
import 'package:eatvio_app/features/create_recipe/presentation/widgets/tags_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'tags_widget_test.mocks.dart';
|
||||
|
||||
@GenerateMocks([CreateRecipeCubit])
|
||||
void main() {
|
||||
group('TagsWidget', () {
|
||||
late MockCreateRecipeCubit mockCubit;
|
||||
|
||||
setUp(() {
|
||||
mockCubit = MockCreateRecipeCubit();
|
||||
});
|
||||
|
||||
Widget createTestWidget() {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: BlocProvider<CreateRecipeCubit>.value(
|
||||
value: mockCubit,
|
||||
child: Scaffold(
|
||||
body: TagsWidget(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays tags widget', (tester) async {
|
||||
final initialState = CreateRecipeState(
|
||||
entity: RecipeCreateEntity(
|
||||
ingredients: [],
|
||||
steps: [],
|
||||
tags: [],
|
||||
),
|
||||
loading: false,
|
||||
);
|
||||
when(mockCubit.state).thenReturn(initialState);
|
||||
when(mockCubit.stream).thenAnswer((_) => Stream.value(initialState));
|
||||
// ignore: return_of_invalid_type
|
||||
when(mockCubit.addTag(any)).thenAnswer((_) => () {});
|
||||
// ignore: return_of_invalid_type
|
||||
when(mockCubit.removeTag(any)).thenAnswer((_) => () {});
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(TagsWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays existing tags', (tester) async {
|
||||
final stateWithTags = CreateRecipeState(
|
||||
entity: RecipeCreateEntity(
|
||||
ingredients: [],
|
||||
steps: [],
|
||||
tags: ['tag1', 'tag2'],
|
||||
),
|
||||
loading: false,
|
||||
);
|
||||
when(mockCubit.state).thenReturn(stateWithTags);
|
||||
when(mockCubit.stream).thenAnswer((_) => Stream.value(stateWithTags));
|
||||
// ignore: return_of_invalid_type
|
||||
when(mockCubit.addTag(any)).thenAnswer((_) => () {});
|
||||
// ignore: return_of_invalid_type
|
||||
when(mockCubit.removeTag(any)).thenAnswer((_) => () {});
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('tag1'), findsOneWidget);
|
||||
expect(find.text('tag2'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('calls addTag when add button is tapped', (tester) async {
|
||||
final initialState = CreateRecipeState(
|
||||
entity: RecipeCreateEntity(
|
||||
ingredients: [],
|
||||
steps: [],
|
||||
tags: [],
|
||||
),
|
||||
loading: false,
|
||||
);
|
||||
when(mockCubit.state).thenReturn(initialState);
|
||||
when(mockCubit.stream).thenAnswer((_) => Stream.value(initialState));
|
||||
// ignore: return_of_invalid_type
|
||||
when(mockCubit.addTag(any)).thenAnswer((_) => () {});
|
||||
// ignore: return_of_invalid_type
|
||||
when(mockCubit.removeTag(any)).thenAnswer((_) => () {});
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Find text field and enter tag
|
||||
final textField = find.byType(TextField);
|
||||
await tester.enterText(textField, 'new tag');
|
||||
await tester.pump();
|
||||
|
||||
// Find and tap add button
|
||||
final addButton = find.byIcon(Icons.done);
|
||||
await tester.tap(addButton);
|
||||
await tester.pump();
|
||||
|
||||
verify(mockCubit.addTag('new tag')).called(1);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_cubit.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/bloc/diary_state.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/add_product_button_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'add_product_button_widget_test.mocks.dart';
|
||||
|
||||
@GenerateMocks([DiaryCubit])
|
||||
void main() {
|
||||
group('AddProductButtonWidget', () {
|
||||
late MockDiaryCubit mockCubit;
|
||||
|
||||
setUp(() {
|
||||
mockCubit = MockDiaryCubit();
|
||||
});
|
||||
|
||||
Widget createTestWidget() {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: BlocProvider<DiaryCubit>.value(
|
||||
value: mockCubit,
|
||||
child: Scaffold(
|
||||
body: AddProductButtonWidget(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays add product button widget', (tester) async {
|
||||
final loadingState = DiaryState.loading();
|
||||
when(mockCubit.state).thenReturn(loadingState);
|
||||
when(mockCubit.stream).thenAnswer((_) => Stream.value(loadingState));
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(AddProductButtonWidget), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/chosen_diet_widget.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('ChosenDietWidgetContent', () {
|
||||
Widget createTestWidget(Widget child) {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: S.delegate.supportedLocales,
|
||||
home: Scaffold(
|
||||
body: child,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays chosen diet widget content', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
createTestWidget(
|
||||
ChosenDietWidgetContent(
|
||||
currentDietDay: 5,
|
||||
dietName: 'Test Diet',
|
||||
dietDuration: 14,
|
||||
dietId: 1,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(ChosenDietWidgetContent), findsOneWidget);
|
||||
expect(find.text('Test Diet'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays current day and duration', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
createTestWidget(
|
||||
ChosenDietWidgetContent(
|
||||
currentDietDay: 7,
|
||||
dietName: 'Test Diet',
|
||||
dietDuration: 21,
|
||||
dietId: 1,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(ChosenDietWidgetContent), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays diet name with underline', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
createTestWidget(
|
||||
ChosenDietWidgetContent(
|
||||
currentDietDay: 1,
|
||||
dietName: 'My Diet',
|
||||
dietDuration: 7,
|
||||
dietId: 1,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.text('My Diet'), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/chosen_plan_widget.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('ChosenPlanWidgetContent', () {
|
||||
Widget createTestWidget({
|
||||
required int currentPlanDay,
|
||||
required String planName,
|
||||
required int planDuration,
|
||||
}) {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: const [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [Locale('ru')],
|
||||
home: Scaffold(
|
||||
body: ChosenPlanWidgetContent(
|
||||
currentPlanDay: currentPlanDay,
|
||||
planName: planName,
|
||||
planDuration: planDuration,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays plan name', (tester) async {
|
||||
await tester.pumpWidget(createTestWidget(
|
||||
currentPlanDay: 5,
|
||||
planName: 'Test Plan',
|
||||
planDuration: 14,
|
||||
));
|
||||
|
||||
expect(find.byType(ChosenPlanWidgetContent), findsOneWidget);
|
||||
expect(find.text('Test Plan'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays day information', (tester) async {
|
||||
await tester.pumpWidget(createTestWidget(
|
||||
currentPlanDay: 3,
|
||||
planName: 'My Plan',
|
||||
planDuration: 7,
|
||||
));
|
||||
|
||||
expect(find.byType(ChosenPlanWidgetContent), findsOneWidget);
|
||||
expect(find.textContaining('3'), findsOneWidget);
|
||||
expect(find.textContaining('7'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays correct day and duration', (tester) async {
|
||||
await tester.pumpWidget(createTestWidget(
|
||||
currentPlanDay: 10,
|
||||
planName: 'Long Plan',
|
||||
planDuration: 30,
|
||||
));
|
||||
|
||||
expect(find.byType(ChosenPlanWidgetContent), findsOneWidget);
|
||||
expect(find.text('Long Plan'), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/comment_container.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('CommentContainer', () {
|
||||
testWidgets('displays comment text', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: CommentContainer(comment: 'Test comment'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(CommentContainer), findsOneWidget);
|
||||
expect(find.text('Test comment'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays empty comment', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: CommentContainer(comment: ''),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(CommentContainer), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays long comment', (tester) async {
|
||||
const longComment = 'This is a very long comment that should be displayed properly in the container';
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: CommentContainer(comment: longComment),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(CommentContainer), findsOneWidget);
|
||||
expect(find.text(longComment), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/finish_day_button_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('FinishDayButtonWidget', () {
|
||||
testWidgets('displays finish day button', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: FinishDayButtonWidget(
|
||||
onPressed: () async {},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(FinishDayButtonWidget), findsOneWidget);
|
||||
expect(find.text('Закончить день'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('calls onPressed when tapped', (tester) async {
|
||||
bool wasCalled = false;
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: FinishDayButtonWidget(
|
||||
onPressed: () async {
|
||||
wasCalled = true;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.text('Закончить день'));
|
||||
await tester.pump();
|
||||
|
||||
expect(wasCalled, isTrue);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
import 'package:eatvio_app/features/diary/models/diary_day_model.dart';
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/meal_summary_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('MealSummaryWidget', () {
|
||||
testWidgets('displays meal summary with totals', (tester) async {
|
||||
final portions = <PortionModel>[];
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: MealSummaryWidget(
|
||||
portions: portions,
|
||||
mealNumber: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(MealSummaryWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('hides when all totals are zero', (tester) async {
|
||||
final portions = <PortionModel>[];
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: MealSummaryWidget(
|
||||
portions: portions,
|
||||
mealNumber: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Widget should be hidden (SizedBox.shrink) when totals are zero
|
||||
expect(find.byType(MealSummaryWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays meal number', (tester) async {
|
||||
final portions = <PortionModel>[];
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: MealSummaryWidget(
|
||||
portions: portions,
|
||||
mealNumber: 3,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(MealSummaryWidget), findsOneWidget);
|
||||
});
|
||||
});
|
||||
|
||||
group('MealSummaryWidget.calculateMealTotals', () {
|
||||
test('returns zero totals for empty portions list', () {
|
||||
final result = MealSummaryWidget.calculateMealTotals([]);
|
||||
|
||||
expect(result['calories'], 0.0);
|
||||
expect(result['proteins'], 0.0);
|
||||
expect(result['fats'], 0.0);
|
||||
expect(result['carbohydrates'], 0.0);
|
||||
});
|
||||
|
||||
test('returns correct map structure', () {
|
||||
final result = MealSummaryWidget.calculateMealTotals([]);
|
||||
|
||||
expect(result.containsKey('calories'), isTrue);
|
||||
expect(result.containsKey('proteins'), isTrue);
|
||||
expect(result.containsKey('fats'), isTrue);
|
||||
expect(result.containsKey('carbohydrates'), isTrue);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import 'package:eatvio_app/features/diary/presentation/widgets/product_loader_widget.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('ProductLoaderWidget', () {
|
||||
testWidgets('displays product loader widget', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: ProductLoaderWidget(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(ProductLoaderWidget), findsOneWidget);
|
||||
expect(find.byType(CupertinoActivityIndicator), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays ListTile with activity indicator', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: ProductLoaderWidget(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(ListTile), findsOneWidget);
|
||||
expect(find.byType(CupertinoActivityIndicator), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
101
test/features/diets/presentation/widgets/info_bouble_test.dart
Normal file
101
test/features/diets/presentation/widgets/info_bouble_test.dart
Normal file
@@ -0,0 +1,101 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/info_bouble.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('InfoBouble', () {
|
||||
testWidgets('displays info bouble with children', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: InfoBouble(
|
||||
children: [
|
||||
Text('Test'),
|
||||
Icon(Icons.star),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(InfoBouble), findsOneWidget);
|
||||
expect(find.text('Test'), findsOneWidget);
|
||||
expect(find.byIcon(Icons.star), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays with custom background color', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: InfoBouble(
|
||||
backgroundColor: Colors.blue,
|
||||
children: [
|
||||
Text('Test'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(InfoBouble), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays with custom radius', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: InfoBouble(
|
||||
radius: 20,
|
||||
children: [
|
||||
Text('Test'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(InfoBouble), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays with custom padding', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: InfoBouble(
|
||||
padding: EdgeInsets.all(16),
|
||||
children: [
|
||||
Text('Test'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(InfoBouble), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays with custom mainAxisAlignment', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: InfoBouble(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text('Test'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(InfoBouble), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
import 'package:eatvio_app/core/app_initializer.dart';
|
||||
import 'package:eatvio_app/core/di/app_config_registration.dart';
|
||||
import 'package:eatvio_app/core/enums/complained_content.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/diets/presentation/widgets/more_options.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('MoreOptions', () {
|
||||
setUp(() async {
|
||||
await sl.reset();
|
||||
AppConfigRegistration.registerAppConfig(buildType: AppBuildType.tests);
|
||||
});
|
||||
|
||||
Widget createTestWidget({
|
||||
String path = 'test/path',
|
||||
ComplainedContent? complainedContentType,
|
||||
String? slug,
|
||||
int? id,
|
||||
bool? disableActions,
|
||||
}) {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [Locale('ru'), Locale('en')],
|
||||
locale: const Locale('ru'),
|
||||
home: Scaffold(
|
||||
body: MoreOptions(
|
||||
path: path,
|
||||
complainedContentType: complainedContentType,
|
||||
slug: slug,
|
||||
id: id,
|
||||
disableActions: disableActions,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays copy link option', (tester) async {
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(MoreOptions), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays share option', (tester) async {
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(MoreOptions), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays complain option when complainedContentType is provided', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
createTestWidget(
|
||||
complainedContentType: ComplainedContent.diet,
|
||||
id: 1,
|
||||
slug: 'test-slug',
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(MoreOptions), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('disables actions when disableActions is true', (tester) async {
|
||||
await tester.pumpWidget(createTestWidget(disableActions: true));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(MoreOptions), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('enables actions when disableActions is false', (tester) async {
|
||||
await tester.pumpWidget(createTestWidget(disableActions: false));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(MoreOptions), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,62 +4,96 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('CommentModel', () {
|
||||
test('создает CommentModel с правильными значениями', () {
|
||||
test('создает экземпляр с данными', () {
|
||||
final comment = Comment(
|
||||
id: 1,
|
||||
authorName: 'Author Name',
|
||||
authorSlug: 'author',
|
||||
authorProfileIcon: 'https://example.com/icon.jpg',
|
||||
authorName: 'Test Author',
|
||||
authorSlug: 'test-author',
|
||||
authorProfileIcon: 'icon.png',
|
||||
body: 'Test comment',
|
||||
childrenComments: [],
|
||||
createdAt: DateTime(2024, 1, 1),
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
|
||||
final model = CommentModel(
|
||||
data: [comment],
|
||||
links: const Links(
|
||||
first: 'https://example.com?page=1',
|
||||
last: 'https://example.com?page=1',
|
||||
prev: null,
|
||||
next: null,
|
||||
),
|
||||
meta: const Meta(
|
||||
currentPage: 1,
|
||||
from: 1,
|
||||
lastPage: 1,
|
||||
links: [],
|
||||
perPage: 10,
|
||||
to: 1,
|
||||
total: 1,
|
||||
),
|
||||
links: const Links(first: '', last: '', prev: null, next: null),
|
||||
meta: const Meta(currentPage: 1, from: null, lastPage: 1, links: [], perPage: 10, to: null, total: 0),
|
||||
);
|
||||
|
||||
expect(model.data.length, 1);
|
||||
expect(model.data.first.id, 1);
|
||||
expect(model.data.first.body, 'Test comment');
|
||||
});
|
||||
|
||||
test('fromJson создает модель из JSON', () {
|
||||
final json = {
|
||||
'data': [
|
||||
{
|
||||
'id': 1,
|
||||
'author_name': 'Test Author',
|
||||
'author_slug': 'test-author',
|
||||
'author_profile_icon': 'icon.png',
|
||||
'body': 'Test comment',
|
||||
'children_comments': [],
|
||||
'created_at': '2024-01-01T00:00:00Z',
|
||||
}
|
||||
],
|
||||
'links': {'first': '', 'last': '', 'prev': null, 'next': null},
|
||||
'meta': {
|
||||
'current_page': 1,
|
||||
'from': null,
|
||||
'last_page': 1,
|
||||
'links': [],
|
||||
'per_page': 10,
|
||||
'to': null,
|
||||
'total': 0,
|
||||
},
|
||||
};
|
||||
|
||||
final model = CommentModel.fromJson(json);
|
||||
|
||||
expect(model.data.length, 1);
|
||||
expect(model.data.first.id, 1);
|
||||
});
|
||||
});
|
||||
|
||||
group('Comment', () {
|
||||
test('создает Comment с вложенными комментариями', () {
|
||||
test('создает экземпляр с данными', () {
|
||||
final comment = Comment(
|
||||
id: 1,
|
||||
authorName: 'Test Author',
|
||||
authorSlug: 'test-author',
|
||||
authorProfileIcon: 'icon.png',
|
||||
body: 'Test comment',
|
||||
childrenComments: [],
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
|
||||
expect(comment.id, 1);
|
||||
expect(comment.authorName, 'Test Author');
|
||||
expect(comment.body, 'Test comment');
|
||||
});
|
||||
|
||||
test('поддерживает вложенные комментарии', () {
|
||||
final childComment = Comment(
|
||||
id: 2,
|
||||
authorName: 'Child Author',
|
||||
authorSlug: 'child-author',
|
||||
authorProfileIcon: 'https://example.com/icon2.jpg',
|
||||
authorProfileIcon: 'child.png',
|
||||
body: 'Child comment',
|
||||
childrenComments: [],
|
||||
createdAt: DateTime(2024, 1, 2),
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
|
||||
final parentComment = Comment(
|
||||
id: 1,
|
||||
authorName: 'Author Name',
|
||||
authorSlug: 'author',
|
||||
authorProfileIcon: 'https://example.com/icon.jpg',
|
||||
authorName: 'Parent Author',
|
||||
authorSlug: 'parent-author',
|
||||
authorProfileIcon: 'parent.png',
|
||||
body: 'Parent comment',
|
||||
childrenComments: [childComment],
|
||||
createdAt: DateTime(2024, 1, 1),
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
|
||||
expect(parentComment.childrenComments.length, 1);
|
||||
|
||||
87
test/features/feed/presentation/widgets/chip_group_test.dart
Normal file
87
test/features/feed/presentation/widgets/chip_group_test.dart
Normal file
@@ -0,0 +1,87 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/chip_group.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('ChipGroup', () {
|
||||
testWidgets('displays chip group widget', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: ChipGroup(
|
||||
selectedChipIndex: 0,
|
||||
chipsLabelList: ['All', 'Recipes', 'Diets'],
|
||||
setSelectedChipIndex: (index) {},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(ChipGroup), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays all chips from list', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: ChipGroup(
|
||||
selectedChipIndex: 0,
|
||||
chipsLabelList: ['All', 'Recipes', 'Diets', 'Plans'],
|
||||
setSelectedChipIndex: (index) {},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(ChipGroup), findsOneWidget);
|
||||
expect(find.text('All'), findsOneWidget);
|
||||
expect(find.text('Recipes'), findsOneWidget);
|
||||
expect(find.text('Diets'), findsOneWidget);
|
||||
expect(find.text('Plans'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('calls setSelectedChipIndex when chip is tapped', (tester) async {
|
||||
int? selectedIndex;
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: ChipGroup(
|
||||
selectedChipIndex: 0,
|
||||
chipsLabelList: ['All', 'Recipes', 'Diets'],
|
||||
setSelectedChipIndex: (index) {
|
||||
selectedIndex = index;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.text('Recipes'));
|
||||
await tester.pump();
|
||||
|
||||
expect(selectedIndex, 1);
|
||||
});
|
||||
|
||||
testWidgets('displays empty chip group when list is empty', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: ChipGroup(
|
||||
selectedChipIndex: 0,
|
||||
chipsLabelList: [],
|
||||
setSelectedChipIndex: (index) {},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(ChipGroup), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/choice_chip_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('ChoiceChipWidget', () {
|
||||
testWidgets('displays chip with label', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: ChoiceChipWidget(
|
||||
chipsLabelList: ['Option 1', 'Option 2'],
|
||||
index: 0,
|
||||
selectedChipIndex: 0,
|
||||
onSelected: (selected) {},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(ChoiceChipWidget), findsOneWidget);
|
||||
expect(find.text('Option 1'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('shows selected state when index matches selectedChipIndex', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: ChoiceChipWidget(
|
||||
chipsLabelList: ['Option 1', 'Option 2'],
|
||||
index: 0,
|
||||
selectedChipIndex: 0,
|
||||
onSelected: (selected) {},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(ChoiceChipWidget), findsOneWidget);
|
||||
final chip = tester.widget<ChoiceChip>(find.byType(ChoiceChip));
|
||||
expect(chip.selected, isTrue);
|
||||
});
|
||||
|
||||
testWidgets('shows unselected state when index does not match', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: ChoiceChipWidget(
|
||||
chipsLabelList: ['Option 1', 'Option 2'],
|
||||
index: 1,
|
||||
selectedChipIndex: 0,
|
||||
onSelected: (selected) {},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(ChoiceChipWidget), findsOneWidget);
|
||||
final chip = tester.widget<ChoiceChip>(find.byType(ChoiceChip));
|
||||
expect(chip.selected, isFalse);
|
||||
});
|
||||
|
||||
testWidgets('applies custom padding', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: ChoiceChipWidget(
|
||||
chipsLabelList: ['Option 1'],
|
||||
index: 0,
|
||||
selectedChipIndex: 0,
|
||||
padding: EdgeInsets.all(16),
|
||||
onSelected: (selected) {},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(ChoiceChipWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('applies custom colors', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: ChoiceChipWidget(
|
||||
chipsLabelList: ['Option 1'],
|
||||
index: 0,
|
||||
selectedChipIndex: 0,
|
||||
activeColor: Colors.blue,
|
||||
inactiveColor: Colors.grey,
|
||||
onSelected: (selected) {},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(ChoiceChipWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('calls onSelected when tapped', (tester) async {
|
||||
bool wasCalled = false;
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: ChoiceChipWidget(
|
||||
chipsLabelList: ['Option 1'],
|
||||
index: 0,
|
||||
selectedChipIndex: 0,
|
||||
onSelected: (selected) {
|
||||
wasCalled = true;
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.byType(ChoiceChip));
|
||||
await tester.pump();
|
||||
|
||||
expect(wasCalled, isTrue);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
import 'package:eatvio_app/core/app_initializer.dart';
|
||||
import 'package:eatvio_app/core/di/app_config_registration.dart';
|
||||
import 'package:eatvio_app/core/models/pagination_model.dart';
|
||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_cubit.dart';
|
||||
import 'package:eatvio_app/features/bottom_navigation_bar/presentation/bloc/profile_avatar_cubit/profile_avatar_state.dart';
|
||||
import 'package:eatvio_app/features/feed/models/comment_model.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/comments_widget.dart';
|
||||
import 'package:eatvio_app/features/profile/models/profile_model.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:get_it/get_it.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
import 'package:network_image_mock/network_image_mock.dart';
|
||||
|
||||
class MockProfileAvatarCubit extends Mock implements ProfileAvatarCubit {}
|
||||
|
||||
void main() {
|
||||
late MockProfileAvatarCubit mockProfileAvatarCubit;
|
||||
|
||||
setUpAll(() async {
|
||||
GetIt.instance.reset();
|
||||
// Инициализируем dotenv для AppConfig
|
||||
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
|
||||
});
|
||||
|
||||
setUp(() {
|
||||
mockProfileAvatarCubit = MockProfileAvatarCubit();
|
||||
GetIt.instance.registerSingleton<ProfileAvatarCubit>(mockProfileAvatarCubit);
|
||||
// Регистрируем AppConfig для тестов
|
||||
AppConfigRegistration.registerAppConfig(buildType: AppBuildType.tests);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
GetIt.instance.reset();
|
||||
});
|
||||
group('CommentsWidget', () {
|
||||
testWidgets('отображается как виджет', (WidgetTester tester) async {
|
||||
const testProfile = ProfileModel(
|
||||
id: 1,
|
||||
slug: 'test-user',
|
||||
name: 'Test User',
|
||||
email: 'test@example.com',
|
||||
phoneConfirmationState: 'confirmed',
|
||||
isPublicProfile: true,
|
||||
isBlockedByMe: false,
|
||||
isBlockedByAuthor: false,
|
||||
isBlockedByUser: false,
|
||||
isEntitySubscribedByMe: false,
|
||||
profilePhotoUrl: '',
|
||||
roles: [],
|
||||
badges: [],
|
||||
subscriptions: [],
|
||||
subscribers: [],
|
||||
);
|
||||
|
||||
when(() => mockProfileAvatarCubit.state).thenReturn(const ProfileAvatarState.loaded(profile: testProfile));
|
||||
|
||||
const commentModel = CommentModel(
|
||||
data: [],
|
||||
links: Links(first: '', last: '', prev: null, next: null),
|
||||
meta: Meta(currentPage: 1, from: null, lastPage: 1, links: [], perPage: 10, to: null, total: 0),
|
||||
);
|
||||
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
localizationsDelegates: const [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: S.delegate.supportedLocales,
|
||||
home: const Scaffold(
|
||||
body: CommentsWidget(id: '1', commentSourceType: CommentSourceType.blogPost, comment: commentModel),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(CommentsWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('отображает комментарии', (WidgetTester tester) async {
|
||||
const testProfile = ProfileModel(
|
||||
id: 1,
|
||||
slug: 'test-author',
|
||||
name: 'Test Author',
|
||||
email: 'test@example.com',
|
||||
phoneConfirmationState: 'confirmed',
|
||||
isPublicProfile: true,
|
||||
isBlockedByMe: false,
|
||||
isBlockedByAuthor: false,
|
||||
isBlockedByUser: false,
|
||||
isEntitySubscribedByMe: false,
|
||||
profilePhotoUrl: '',
|
||||
roles: [],
|
||||
badges: [],
|
||||
subscriptions: [],
|
||||
subscribers: [],
|
||||
);
|
||||
|
||||
when(() => mockProfileAvatarCubit.state).thenReturn(const ProfileAvatarState.loaded(profile: testProfile));
|
||||
|
||||
final comment = Comment(
|
||||
id: 1,
|
||||
authorName: 'Test Author',
|
||||
authorSlug: 'test-author',
|
||||
authorProfileIcon: '',
|
||||
body: 'Test comment',
|
||||
childrenComments: [],
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
|
||||
final commentModel = CommentModel(
|
||||
data: [comment],
|
||||
links: const Links(first: '', last: '', prev: null, next: null),
|
||||
meta: const Meta(currentPage: 1, from: null, lastPage: 1, links: [], perPage: 10, to: null, total: 0),
|
||||
);
|
||||
|
||||
// Используем mockNetworkImages для обработки NetworkImage в тестах
|
||||
await mockNetworkImagesFor(() async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
localizationsDelegates: const [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: S.delegate.supportedLocales,
|
||||
home: Scaffold(
|
||||
body: CommentsWidget(id: '1', commentSourceType: CommentSourceType.blogPost, comment: commentModel),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(CommentsWidget), findsOneWidget);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
import 'package:eatvio_app/core/app_config.dart';
|
||||
import 'package:eatvio_app/core/app_initializer.dart';
|
||||
import 'package:eatvio_app/core/di/app_config_registration.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/feed/models/feed_consultant_model.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/consultant_widget.dart';
|
||||
import 'package:eatvio_app/features/profile/models/badge_model.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:network_image_mock/network_image_mock.dart';
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
setUpAll(() async {
|
||||
// Initialize dotenv for tests
|
||||
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
|
||||
});
|
||||
|
||||
group('ConsultantWidget', () {
|
||||
setUp(() async {
|
||||
await sl.reset();
|
||||
dotenv.loadFromString(envString: 'DEV_BASE_URL=http://localhost\nBASE_URL=http://localhost');
|
||||
AppConfigRegistration.registerAppConfig(buildType: AppBuildType.tests);
|
||||
// Ensure AppConfig has the correct baseUrl for image URL construction
|
||||
sl<AppConfig>().setBaseUrl('http://localhost');
|
||||
});
|
||||
|
||||
Widget createTestWidget(FeedConsultantModel consultant) {
|
||||
return MaterialApp.router(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [Locale('ru'), Locale('en')],
|
||||
locale: const Locale('ru'),
|
||||
routerConfig: GoRouter(
|
||||
initialLocation: '/',
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/',
|
||||
builder: (context, state) => Scaffold(
|
||||
body: ConsultantWidget(consultant: consultant),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/profileScreen',
|
||||
name: 'profileScreen',
|
||||
builder: (context, state) => Scaffold(
|
||||
appBar: AppBar(title: const Text('Profile')),
|
||||
body: Center(child: Text('Profile: ${state.extra}')),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays consultant information', (tester) async {
|
||||
await mockNetworkImagesFor(() async {
|
||||
final consultant = FeedConsultantModel(
|
||||
slug: 'test-consultant',
|
||||
name: 'Test Consultant',
|
||||
photo: 'https://example.com/photo.jpg',
|
||||
description: 'Test description',
|
||||
totalScores: 100,
|
||||
ratingPlace: 1,
|
||||
badges: [],
|
||||
);
|
||||
|
||||
await tester.pumpWidget(createTestWidget(consultant));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Test Consultant'), findsOneWidget);
|
||||
expect(find.text('Рейтинг: 100'), findsOneWidget);
|
||||
expect(find.text('Test description'), findsOneWidget);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('displays consultant with badges', (tester) async {
|
||||
await mockNetworkImagesFor(() async {
|
||||
final consultant = FeedConsultantModel(
|
||||
slug: 'test-consultant',
|
||||
name: 'Test Consultant',
|
||||
photo: 'https://example.com/photo.jpg',
|
||||
description: 'Test description',
|
||||
totalScores: 100,
|
||||
ratingPlace: 1,
|
||||
badges: [
|
||||
BadgeModel(id: 1, title: 'Badge 1', image: 'badge1.png', description: 'Description 1', type: 'test'),
|
||||
BadgeModel(id: 2, title: 'Badge 2', image: 'badge2.png', description: 'Description 2', type: 'test'),
|
||||
],
|
||||
);
|
||||
|
||||
await tester.pumpWidget(createTestWidget(consultant));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Test Consultant'), findsOneWidget);
|
||||
expect(find.byType(ConsultantWidget), findsOneWidget);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('displays rating place', (tester) async {
|
||||
await mockNetworkImagesFor(() async {
|
||||
final consultant = FeedConsultantModel(
|
||||
slug: 'test-consultant',
|
||||
name: 'Test Consultant',
|
||||
photo: 'https://example.com/photo.jpg',
|
||||
description: 'Test description',
|
||||
totalScores: 100,
|
||||
ratingPlace: 5,
|
||||
badges: [],
|
||||
);
|
||||
|
||||
await tester.pumpWidget(createTestWidget(consultant));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('5'), findsOneWidget);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('handles photo with https URL', (tester) async {
|
||||
await mockNetworkImagesFor(() async {
|
||||
final consultant = FeedConsultantModel(
|
||||
slug: 'test-consultant',
|
||||
name: 'Test Consultant',
|
||||
photo: 'https://example.com/photo.jpg',
|
||||
description: 'Test description',
|
||||
totalScores: 100,
|
||||
ratingPlace: 1,
|
||||
badges: [],
|
||||
);
|
||||
|
||||
await tester.pumpWidget(createTestWidget(consultant));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(CircleAvatar), findsOneWidget);
|
||||
});
|
||||
});
|
||||
|
||||
testWidgets('handles photo without https URL', (tester) async {
|
||||
await mockNetworkImagesFor(() async {
|
||||
final consultant = FeedConsultantModel(
|
||||
slug: 'test-consultant',
|
||||
name: 'Test Consultant',
|
||||
photo: '/storage/photo.jpg',
|
||||
description: 'Test description',
|
||||
totalScores: 100,
|
||||
ratingPlace: 1,
|
||||
badges: [],
|
||||
);
|
||||
|
||||
await tester.pumpWidget(createTestWidget(consultant));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(CircleAvatar), findsOneWidget);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_state.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_state.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/duration_choice_filter_widget.dart';
|
||||
import 'package:eatvio_app/features/my_diets/presentation/cubit/my_diets_cubit.dart';
|
||||
import 'package:eatvio_app/features/my_diets/presentation/cubit/my_diets_state.dart';
|
||||
import 'package:eatvio_app/features/my_plans/presentation/cubit/my_plans_cubit.dart';
|
||||
import 'package:eatvio_app/features/my_plans/presentation/cubit/my_plans_state.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'duration_choice_filter_widget_test.mocks.dart';
|
||||
|
||||
@GenerateNiceMocks([
|
||||
MockSpec<PlansCubit>(),
|
||||
MockSpec<DietsCubit>(),
|
||||
MockSpec<MyPlansCubit>(),
|
||||
MockSpec<MyDietsCubit>(),
|
||||
])
|
||||
void main() {
|
||||
group('DurationChoiceFilterWidget', () {
|
||||
late MockPlansCubit mockPlansCubit;
|
||||
late MockDietsCubit mockDietsCubit;
|
||||
late MockMyPlansCubit mockMyPlansCubit;
|
||||
late MockMyDietsCubit mockMyDietsCubit;
|
||||
|
||||
setUp(() {
|
||||
mockPlansCubit = MockPlansCubit();
|
||||
mockDietsCubit = MockDietsCubit();
|
||||
mockMyPlansCubit = MockMyPlansCubit();
|
||||
mockMyDietsCubit = MockMyDietsCubit();
|
||||
});
|
||||
|
||||
Widget createTestWidget(Widget child) {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [Locale('ru'), Locale('en')],
|
||||
locale: const Locale('ru'),
|
||||
home: Scaffold(body: child),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays duration filter for DietsCubit', (tester) async {
|
||||
when(mockDietsCubit.state).thenReturn(DietsState.initial());
|
||||
when(mockDietsCubit.stream).thenAnswer((_) => Stream.value(DietsState.initial()));
|
||||
|
||||
await tester.pumpWidget(
|
||||
createTestWidget(
|
||||
BlocProvider<DietsCubit>.value(
|
||||
value: mockDietsCubit,
|
||||
child: DurationChoiceFilterWidget(dietCubit: mockDietsCubit),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(DurationChoiceFilterWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays duration filter for PlansCubit', (tester) async {
|
||||
when(mockPlansCubit.state).thenReturn(PlansState.initial());
|
||||
when(mockPlansCubit.stream).thenAnswer((_) => Stream.value(PlansState.initial()));
|
||||
|
||||
await tester.pumpWidget(
|
||||
createTestWidget(
|
||||
BlocProvider<PlansCubit>.value(
|
||||
value: mockPlansCubit,
|
||||
child: DurationChoiceFilterWidget(plansCubit: mockPlansCubit),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(DurationChoiceFilterWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays duration filter for MyPlansCubit', (tester) async {
|
||||
when(mockMyPlansCubit.state).thenReturn(MyPlansState());
|
||||
when(mockMyPlansCubit.stream).thenAnswer((_) => Stream.value(MyPlansState()));
|
||||
|
||||
await tester.pumpWidget(
|
||||
createTestWidget(
|
||||
BlocProvider<MyPlansCubit>.value(
|
||||
value: mockMyPlansCubit,
|
||||
child: DurationChoiceFilterWidget(myPlansCubit: mockMyPlansCubit),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(DurationChoiceFilterWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays duration filter for MyDietsCubit', (tester) async {
|
||||
when(mockMyDietsCubit.state).thenReturn(MyDietsState());
|
||||
when(mockMyDietsCubit.stream).thenAnswer((_) => Stream.value(MyDietsState()));
|
||||
|
||||
await tester.pumpWidget(
|
||||
createTestWidget(
|
||||
BlocProvider<MyDietsCubit>.value(
|
||||
value: mockMyDietsCubit,
|
||||
child: DurationChoiceFilterWidget(myDietsCubit: mockMyDietsCubit),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(DurationChoiceFilterWidget), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/filter_badge.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('FilterBadge', () {
|
||||
testWidgets('displays filter badge widget', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: FilterBadge(
|
||||
filterBottomSheet: Container(
|
||||
child: Text('Filter Bottom Sheet'),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(FilterBadge), findsOneWidget);
|
||||
expect(find.byType(GestureDetector), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('opens bottom sheet when tapped', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: FilterBadge(
|
||||
filterBottomSheet: Container(
|
||||
child: Text('Filter Bottom Sheet'),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.byType(FilterBadge));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.text('Filter Bottom Sheet'), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_state.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/sorting_drop_down_filter.dart';
|
||||
import 'package:eatvio_app/features/my_diets/presentation/cubit/my_diets_cubit.dart';
|
||||
import 'package:eatvio_app/features/my_diets/presentation/cubit/my_diets_state.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'sorting_drop_down_filter_test.mocks.dart';
|
||||
|
||||
@GenerateNiceMocks([
|
||||
MockSpec<DietsCubit>(),
|
||||
MockSpec<MyDietsCubit>(),
|
||||
])
|
||||
void main() {
|
||||
group('SortingDropDownFilter', () {
|
||||
late MockDietsCubit mockDietsCubit;
|
||||
late MockMyDietsCubit mockMyDietsCubit;
|
||||
|
||||
setUp(() {
|
||||
mockDietsCubit = MockDietsCubit();
|
||||
mockMyDietsCubit = MockMyDietsCubit();
|
||||
});
|
||||
|
||||
Widget createTestWidget(Widget child) {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [Locale('ru'), Locale('en')],
|
||||
locale: const Locale('ru'),
|
||||
home: Scaffold(body: child),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays sorting dropdown for DietsCubit', (tester) async {
|
||||
when(mockDietsCubit.state).thenReturn(DietsState.initial());
|
||||
when(mockDietsCubit.stream).thenAnswer((_) => Stream.value(DietsState.initial()));
|
||||
|
||||
await tester.pumpWidget(
|
||||
createTestWidget(
|
||||
BlocProvider<DietsCubit>.value(
|
||||
value: mockDietsCubit,
|
||||
child: SortingDropDownFilter(dietsCubit: mockDietsCubit),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(SortingDropDownFilter), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays sorting dropdown for MyDietsCubit', (tester) async {
|
||||
when(mockMyDietsCubit.state).thenReturn(MyDietsState());
|
||||
when(mockMyDietsCubit.stream).thenAnswer((_) => Stream.value(MyDietsState()));
|
||||
|
||||
await tester.pumpWidget(
|
||||
createTestWidget(
|
||||
BlocProvider<MyDietsCubit>.value(
|
||||
value: mockMyDietsCubit,
|
||||
child: SortingDropDownFilter(myDietsCubit: mockMyDietsCubit),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(SortingDropDownFilter), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import 'package:eatvio_app/core/app_initializer.dart';
|
||||
import 'package:eatvio_app/core/di/app_config_registration.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/subscribe_button_widget.dart';
|
||||
import 'package:eatvio_app/features/profile/presentation/bloc/sub_cubit/sub_cubit.dart';
|
||||
import 'package:eatvio_app/features/profile/presentation/bloc/sub_cubit/sub_state.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'subscribe_button_widget_test.mocks.dart';
|
||||
|
||||
@GenerateNiceMocks([MockSpec<SubCubit>()])
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('SubscribeButtonWidget', () {
|
||||
late MockSubCubit mockSubCubit;
|
||||
|
||||
setUp(() async {
|
||||
await sl.reset();
|
||||
AppConfigRegistration.registerAppConfig(buildType: AppBuildType.tests);
|
||||
mockSubCubit = MockSubCubit();
|
||||
sl.registerLazySingleton<SubCubit>(() => mockSubCubit);
|
||||
});
|
||||
|
||||
Widget createTestWidget(String slug) {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: BlocProvider<SubCubit>.value(
|
||||
value: mockSubCubit,
|
||||
child: Scaffold(
|
||||
body: SubscribeButtonWidget(slug: slug),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays subscribe button', (tester) async {
|
||||
when(mockSubCubit.stream).thenAnswer((_) => Stream.value(const SubState()));
|
||||
|
||||
await tester.pumpWidget(createTestWidget('test-slug'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(SubscribeButtonWidget), findsOneWidget);
|
||||
expect(find.text('Подписаться'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('calls subscribe when tapped', (tester) async {
|
||||
when(mockSubCubit.stream).thenAnswer((_) => Stream.value(const SubState()));
|
||||
when(mockSubCubit.subscribe(any)).thenAnswer((_) async {});
|
||||
|
||||
await tester.pumpWidget(createTestWidget('test-slug'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.text('Подписаться'));
|
||||
await tester.pump();
|
||||
|
||||
verify(mockSubCubit.subscribe('test-slug')).called(1);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/create_recipe/models/recipe_tag_model.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/recipes_cubit/recipes_state.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/tags_modal_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'tags_modal_widget_test.mocks.dart';
|
||||
|
||||
@GenerateNiceMocks([MockSpec<RecipesCubit>()])
|
||||
void main() {
|
||||
group('TagsModalWidget', () {
|
||||
late MockRecipesCubit mockRecipesCubit;
|
||||
|
||||
setUp(() {
|
||||
mockRecipesCubit = MockRecipesCubit();
|
||||
});
|
||||
|
||||
Widget createTestWidget() {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: BlocProvider<RecipesCubit>.value(
|
||||
value: mockRecipesCubit,
|
||||
child: Scaffold(
|
||||
body: TagsModalWidget(recipesCubit: mockRecipesCubit),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays tags modal widget', (tester) async {
|
||||
final state = RecipesState(
|
||||
recipesList: [],
|
||||
recipesTags: [
|
||||
RecipeTag(
|
||||
id: 1,
|
||||
name: 'Tag 1',
|
||||
recipesCount: 5,
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
),
|
||||
RecipeTag(
|
||||
id: 2,
|
||||
name: 'Tag 2',
|
||||
recipesCount: 10,
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
),
|
||||
],
|
||||
selectedTags: {},
|
||||
selectedTagsCounter: 0,
|
||||
isLoading: false,
|
||||
);
|
||||
when(mockRecipesCubit.state).thenReturn(state);
|
||||
when(mockRecipesCubit.stream).thenAnswer((_) => Stream.value(state));
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(TagsModalWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays tags with counts', (tester) async {
|
||||
final state = RecipesState(
|
||||
recipesList: [],
|
||||
recipesTags: [
|
||||
RecipeTag(
|
||||
id: 1,
|
||||
name: 'Tag 1',
|
||||
recipesCount: 5,
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
),
|
||||
],
|
||||
selectedTags: {},
|
||||
selectedTagsCounter: 0,
|
||||
isLoading: false,
|
||||
);
|
||||
when(mockRecipesCubit.state).thenReturn(state);
|
||||
when(mockRecipesCubit.stream).thenAnswer((_) => Stream.value(state));
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.textContaining('Tag 1'), findsOneWidget);
|
||||
expect(find.textContaining('5'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('highlights selected tags', (tester) async {
|
||||
final state = RecipesState(
|
||||
recipesList: [],
|
||||
recipesTags: [
|
||||
RecipeTag(
|
||||
id: 1,
|
||||
name: 'Tag 1',
|
||||
recipesCount: 5,
|
||||
createdAt: DateTime.now(),
|
||||
updatedAt: DateTime.now(),
|
||||
),
|
||||
],
|
||||
selectedTags: {1},
|
||||
selectedTagsCounter: 1,
|
||||
isLoading: false,
|
||||
);
|
||||
when(mockRecipesCubit.state).thenReturn(state);
|
||||
when(mockRecipesCubit.stream).thenAnswer((_) => Stream.value(state));
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(TagsModalWidget), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_state.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_cubit.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/plans_cubit/plans_state.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/widgets/type_choice_filter_widget.dart';
|
||||
import 'package:eatvio_app/features/my_diets/presentation/cubit/my_diets_cubit.dart';
|
||||
import 'package:eatvio_app/features/my_diets/presentation/cubit/my_diets_state.dart';
|
||||
import 'package:eatvio_app/features/my_plans/presentation/cubit/my_plans_cubit.dart';
|
||||
import 'package:eatvio_app/features/my_plans/presentation/cubit/my_plans_state.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'type_choice_filter_widget_test.mocks.dart';
|
||||
|
||||
@GenerateNiceMocks([
|
||||
MockSpec<PlansCubit>(),
|
||||
MockSpec<DietsCubit>(),
|
||||
MockSpec<MyPlansCubit>(),
|
||||
MockSpec<MyDietsCubit>(),
|
||||
])
|
||||
void main() {
|
||||
group('TypeChoiceFilterWidget', () {
|
||||
late MockPlansCubit mockPlansCubit;
|
||||
late MockDietsCubit mockDietsCubit;
|
||||
late MockMyPlansCubit mockMyPlansCubit;
|
||||
late MockMyDietsCubit mockMyDietsCubit;
|
||||
|
||||
setUp(() {
|
||||
mockPlansCubit = MockPlansCubit();
|
||||
mockDietsCubit = MockDietsCubit();
|
||||
mockMyPlansCubit = MockMyPlansCubit();
|
||||
mockMyDietsCubit = MockMyDietsCubit();
|
||||
});
|
||||
|
||||
Widget createTestWidget(Widget child) {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [Locale('ru'), Locale('en')],
|
||||
locale: const Locale('ru'),
|
||||
home: Scaffold(body: child),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays type filter for PlansCubit', (tester) async {
|
||||
when(mockPlansCubit.state).thenReturn(PlansState.initial());
|
||||
when(mockPlansCubit.stream).thenAnswer((_) => Stream.value(PlansState.initial()));
|
||||
|
||||
await tester.pumpWidget(
|
||||
createTestWidget(
|
||||
BlocProvider<PlansCubit>.value(
|
||||
value: mockPlansCubit,
|
||||
child: TypeChoiceFilterWidget(plansCubit: mockPlansCubit),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(TypeChoiceFilterWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays type filter for DietsCubit', (tester) async {
|
||||
when(mockDietsCubit.state).thenReturn(DietsState.initial());
|
||||
when(mockDietsCubit.stream).thenAnswer((_) => Stream.value(DietsState.initial()));
|
||||
|
||||
await tester.pumpWidget(
|
||||
createTestWidget(
|
||||
BlocProvider<DietsCubit>.value(
|
||||
value: mockDietsCubit,
|
||||
child: TypeChoiceFilterWidget(dietsCubit: mockDietsCubit),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(TypeChoiceFilterWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays type filter for MyPlansCubit', (tester) async {
|
||||
when(mockMyPlansCubit.state).thenReturn(MyPlansState());
|
||||
when(mockMyPlansCubit.stream).thenAnswer((_) => Stream.value(MyPlansState()));
|
||||
|
||||
await tester.pumpWidget(
|
||||
createTestWidget(
|
||||
BlocProvider<MyPlansCubit>.value(
|
||||
value: mockMyPlansCubit,
|
||||
child: TypeChoiceFilterWidget(myPlansCubit: mockMyPlansCubit),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(TypeChoiceFilterWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays type filter for MyDietsCubit', (tester) async {
|
||||
when(mockMyDietsCubit.state).thenReturn(MyDietsState());
|
||||
when(mockMyDietsCubit.stream).thenAnswer((_) => Stream.value(MyDietsState()));
|
||||
|
||||
await tester.pumpWidget(
|
||||
createTestWidget(
|
||||
BlocProvider<MyDietsCubit>.value(
|
||||
value: mockMyDietsCubit,
|
||||
child: TypeChoiceFilterWidget(myDietsCubit: mockMyDietsCubit),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(TypeChoiceFilterWidget), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/finances_and_consultations_archive/presentation/widgets/status_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('StatusWidget', () {
|
||||
testWidgets('displays canceled status', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: StatusWidget(status: Status.canceled),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(StatusWidget), findsOneWidget);
|
||||
expect(find.text('Отменён'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays success status', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: StatusWidget(status: Status.success),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(StatusWidget), findsOneWidget);
|
||||
expect(find.text('Успешно'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays inProgress status', (tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: Scaffold(
|
||||
body: StatusWidget(status: Status.inProgress),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.byType(StatusWidget), findsOneWidget);
|
||||
expect(find.text('В процессе'), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import 'package:eatvio_app/features/glossary/models/glossary_model.dart';
|
||||
import 'package:eatvio_app/features/glossary/repositories/glossary_repository.dart';
|
||||
import 'package:eatvio_app/features/glossary/services/glossary_service.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
|
||||
class MockGlossaryService extends Mock implements GlossaryService {}
|
||||
|
||||
void main() {
|
||||
group('GlossaryRepository', () {
|
||||
late GlossaryRepository repository;
|
||||
late MockGlossaryService mockService;
|
||||
|
||||
setUp(() {
|
||||
mockService = MockGlossaryService();
|
||||
repository = GlossaryRepository(glossaryService: mockService);
|
||||
});
|
||||
|
||||
test('getGlossaryListByQuery - успешный запрос', () async {
|
||||
const query = 'test';
|
||||
final mockGlossaries = <GlossaryModel>[];
|
||||
final mockPagination = GlossaryPaginationModel(glossariesList: mockGlossaries);
|
||||
|
||||
when(() => mockService.getGlossaryByQuery(query: query))
|
||||
.thenAnswer((_) async => mockPagination);
|
||||
|
||||
final result = await repository.getGlossaryListByQuery(query);
|
||||
|
||||
expect(result, mockGlossaries);
|
||||
verify(() => mockService.getGlossaryByQuery(query: query)).called(1);
|
||||
});
|
||||
|
||||
test('getGlossaryListByQuery - пробрасывает ошибку', () async {
|
||||
const query = 'test';
|
||||
|
||||
when(() => mockService.getGlossaryByQuery(query: query))
|
||||
.thenThrow(Exception('Error'));
|
||||
|
||||
expect(() => repository.getGlossaryListByQuery(query), throwsException);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/my_finance/models/payment_url_model.dart';
|
||||
import 'package:eatvio_app/features/my_finance/presentation/cubit/user_cards_cubit/user_cards_cubit.dart';
|
||||
import 'package:eatvio_app/features/my_finance/presentation/cubit/user_cards_cubit/user_cards_state.dart';
|
||||
import 'package:eatvio_app/features/my_finance/presentation/widgets/card_widget.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'card_widget_test.mocks.dart';
|
||||
|
||||
@GenerateNiceMocks([MockSpec<UserCardsCubit>()])
|
||||
void main() {
|
||||
group('CardWidget', () {
|
||||
late MockUserCardsCubit mockCubit;
|
||||
|
||||
setUp(() {
|
||||
mockCubit = MockUserCardsCubit();
|
||||
});
|
||||
|
||||
Widget createTestWidget({
|
||||
bool isSelected = false,
|
||||
bool enabledAddCard = false,
|
||||
int cardId = 0,
|
||||
String cardNumber = '',
|
||||
}) {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: const [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [Locale('ru'), Locale('en')],
|
||||
locale: const Locale('ru'),
|
||||
home: BlocProvider<UserCardsCubit>.value(
|
||||
value: mockCubit,
|
||||
child: Scaffold(
|
||||
body: CardWidget(
|
||||
isSelected: isSelected,
|
||||
enabledAddCard: enabledAddCard,
|
||||
cardId: cardId,
|
||||
cardNumber: cardNumber,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays card widget with card number', (tester) async {
|
||||
when(mockCubit.stream).thenAnswer((_) => Stream.value(UserCardsState()));
|
||||
|
||||
await tester.pumpWidget(createTestWidget(
|
||||
cardId: 1,
|
||||
cardNumber: '1234 5678 9012 3456',
|
||||
));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(CardWidget), findsOneWidget);
|
||||
expect(find.text('1234 5678 9012 3456'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays add card widget when enabledAddCard is true', (tester) async {
|
||||
when(mockCubit.stream).thenAnswer((_) => Stream.value(UserCardsState()));
|
||||
|
||||
await tester.pumpWidget(createTestWidget(
|
||||
enabledAddCard: true,
|
||||
));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(CardWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('calls markAsDefault when card is tapped', (tester) async {
|
||||
when(mockCubit.state).thenReturn(UserCardsState());
|
||||
when(mockCubit.stream).thenAnswer((_) => Stream.value(UserCardsState()));
|
||||
when(mockCubit.markAsDefault(id: anyNamed('id'))).thenAnswer((_) async {});
|
||||
|
||||
await tester.pumpWidget(createTestWidget(
|
||||
cardId: 1,
|
||||
cardNumber: '1234 5678 9012 3456',
|
||||
));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byType(CardWidget));
|
||||
await tester.pump();
|
||||
|
||||
verify(mockCubit.markAsDefault(id: 1)).called(1);
|
||||
});
|
||||
|
||||
testWidgets('calls addCard when add card widget is tapped', (tester) async {
|
||||
when(mockCubit.state).thenReturn(UserCardsState());
|
||||
when(mockCubit.stream).thenAnswer((_) => Stream.value(UserCardsState()));
|
||||
when(mockCubit.addCard()).thenAnswer((_) async => PaymentUrlModel(paymentUrl: 'https://example.com'));
|
||||
|
||||
await tester.pumpWidget(createTestWidget(
|
||||
enabledAddCard: true,
|
||||
));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.byType(CardWidget));
|
||||
await tester.pump();
|
||||
|
||||
verify(mockCubit.addCard()).called(1);
|
||||
});
|
||||
|
||||
testWidgets('calls deleteCard when delete button is tapped', (tester) async {
|
||||
when(mockCubit.state).thenReturn(UserCardsState());
|
||||
when(mockCubit.stream).thenAnswer((_) => Stream.value(UserCardsState()));
|
||||
when(mockCubit.markAsDefault(id: anyNamed('id'))).thenAnswer((_) async {});
|
||||
when(mockCubit.deleteCard(id: anyNamed('id'))).thenAnswer((_) async {});
|
||||
|
||||
await tester.pumpWidget(createTestWidget(
|
||||
cardId: 1,
|
||||
cardNumber: '1234 5678 9012 3456',
|
||||
));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Find delete button (close icon)
|
||||
final deleteButton = find.byType(GestureDetector);
|
||||
if (deleteButton.evaluate().length > 1) {
|
||||
await tester.tap(deleteButton.last);
|
||||
await tester.pump();
|
||||
|
||||
verify(mockCubit.deleteCard(id: 1)).called(1);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,169 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eatvio_app/features/notifications/models/notification_model.dart';
|
||||
import 'package:eatvio_app/features/notifications/service/notifications_service.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'notifications_service_test.mocks.dart';
|
||||
|
||||
@GenerateMocks([Dio])
|
||||
void main() {
|
||||
group('NotificationsService', () {
|
||||
late NotificationsService service;
|
||||
late MockDio mockDio;
|
||||
|
||||
setUp(() {
|
||||
mockDio = MockDio();
|
||||
service = NotificationsService(mockDio);
|
||||
});
|
||||
|
||||
test('getNotifications returns null when status code is not 200', () async {
|
||||
when(mockDio.get(any)).thenAnswer((_) async => Response(
|
||||
requestOptions: RequestOptions(path: '/api/profile/notifications'),
|
||||
statusCode: 404,
|
||||
data: {},
|
||||
));
|
||||
|
||||
final result = await service.getNotifications(page: 1);
|
||||
|
||||
expect(result, isNull);
|
||||
});
|
||||
|
||||
test('getNotifications parses notifications correctly', () async {
|
||||
when(mockDio.get(any)).thenAnswer((_) async => Response(
|
||||
requestOptions: RequestOptions(path: '/api/profile/notifications'),
|
||||
statusCode: 200,
|
||||
data: {
|
||||
'data': [
|
||||
{
|
||||
'type': 'diary-reminder-notification',
|
||||
'read_at': null,
|
||||
'created_at': '2024-01-15T10:30:00Z',
|
||||
'data': {},
|
||||
}
|
||||
],
|
||||
'current_page': 1,
|
||||
'last_page': 1,
|
||||
'per_page': 10,
|
||||
'total': 1,
|
||||
},
|
||||
));
|
||||
|
||||
final result = await service.getNotifications(page: 1);
|
||||
|
||||
expect(result, isNotNull);
|
||||
expect(result!['notifications'], isA<List>());
|
||||
expect(result['pagination'], isA<Map>());
|
||||
expect(result['pagination']['current_page'], 1);
|
||||
});
|
||||
|
||||
test('getNotifications handles unknown notification type', () async {
|
||||
when(mockDio.get(any)).thenAnswer((_) async => Response(
|
||||
requestOptions: RequestOptions(path: '/api/profile/notifications'),
|
||||
statusCode: 200,
|
||||
data: {
|
||||
'data': [
|
||||
{
|
||||
'type': 'unknown-type',
|
||||
'read_at': null,
|
||||
'created_at': '2024-01-15T10:30:00Z',
|
||||
'data': {},
|
||||
}
|
||||
],
|
||||
'current_page': 1,
|
||||
'last_page': 1,
|
||||
'per_page': 10,
|
||||
'total': 1,
|
||||
},
|
||||
));
|
||||
|
||||
final result = await service.getNotifications(page: 1);
|
||||
|
||||
expect(result, isNotNull);
|
||||
expect(result!['notifications'], isA<List>());
|
||||
final notifications = result['notifications'] as List;
|
||||
expect(notifications.first, isA<UnknownNotification>());
|
||||
});
|
||||
|
||||
test('getNotifications handles notification_class_name field', () async {
|
||||
when(mockDio.get(any)).thenAnswer((_) async => Response(
|
||||
requestOptions: RequestOptions(path: '/api/profile/notifications'),
|
||||
statusCode: 200,
|
||||
data: {
|
||||
'data': [
|
||||
{
|
||||
'notification_class_name': 'App\\Notifications\\DiaryReminderNotification',
|
||||
'read_at': null,
|
||||
'created_at': '2024-01-15T10:30:00Z',
|
||||
'data': {},
|
||||
}
|
||||
],
|
||||
'current_page': 1,
|
||||
'last_page': 1,
|
||||
'per_page': 10,
|
||||
'total': 1,
|
||||
},
|
||||
));
|
||||
|
||||
final result = await service.getNotifications(page: 1);
|
||||
|
||||
expect(result, isNotNull);
|
||||
expect(result!['notifications'], isA<List>());
|
||||
});
|
||||
|
||||
test('getNotifications handles read_at correctly', () async {
|
||||
when(mockDio.get(any)).thenAnswer((_) async => Response(
|
||||
requestOptions: RequestOptions(path: '/api/profile/notifications'),
|
||||
statusCode: 200,
|
||||
data: {
|
||||
'data': [
|
||||
{
|
||||
'type': 'diary-reminder-notification',
|
||||
'read_at': '2024-01-15T10:30:00Z',
|
||||
'created_at': '2024-01-15T10:30:00Z',
|
||||
'data': {},
|
||||
}
|
||||
],
|
||||
'current_page': 1,
|
||||
'last_page': 1,
|
||||
'per_page': 10,
|
||||
'total': 1,
|
||||
},
|
||||
));
|
||||
|
||||
final result = await service.getNotifications(page: 1);
|
||||
|
||||
expect(result, isNotNull);
|
||||
expect(result!['notifications'], isA<List>());
|
||||
});
|
||||
|
||||
test('getNotifications rethrows exceptions', () async {
|
||||
when(mockDio.get(any)).thenThrow(DioException(
|
||||
requestOptions: RequestOptions(path: '/api/profile/notifications'),
|
||||
));
|
||||
|
||||
expect(() => service.getNotifications(page: 1), throwsA(isA<DioException>()));
|
||||
});
|
||||
|
||||
test('markNotificationsAsRead calls correct endpoint', () async {
|
||||
when(mockDio.post(any)).thenAnswer((_) async => Response(
|
||||
requestOptions: RequestOptions(path: '/api/profile/mark_notifications_as_readed'),
|
||||
statusCode: 200,
|
||||
));
|
||||
|
||||
await service.markNotificationsAsRead();
|
||||
|
||||
verify(mockDio.post('/api/profile/mark_notifications_as_readed')).called(1);
|
||||
});
|
||||
|
||||
test('markNotificationsAsRead rethrows exceptions', () async {
|
||||
when(mockDio.post(any)).thenThrow(DioException(
|
||||
requestOptions: RequestOptions(path: '/api/profile/mark_notifications_as_readed'),
|
||||
));
|
||||
|
||||
expect(() => service.markNotificationsAsRead(), throwsA(isA<DioException>()));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import 'package:eatvio_app/core/app_initializer.dart';
|
||||
import 'package:eatvio_app/core/di/app_config_registration.dart';
|
||||
import 'package:eatvio_app/core/locator_service.dart';
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/profile/presentation/bloc/profile_cubit/profile_cubit.dart';
|
||||
import 'package:eatvio_app/features/profile/presentation/bloc/sub_cubit/sub_cubit.dart';
|
||||
import 'package:eatvio_app/features/profile/presentation/bloc/sub_cubit/sub_state.dart';
|
||||
import 'package:eatvio_app/features/profile/presentation/widgets/sub_action_button_widget.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'sub_action_button_widget_test.mocks.dart';
|
||||
|
||||
@GenerateNiceMocks([
|
||||
MockSpec<SubCubit>(),
|
||||
MockSpec<ProfileCubit>(),
|
||||
])
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('SubActionButtonWidget', () {
|
||||
late MockSubCubit mockSubCubit;
|
||||
late MockProfileCubit mockProfileCubit;
|
||||
|
||||
setUp(() async {
|
||||
await sl.reset();
|
||||
AppConfigRegistration.registerAppConfig(buildType: AppBuildType.tests);
|
||||
mockSubCubit = MockSubCubit();
|
||||
mockProfileCubit = MockProfileCubit();
|
||||
sl.registerLazySingleton<SubCubit>(() => mockSubCubit);
|
||||
sl.registerLazySingleton<ProfileCubit>(() => mockProfileCubit);
|
||||
});
|
||||
|
||||
Widget createTestWidget(SubActionType actionType) {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
home: MultiBlocProvider(
|
||||
providers: [
|
||||
BlocProvider<SubCubit>.value(value: mockSubCubit),
|
||||
BlocProvider<ProfileCubit>.value(value: mockProfileCubit),
|
||||
],
|
||||
child: Scaffold(
|
||||
body: SubActionButtonWidget(
|
||||
subActionType: actionType,
|
||||
slug: 'test-slug',
|
||||
name: 'Test User',
|
||||
porfileIcon: 'https://example.com/icon.jpg',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays subscribe button when action type is subscribe', (tester) async {
|
||||
|
||||
await tester.pumpWidget(createTestWidget(SubActionType.subscribe));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(SubActionButtonWidget), findsOneWidget);
|
||||
expect(find.text('Подписаться'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays message button when action type is sendMessage', (tester) async {
|
||||
|
||||
await tester.pumpWidget(createTestWidget(SubActionType.sendMessage));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(SubActionButtonWidget), findsOneWidget);
|
||||
expect(find.text('Сообщение'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('calls subscribe when subscribe button is tapped', (tester) async {
|
||||
when(mockSubCubit.state).thenReturn(const SubState());
|
||||
when(mockSubCubit.stream).thenAnswer((_) => Stream.value(const SubState()));
|
||||
when(mockSubCubit.subscribe(any)).thenAnswer((_) async {});
|
||||
|
||||
await tester.pumpWidget(createTestWidget(SubActionType.subscribe));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
await tester.tap(find.text('Подписаться'));
|
||||
await tester.pump();
|
||||
|
||||
verify(mockSubCubit.subscribe('test-slug')).called(1);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
import 'package:eatvio_app/core/prefs.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/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_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
|
||||
import 'blood_pressure_screen_test.mocks.dart';
|
||||
|
||||
@GenerateMocks([RegistrationRepository, Prefs])
|
||||
void main() {
|
||||
group('BloodPressureScreen', () {
|
||||
late MockRegistrationRepository mockRegistrationRepository;
|
||||
late MockPrefs mockPrefs;
|
||||
late RegistrationCubit registrationCubit;
|
||||
|
||||
setUp(() {
|
||||
mockRegistrationRepository = MockRegistrationRepository();
|
||||
mockPrefs = MockPrefs();
|
||||
registrationCubit = RegistrationCubit(
|
||||
registrationRepository: mockRegistrationRepository,
|
||||
prefs: mockPrefs,
|
||||
);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
registrationCubit.close();
|
||||
});
|
||||
|
||||
Widget createTestWidget(UserRegistrationSheet sheet) {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
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),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays blood pressure screen', (tester) async {
|
||||
final 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.byType(BloodPressureScreen), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays existing blood pressure values', (tester) async {
|
||||
final 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 {
|
||||
final 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();
|
||||
|
||||
expect(find.byType(BloodPressureScreen), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
import 'package:eatvio_app/core/prefs.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/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_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
|
||||
import 'credentials_screen_test.mocks.dart';
|
||||
|
||||
@GenerateMocks([RegistrationRepository, Prefs])
|
||||
void main() {
|
||||
group('CredentialsScreen', () {
|
||||
late MockRegistrationRepository mockRegistrationRepository;
|
||||
late MockPrefs mockPrefs;
|
||||
late RegistrationCubit registrationCubit;
|
||||
|
||||
setUp(() {
|
||||
mockRegistrationRepository = MockRegistrationRepository();
|
||||
mockPrefs = MockPrefs();
|
||||
registrationCubit = RegistrationCubit(
|
||||
registrationRepository: mockRegistrationRepository,
|
||||
prefs: mockPrefs,
|
||||
);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
registrationCubit.close();
|
||||
});
|
||||
|
||||
Widget createTestWidget(UserRegistrationSheet sheet) {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
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),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays email field', (tester) async {
|
||||
final 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: '',
|
||||
);
|
||||
|
||||
await tester.pumpWidget(createTestWidget(sheet));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(CredentialsScreen), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays password fields', (tester) async {
|
||||
final 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 {
|
||||
final 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();
|
||||
|
||||
expect(find.byType(CredentialsScreen), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
import 'package:eatvio_app/core/prefs.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/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_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
|
||||
import 'date_of_birth_screen_test.mocks.dart';
|
||||
|
||||
@GenerateMocks([RegistrationRepository, Prefs])
|
||||
void main() {
|
||||
group('DateOfBirthScreen', () {
|
||||
late MockRegistrationRepository mockRegistrationRepository;
|
||||
late MockPrefs mockPrefs;
|
||||
late RegistrationCubit registrationCubit;
|
||||
|
||||
setUp(() {
|
||||
mockRegistrationRepository = MockRegistrationRepository();
|
||||
mockPrefs = MockPrefs();
|
||||
registrationCubit = RegistrationCubit(
|
||||
registrationRepository: mockRegistrationRepository,
|
||||
prefs: mockPrefs,
|
||||
);
|
||||
});
|
||||
|
||||
tearDown(() {
|
||||
registrationCubit.close();
|
||||
});
|
||||
|
||||
Widget createTestWidget(UserRegistrationSheet sheet) {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
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),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays date of birth screen', (tester) async {
|
||||
final 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.byType(DateOfBirthScreen), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays existing birthdate when provided', (tester) async {
|
||||
final 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 {
|
||||
final 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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/registration_v2/cubit/registration_cubit.dart';
|
||||
import 'package:eatvio_app/features/registration_v2/cubit/registration_state.dart';
|
||||
import 'package:eatvio_app/features/registration_v2/presentation/widgets/sex_widget.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'sex_widget_test.mocks.dart';
|
||||
|
||||
@GenerateNiceMocks([MockSpec<RegistrationCubitV2>()])
|
||||
void main() {
|
||||
group('SexWidget', () {
|
||||
late MockRegistrationCubitV2 mockCubit;
|
||||
|
||||
setUp(() {
|
||||
mockCubit = MockRegistrationCubitV2();
|
||||
});
|
||||
|
||||
Widget createTestWidget() {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: const [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [Locale('ru')],
|
||||
home: BlocProvider<RegistrationCubitV2>.value(
|
||||
value: mockCubit,
|
||||
child: Scaffold(
|
||||
body: SexWidget(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays sex widget', (tester) async {
|
||||
when(mockCubit.state).thenReturn(
|
||||
RegistrationStateV2(
|
||||
step: 0,
|
||||
gender: '',
|
||||
isGenderValid: true,
|
||||
),
|
||||
);
|
||||
when(mockCubit.stream).thenAnswer((_) => Stream.value(
|
||||
RegistrationStateV2(
|
||||
step: 0,
|
||||
gender: '',
|
||||
isGenderValid: true,
|
||||
),
|
||||
));
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(SexWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('calls setGender when male is tapped', (tester) async {
|
||||
when(mockCubit.state).thenReturn(
|
||||
RegistrationStateV2(
|
||||
step: 0,
|
||||
gender: '',
|
||||
isGenderValid: true,
|
||||
),
|
||||
);
|
||||
when(mockCubit.stream).thenAnswer((_) => Stream.value(
|
||||
RegistrationStateV2(
|
||||
step: 0,
|
||||
gender: '',
|
||||
isGenderValid: true,
|
||||
),
|
||||
));
|
||||
when(mockCubit.setGender(any)).thenAnswer((_) async {});
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Find and tap male button - try to find by InkWell or text
|
||||
final inkWells = find.byType(InkWell);
|
||||
if (inkWells.evaluate().isNotEmpty) {
|
||||
await tester.tap(inkWells.first);
|
||||
await tester.pump();
|
||||
|
||||
verify(mockCubit.setGender('male')).called(1);
|
||||
}
|
||||
});
|
||||
|
||||
testWidgets('shows error when gender is invalid', (tester) async {
|
||||
when(mockCubit.state).thenReturn(
|
||||
RegistrationStateV2(
|
||||
step: 0,
|
||||
gender: '',
|
||||
isGenderValid: false,
|
||||
),
|
||||
);
|
||||
when(mockCubit.stream).thenAnswer((_) => Stream.value(
|
||||
RegistrationStateV2(
|
||||
step: 0,
|
||||
gender: '',
|
||||
isGenderValid: false,
|
||||
),
|
||||
));
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(SexWidget), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import 'package:eatvio_app/core/theme/theme_helper.dart';
|
||||
import 'package:eatvio_app/features/registration_v2/cubit/registration_cubit.dart';
|
||||
import 'package:eatvio_app/features/registration_v2/cubit/registration_state.dart';
|
||||
import 'package:eatvio_app/features/registration_v2/presentation/widgets/step_widget.dart';
|
||||
import 'package:eatvio_app/generated/l10n.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
import 'step_widget_test.mocks.dart';
|
||||
|
||||
@GenerateMocks([RegistrationCubitV2])
|
||||
void main() {
|
||||
group('StepWidget', () {
|
||||
late MockRegistrationCubitV2 mockCubit;
|
||||
|
||||
setUp(() {
|
||||
mockCubit = MockRegistrationCubitV2();
|
||||
});
|
||||
|
||||
Widget createTestWidget() {
|
||||
return MaterialApp(
|
||||
theme: ThemeHelper().themeData(),
|
||||
localizationsDelegates: const [
|
||||
S.delegate,
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
supportedLocales: const [Locale('ru'), Locale('en')],
|
||||
locale: const Locale('ru'),
|
||||
home: BlocProvider<RegistrationCubitV2>.value(
|
||||
value: mockCubit,
|
||||
child: Scaffold(
|
||||
body: StepWidget(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
testWidgets('displays step widget', (tester) async {
|
||||
when(mockCubit.state).thenReturn(
|
||||
RegistrationStateV2(step: 0),
|
||||
);
|
||||
when(mockCubit.stream).thenAnswer((_) => Stream.value(RegistrationStateV2(step: 0)));
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(StepWidget), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('displays correct step number', (tester) async {
|
||||
when(mockCubit.state).thenReturn(
|
||||
RegistrationStateV2(step: 2),
|
||||
);
|
||||
when(mockCubit.stream).thenAnswer((_) => Stream.value(RegistrationStateV2(step: 2)));
|
||||
|
||||
await tester.pumpWidget(createTestWidget());
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
expect(find.byType(StepWidget), findsOneWidget);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,12 +2,10 @@ import 'package:eatvio_app/features/registration_v2/models/registration_model.da
|
||||
import 'package:eatvio_app/features/registration_v2/repositories/registration_repository_v2.dart';
|
||||
import 'package:eatvio_app/features/registration_v2/services/registration_service_v2.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
|
||||
import 'registration_repository_v2_test.mocks.dart';
|
||||
class MockRegistrationServiceV2 extends Mock implements RegistrationServiceV2 {}
|
||||
|
||||
@GenerateMocks([RegistrationServiceV2])
|
||||
void main() {
|
||||
group('RegistrationRepositoryV2', () {
|
||||
late RegistrationRepositoryV2 repository;
|
||||
@@ -18,10 +16,11 @@ void main() {
|
||||
repository = RegistrationRepositoryV2(registrationService: mockService);
|
||||
});
|
||||
|
||||
test('register - успешная регистрация', () async {
|
||||
test('register - успешная регистрация возвращает токен', () async {
|
||||
const token = 'test-token-123';
|
||||
final registrationModel = RegistrationModel(
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
firstName: 'Test',
|
||||
lastName: 'User',
|
||||
email: 'test@example.com',
|
||||
phone: '+1234567890',
|
||||
gender: 'male',
|
||||
@@ -33,20 +32,19 @@ void main() {
|
||||
birthday: '1990-01-01',
|
||||
);
|
||||
|
||||
const token = 'test-token';
|
||||
when(mockService.register(model: anyNamed('model')))
|
||||
when(() => mockService.register(model: any(named: 'model')))
|
||||
.thenAnswer((_) async => {'token': token});
|
||||
|
||||
final result = await repository.register(registrationModel: registrationModel);
|
||||
|
||||
expect(result, equals(token));
|
||||
verify(mockService.register(model: anyNamed('model'))).called(1);
|
||||
expect(result, token);
|
||||
verify(() => mockService.register(model: any(named: 'model'))).called(1);
|
||||
});
|
||||
|
||||
test('register - проброс ошибки', () async {
|
||||
test('register - возвращает null если токена нет', () async {
|
||||
final registrationModel = RegistrationModel(
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
firstName: 'Test',
|
||||
lastName: 'User',
|
||||
email: 'test@example.com',
|
||||
phone: '+1234567890',
|
||||
gender: 'male',
|
||||
@@ -58,16 +56,33 @@ void main() {
|
||||
birthday: '1990-01-01',
|
||||
);
|
||||
|
||||
final error = Exception('Ошибка регистрации');
|
||||
when(mockService.register(model: anyNamed('model')))
|
||||
.thenThrow(error);
|
||||
when(() => mockService.register(model: any(named: 'model')))
|
||||
.thenAnswer((_) async => {});
|
||||
|
||||
expect(
|
||||
() => repository.register(registrationModel: registrationModel),
|
||||
throwsA(error),
|
||||
final result = await repository.register(registrationModel: registrationModel);
|
||||
|
||||
expect(result, null);
|
||||
});
|
||||
|
||||
test('register - пробрасывает ошибку', () async {
|
||||
final registrationModel = RegistrationModel(
|
||||
firstName: 'Test',
|
||||
lastName: 'User',
|
||||
email: 'test@example.com',
|
||||
phone: '+1234567890',
|
||||
gender: 'male',
|
||||
password: 'password123',
|
||||
confirmPassword: 'password123',
|
||||
weight: 70,
|
||||
height: 175,
|
||||
activityCoefficient: 1.5,
|
||||
birthday: '1990-01-01',
|
||||
);
|
||||
verify(mockService.register(model: anyNamed('model'))).called(1);
|
||||
|
||||
when(() => mockService.register(model: any(named: 'model')))
|
||||
.thenThrow(Exception('Error'));
|
||||
|
||||
expect(() => repository.register(registrationModel: registrationModel), throwsException);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user