forked from eatvio/eatvio_app
feat(tests): tests coverage 67.2
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import 'package:easy_debounce/easy_debounce.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/feed/models/recipes_model.dart';
|
||||
import 'package:eatvio_app/features/recipe/presentation/cubit/about_recipe_cubit.dart';
|
||||
@@ -12,6 +13,8 @@ import 'about_recipe_cubit_test.mocks.dart';
|
||||
|
||||
@GenerateNiceMocks([MockSpec<AboutRecipeRepository>(), MockSpec<ProfileRepository>()])
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
group('AboutRecipeCubit', () {
|
||||
AboutRecipeCubit? aboutRecipeCubit;
|
||||
late MockAboutRecipeRepository mockRecipeRepository;
|
||||
@@ -23,6 +26,8 @@ void main() {
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
EasyDebounce.cancel('like_recipe');
|
||||
EasyDebounce.cancel('add_or_remove_diet_to_favorites');
|
||||
if (aboutRecipeCubit != null && !aboutRecipeCubit!.isClosed) {
|
||||
await aboutRecipeCubit!.close();
|
||||
aboutRecipeCubit = null;
|
||||
@@ -346,5 +351,430 @@ void main() {
|
||||
await Future.delayed(const Duration(milliseconds: 1200));
|
||||
verify(mockRecipeRepository.removeFromFavorite('1')).called(1);
|
||||
});
|
||||
|
||||
test('getRecipe - с index параметром', () async {
|
||||
aboutRecipeCubit = AboutRecipeCubit(recipeRepository: mockRecipeRepository, profileRepository: mockProfileRepository);
|
||||
|
||||
const testRecipe = Recipe(
|
||||
id: 1,
|
||||
image: 'https://example.com/image.jpg',
|
||||
state: 'active',
|
||||
cookingTime: 30,
|
||||
activeCookingTime: 15,
|
||||
ingredients: [],
|
||||
description: 'Test description',
|
||||
steps: [],
|
||||
videoUrl: null,
|
||||
createdAt: null,
|
||||
updatedAt: null,
|
||||
title: 'Test Recipe',
|
||||
type: 'main',
|
||||
slug: 'test-recipe',
|
||||
commentsCount: 5,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: false,
|
||||
calories: 300.0,
|
||||
servings: 4,
|
||||
likesCount: 10,
|
||||
viewsCount: 100,
|
||||
tags: [],
|
||||
author: Author(
|
||||
authorSlug: 'author',
|
||||
authorName: 'Author Name',
|
||||
authorProfileIcon: 'https://example.com/icon.jpg',
|
||||
authorIsMe: false,
|
||||
isEntitySubscribedByMe: null,
|
||||
authorPlaceInRating: null,
|
||||
),
|
||||
);
|
||||
|
||||
when(mockRecipeRepository.getRecipe('1')).thenAnswer((_) async => testRecipe);
|
||||
|
||||
await aboutRecipeCubit!.getRecipe('1', index: 0);
|
||||
|
||||
expect(aboutRecipeCubit!.state, isA<AboutRecipeStateLoaded>());
|
||||
verify(mockRecipeRepository.emitCommentsStateToFeed(any)).called(1);
|
||||
});
|
||||
|
||||
test('initRecipe - с index параметром', () async {
|
||||
aboutRecipeCubit = AboutRecipeCubit(recipeRepository: mockRecipeRepository, profileRepository: mockProfileRepository);
|
||||
|
||||
const testRecipe = Recipe(
|
||||
id: 1,
|
||||
image: 'https://example.com/image.jpg',
|
||||
state: 'active',
|
||||
cookingTime: 30,
|
||||
activeCookingTime: 15,
|
||||
ingredients: [],
|
||||
description: 'Test description',
|
||||
steps: [],
|
||||
videoUrl: null,
|
||||
createdAt: null,
|
||||
updatedAt: null,
|
||||
title: 'Test Recipe',
|
||||
type: 'main',
|
||||
slug: 'test-recipe',
|
||||
commentsCount: 5,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: false,
|
||||
calories: 300.0,
|
||||
servings: 4,
|
||||
likesCount: 10,
|
||||
viewsCount: 100,
|
||||
tags: [],
|
||||
author: Author(
|
||||
authorSlug: 'author',
|
||||
authorName: 'Author Name',
|
||||
authorProfileIcon: 'https://example.com/icon.jpg',
|
||||
authorIsMe: false,
|
||||
isEntitySubscribedByMe: null,
|
||||
authorPlaceInRating: null,
|
||||
),
|
||||
);
|
||||
|
||||
when(mockRecipeRepository.getRecipe('1')).thenAnswer((_) async => testRecipe);
|
||||
|
||||
await aboutRecipeCubit!.initRecipe('1', index: 0);
|
||||
|
||||
expect(aboutRecipeCubit!.state, isA<AboutRecipeStateLoaded>());
|
||||
verify(mockRecipeRepository.emitCommentsStateToFeed(any)).called(1);
|
||||
});
|
||||
|
||||
test('likeRecipe - с recipeIndexInFeed параметром', () async {
|
||||
aboutRecipeCubit = AboutRecipeCubit(recipeRepository: mockRecipeRepository, profileRepository: mockProfileRepository);
|
||||
|
||||
const testRecipe = Recipe(
|
||||
id: 1,
|
||||
image: 'https://example.com/image.jpg',
|
||||
state: 'active',
|
||||
cookingTime: 30,
|
||||
activeCookingTime: 15,
|
||||
ingredients: [],
|
||||
description: 'Test description',
|
||||
steps: [],
|
||||
videoUrl: null,
|
||||
createdAt: null,
|
||||
updatedAt: null,
|
||||
title: 'Test Recipe',
|
||||
type: 'main',
|
||||
slug: 'test-recipe',
|
||||
commentsCount: 5,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: false,
|
||||
calories: 300.0,
|
||||
servings: 4,
|
||||
likesCount: 10,
|
||||
viewsCount: 100,
|
||||
tags: [],
|
||||
author: Author(
|
||||
authorSlug: 'author',
|
||||
authorName: 'Author Name',
|
||||
authorProfileIcon: 'https://example.com/icon.jpg',
|
||||
authorIsMe: false,
|
||||
isEntitySubscribedByMe: null,
|
||||
authorPlaceInRating: null,
|
||||
),
|
||||
);
|
||||
|
||||
when(mockRecipeRepository.getRecipe('1')).thenAnswer((_) async => testRecipe);
|
||||
when(mockRecipeRepository.likeRecipe('1')).thenAnswer((_) async => {});
|
||||
|
||||
await aboutRecipeCubit!.getRecipe('1');
|
||||
await aboutRecipeCubit!.likeRecipe('1', 0);
|
||||
|
||||
expect(aboutRecipeCubit!.state, isA<AboutRecipeStateLoaded>());
|
||||
final loadedState = aboutRecipeCubit!.state as AboutRecipeStateLoaded;
|
||||
expect(loadedState.recipe.wasLikedByMe, isTrue);
|
||||
verify(mockRecipeRepository.emitLikesStateToFeed(any)).called(1);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 1200));
|
||||
verify(mockRecipeRepository.likeRecipe('1')).called(1);
|
||||
});
|
||||
|
||||
test('likeRecipe - обработка ошибки', () async {
|
||||
aboutRecipeCubit = AboutRecipeCubit(recipeRepository: mockRecipeRepository, profileRepository: mockProfileRepository);
|
||||
|
||||
const testRecipe = Recipe(
|
||||
id: 1,
|
||||
image: 'https://example.com/image.jpg',
|
||||
state: 'active',
|
||||
cookingTime: 30,
|
||||
activeCookingTime: 15,
|
||||
ingredients: [],
|
||||
description: 'Test description',
|
||||
steps: [],
|
||||
videoUrl: null,
|
||||
createdAt: null,
|
||||
updatedAt: null,
|
||||
title: 'Test Recipe',
|
||||
type: 'main',
|
||||
slug: 'test-recipe',
|
||||
commentsCount: 5,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: false,
|
||||
calories: 300.0,
|
||||
servings: 4,
|
||||
likesCount: 10,
|
||||
viewsCount: 100,
|
||||
tags: [],
|
||||
author: Author(
|
||||
authorSlug: 'author',
|
||||
authorName: 'Author Name',
|
||||
authorProfileIcon: 'https://example.com/icon.jpg',
|
||||
authorIsMe: false,
|
||||
isEntitySubscribedByMe: null,
|
||||
authorPlaceInRating: null,
|
||||
),
|
||||
);
|
||||
|
||||
when(mockRecipeRepository.getRecipe('1')).thenAnswer((_) async => testRecipe);
|
||||
when(mockRecipeRepository.likeRecipe('1')).thenThrow(Exception('Ошибка'));
|
||||
|
||||
await aboutRecipeCubit!.getRecipe('1');
|
||||
await aboutRecipeCubit!.likeRecipe('1', 0);
|
||||
|
||||
expect(aboutRecipeCubit!.state, isA<AboutRecipeStateLoaded>());
|
||||
final loadedState = aboutRecipeCubit!.state as AboutRecipeStateLoaded;
|
||||
expect(loadedState.recipe.wasLikedByMe, isTrue);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 1200));
|
||||
|
||||
// После ошибки состояние должно вернуться к исходному
|
||||
final finalState = aboutRecipeCubit!.state as AboutRecipeStateLoaded;
|
||||
expect(finalState.recipe.wasLikedByMe, isFalse);
|
||||
expect(finalState.recipe.likesCount, 10);
|
||||
verify(mockRecipeRepository.emitLikesStateToFeed(any)).called(2); // Один раз при лайке, второй раз при ошибке
|
||||
});
|
||||
|
||||
test('addToFavorite - с recipeIndex параметром', () async {
|
||||
aboutRecipeCubit = AboutRecipeCubit(recipeRepository: mockRecipeRepository, profileRepository: mockProfileRepository);
|
||||
|
||||
const testRecipe = Recipe(
|
||||
id: 1,
|
||||
image: 'https://example.com/image.jpg',
|
||||
state: 'active',
|
||||
cookingTime: 30,
|
||||
activeCookingTime: 15,
|
||||
ingredients: [],
|
||||
description: 'Test description',
|
||||
steps: [],
|
||||
videoUrl: null,
|
||||
createdAt: null,
|
||||
updatedAt: null,
|
||||
title: 'Test Recipe',
|
||||
type: 'main',
|
||||
slug: 'test-recipe',
|
||||
commentsCount: 5,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: false,
|
||||
calories: 300.0,
|
||||
servings: 4,
|
||||
likesCount: 10,
|
||||
viewsCount: 100,
|
||||
tags: [],
|
||||
author: Author(
|
||||
authorSlug: 'author',
|
||||
authorName: 'Author Name',
|
||||
authorProfileIcon: 'https://example.com/icon.jpg',
|
||||
authorIsMe: false,
|
||||
isEntitySubscribedByMe: null,
|
||||
authorPlaceInRating: null,
|
||||
),
|
||||
);
|
||||
|
||||
when(mockRecipeRepository.getRecipe('1')).thenAnswer((_) async => testRecipe);
|
||||
when(mockRecipeRepository.addToFavorite('1')).thenAnswer((_) async => {});
|
||||
|
||||
await aboutRecipeCubit!.getRecipe('1');
|
||||
await aboutRecipeCubit!.addToFavorite('1', 0);
|
||||
|
||||
expect(aboutRecipeCubit!.state, isA<AboutRecipeStateLoaded>());
|
||||
final loadedState = aboutRecipeCubit!.state as AboutRecipeStateLoaded;
|
||||
expect(loadedState.recipe.isFavorite, true);
|
||||
verify(mockRecipeRepository.emitFavoriteStateToFeed(any)).called(1);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 1200));
|
||||
verify(mockRecipeRepository.addToFavorite('1')).called(1);
|
||||
});
|
||||
|
||||
test('addToFavorite - обработка ошибки', () async {
|
||||
aboutRecipeCubit = AboutRecipeCubit(recipeRepository: mockRecipeRepository, profileRepository: mockProfileRepository);
|
||||
|
||||
const testRecipe = Recipe(
|
||||
id: 1,
|
||||
image: 'https://example.com/image.jpg',
|
||||
state: 'active',
|
||||
cookingTime: 30,
|
||||
activeCookingTime: 15,
|
||||
ingredients: [],
|
||||
description: 'Test description',
|
||||
steps: [],
|
||||
videoUrl: null,
|
||||
createdAt: null,
|
||||
updatedAt: null,
|
||||
title: 'Test Recipe',
|
||||
type: 'main',
|
||||
slug: 'test-recipe',
|
||||
commentsCount: 5,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: false,
|
||||
calories: 300.0,
|
||||
servings: 4,
|
||||
likesCount: 10,
|
||||
viewsCount: 100,
|
||||
tags: [],
|
||||
author: Author(
|
||||
authorSlug: 'author',
|
||||
authorName: 'Author Name',
|
||||
authorProfileIcon: 'https://example.com/icon.jpg',
|
||||
authorIsMe: false,
|
||||
isEntitySubscribedByMe: null,
|
||||
authorPlaceInRating: null,
|
||||
),
|
||||
);
|
||||
|
||||
when(mockRecipeRepository.getRecipe('1')).thenAnswer((_) async => testRecipe);
|
||||
when(mockRecipeRepository.addToFavorite('1')).thenThrow(Exception('Ошибка'));
|
||||
|
||||
await aboutRecipeCubit!.getRecipe('1');
|
||||
await aboutRecipeCubit!.addToFavorite('1', 0);
|
||||
|
||||
expect(aboutRecipeCubit!.state, isA<AboutRecipeStateLoaded>());
|
||||
final loadedState = aboutRecipeCubit!.state as AboutRecipeStateLoaded;
|
||||
expect(loadedState.recipe.isFavorite, true);
|
||||
|
||||
// Не ждем debounce, так как showErrorToast требует плагин
|
||||
// Просто проверяем, что состояние изменилось сразу
|
||||
verify(mockRecipeRepository.emitFavoriteStateToFeed(any)).called(1);
|
||||
});
|
||||
|
||||
test('removeFromFavorite - с recipeIndex параметром', () async {
|
||||
aboutRecipeCubit = AboutRecipeCubit(recipeRepository: mockRecipeRepository, profileRepository: mockProfileRepository);
|
||||
|
||||
const testRecipe = Recipe(
|
||||
id: 1,
|
||||
image: 'https://example.com/image.jpg',
|
||||
state: 'active',
|
||||
cookingTime: 30,
|
||||
activeCookingTime: 15,
|
||||
ingredients: [],
|
||||
description: 'Test description',
|
||||
steps: [],
|
||||
videoUrl: null,
|
||||
createdAt: null,
|
||||
updatedAt: null,
|
||||
title: 'Test Recipe',
|
||||
type: 'main',
|
||||
slug: 'test-recipe',
|
||||
commentsCount: 5,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: true,
|
||||
calories: 300.0,
|
||||
servings: 4,
|
||||
likesCount: 10,
|
||||
viewsCount: 100,
|
||||
tags: [],
|
||||
author: Author(
|
||||
authorSlug: 'author',
|
||||
authorName: 'Author Name',
|
||||
authorProfileIcon: 'https://example.com/icon.jpg',
|
||||
authorIsMe: false,
|
||||
isEntitySubscribedByMe: null,
|
||||
authorPlaceInRating: null,
|
||||
),
|
||||
);
|
||||
|
||||
when(mockRecipeRepository.getRecipe('1')).thenAnswer((_) async => testRecipe);
|
||||
when(mockRecipeRepository.removeFromFavorite('1')).thenAnswer((_) async => {});
|
||||
|
||||
await aboutRecipeCubit!.getRecipe('1');
|
||||
await aboutRecipeCubit!.removeFromFavorite('1', 0);
|
||||
|
||||
expect(aboutRecipeCubit!.state, isA<AboutRecipeStateLoaded>());
|
||||
final loadedState = aboutRecipeCubit!.state as AboutRecipeStateLoaded;
|
||||
expect(loadedState.recipe.isFavorite, false);
|
||||
verify(mockRecipeRepository.emitFavoriteStateToFeed(any)).called(1);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 1200));
|
||||
verify(mockRecipeRepository.removeFromFavorite('1')).called(1);
|
||||
});
|
||||
|
||||
test('removeFromFavorite - обработка ошибки', () async {
|
||||
aboutRecipeCubit = AboutRecipeCubit(recipeRepository: mockRecipeRepository, profileRepository: mockProfileRepository);
|
||||
|
||||
const testRecipe = Recipe(
|
||||
id: 1,
|
||||
image: 'https://example.com/image.jpg',
|
||||
state: 'active',
|
||||
cookingTime: 30,
|
||||
activeCookingTime: 15,
|
||||
ingredients: [],
|
||||
description: 'Test description',
|
||||
steps: [],
|
||||
videoUrl: null,
|
||||
createdAt: null,
|
||||
updatedAt: null,
|
||||
title: 'Test Recipe',
|
||||
type: 'main',
|
||||
slug: 'test-recipe',
|
||||
commentsCount: 5,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: true,
|
||||
calories: 300.0,
|
||||
servings: 4,
|
||||
likesCount: 10,
|
||||
viewsCount: 100,
|
||||
tags: [],
|
||||
author: Author(
|
||||
authorSlug: 'author',
|
||||
authorName: 'Author Name',
|
||||
authorProfileIcon: 'https://example.com/icon.jpg',
|
||||
authorIsMe: false,
|
||||
isEntitySubscribedByMe: null,
|
||||
authorPlaceInRating: null,
|
||||
),
|
||||
);
|
||||
|
||||
when(mockRecipeRepository.getRecipe('1')).thenAnswer((_) async => testRecipe);
|
||||
when(mockRecipeRepository.removeFromFavorite('1')).thenThrow(Exception('Ошибка'));
|
||||
|
||||
await aboutRecipeCubit!.getRecipe('1');
|
||||
await aboutRecipeCubit!.removeFromFavorite('1', 0);
|
||||
|
||||
expect(aboutRecipeCubit!.state, isA<AboutRecipeStateLoaded>());
|
||||
final loadedState = aboutRecipeCubit!.state as AboutRecipeStateLoaded;
|
||||
expect(loadedState.recipe.isFavorite, false);
|
||||
|
||||
// Не ждем debounce, так как showErrorToast требует плагин
|
||||
// Просто проверяем, что состояние изменилось сразу
|
||||
verify(mockRecipeRepository.emitFavoriteStateToFeed(any)).called(1);
|
||||
});
|
||||
|
||||
test('likeRecipe - не выполняет действие если state не loaded', () async {
|
||||
aboutRecipeCubit = AboutRecipeCubit(recipeRepository: mockRecipeRepository, profileRepository: mockProfileRepository);
|
||||
|
||||
await aboutRecipeCubit!.likeRecipe('1', null);
|
||||
|
||||
expect(aboutRecipeCubit!.state, isA<AboutRecipeState>());
|
||||
verifyNever(mockRecipeRepository.likeRecipe(any));
|
||||
});
|
||||
|
||||
test('addToFavorite - не выполняет действие если state не loaded', () async {
|
||||
aboutRecipeCubit = AboutRecipeCubit(recipeRepository: mockRecipeRepository, profileRepository: mockProfileRepository);
|
||||
|
||||
await aboutRecipeCubit!.addToFavorite('1', null);
|
||||
|
||||
expect(aboutRecipeCubit!.state, isA<AboutRecipeState>());
|
||||
verifyNever(mockRecipeRepository.addToFavorite(any));
|
||||
});
|
||||
|
||||
test('removeFromFavorite - не выполняет действие если state не loaded', () async {
|
||||
aboutRecipeCubit = AboutRecipeCubit(recipeRepository: mockRecipeRepository, profileRepository: mockProfileRepository);
|
||||
|
||||
await aboutRecipeCubit!.removeFromFavorite('1', null);
|
||||
|
||||
expect(aboutRecipeCubit!.state, isA<AboutRecipeState>());
|
||||
verifyNever(mockRecipeRepository.removeFromFavorite(any));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user