forked from eatvio/eatvio_app
feat(tests): updated tests coverage to 66.5%
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import 'package:easy_debounce/easy_debounce.dart';
|
||||
import 'package:eatvio_app/core/models/pagination_model.dart';
|
||||
import 'package:eatvio_app/features/diets/models/diet_likes_model.dart';
|
||||
import 'package:eatvio_app/features/diets/repositories/diet_repository.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
import 'package:eatvio_app/features/feed/presentation/bloc/diets_cubit/diets_cubit.dart';
|
||||
@@ -172,6 +173,411 @@ void main() {
|
||||
expect(dietsCubit!.state.errorMessage, isNotNull);
|
||||
expect(dietsCubit!.state.isLoading, isFalse);
|
||||
});
|
||||
|
||||
test('loadNextPage - загружает следующую страницу', () async {
|
||||
dietsCubit = DietsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
dietsRepository: mockDietRepository,
|
||||
);
|
||||
|
||||
const testDiet1 = Diet(
|
||||
id: 1,
|
||||
slug: 'test-diet-1',
|
||||
name: 'Test Diet 1',
|
||||
image: 'https://example.com/image1.jpg',
|
||||
duration: 7,
|
||||
state: DietState.active,
|
||||
type: DietType(veg: true, light: false, carb: false, meat: false),
|
||||
details: 'Test details 1',
|
||||
dailySchedule: {},
|
||||
author: Author(authorSlug: 'author', authorName: 'Author Name', authorProfileIcon: 'https://example.com/icon.jpg', authorIsMe: false, isEntitySubscribedByMe: null, authorPlaceInRating: null),
|
||||
totalLikes: 10,
|
||||
totalViews: 100,
|
||||
totalComments: 5,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: false,
|
||||
dailyNutrition: [],
|
||||
);
|
||||
|
||||
const testDiet2 = Diet(
|
||||
id: 2,
|
||||
slug: 'test-diet-2',
|
||||
name: 'Test Diet 2',
|
||||
image: 'https://example.com/image2.jpg',
|
||||
duration: 7,
|
||||
state: DietState.active,
|
||||
type: DietType(veg: false, light: true, carb: false, meat: false),
|
||||
details: 'Test details 2',
|
||||
dailySchedule: {},
|
||||
author: Author(authorSlug: 'author', authorName: 'Author Name', authorProfileIcon: 'https://example.com/icon.jpg', authorIsMe: false, isEntitySubscribedByMe: null, authorPlaceInRating: null),
|
||||
totalLikes: 20,
|
||||
totalViews: 200,
|
||||
totalComments: 10,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: false,
|
||||
dailyNutrition: [],
|
||||
);
|
||||
|
||||
const firstPagePagination = DietsPagination(
|
||||
data: [testDiet1],
|
||||
links: Links(first: 'https://example.com?page=1', last: 'https://example.com?page=2', prev: null, next: 'https://example.com?page=2'),
|
||||
meta: Meta(currentPage: 1, from: 1, lastPage: 2, links: [], perPage: 10, to: 1, total: 2),
|
||||
);
|
||||
|
||||
const secondPagePagination = DietsPagination(
|
||||
data: [testDiet2],
|
||||
links: Links(first: 'https://example.com?page=1', last: 'https://example.com?page=2', prev: 'https://example.com?page=1', next: null),
|
||||
meta: Meta(currentPage: 2, from: 2, lastPage: 2, links: [], perPage: 10, to: 2, total: 2),
|
||||
);
|
||||
|
||||
when(mockFeedRepository.getDiets(
|
||||
query: anyNamed('query'),
|
||||
types: anyNamed('types'),
|
||||
duration: anyNamed('duration'),
|
||||
sorting: anyNamed('sorting'),
|
||||
)).thenAnswer((_) async => firstPagePagination);
|
||||
|
||||
await dietsCubit!.loadDiets();
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
when(mockFeedRepository.getDiets(
|
||||
page: 2,
|
||||
query: anyNamed('query'),
|
||||
types: anyNamed('types'),
|
||||
duration: anyNamed('duration'),
|
||||
sorting: anyNamed('sorting'),
|
||||
)).thenAnswer((_) async => secondPagePagination);
|
||||
|
||||
await dietsCubit!.loadNextPage();
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
|
||||
expect(dietsCubit!.state.dietsList.length, 2);
|
||||
expect(dietsCubit!.state.dietsList[0].id, 1);
|
||||
expect(dietsCubit!.state.dietsList[1].id, 2);
|
||||
});
|
||||
|
||||
test('loadNextPage - не загружает если уже загружается', () async {
|
||||
dietsCubit = DietsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
dietsRepository: mockDietRepository,
|
||||
);
|
||||
|
||||
const testDiet = Diet(
|
||||
id: 1,
|
||||
slug: 'test-diet',
|
||||
name: 'Test Diet',
|
||||
image: 'https://example.com/image.jpg',
|
||||
duration: 7,
|
||||
state: DietState.active,
|
||||
type: DietType(veg: true, light: false, carb: false, meat: false),
|
||||
details: 'Test details',
|
||||
dailySchedule: {},
|
||||
author: Author(authorSlug: 'author', authorName: 'Author Name', authorProfileIcon: 'https://example.com/icon.jpg', authorIsMe: false, isEntitySubscribedByMe: null, authorPlaceInRating: null),
|
||||
totalLikes: 10,
|
||||
totalViews: 100,
|
||||
totalComments: 5,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: false,
|
||||
dailyNutrition: [],
|
||||
);
|
||||
|
||||
const firstPagePagination = DietsPagination(
|
||||
data: [testDiet],
|
||||
links: Links(first: 'https://example.com?page=1', last: 'https://example.com?page=2', prev: null, next: 'https://example.com?page=2'),
|
||||
meta: Meta(currentPage: 1, from: 1, lastPage: 2, links: [], perPage: 10, to: 1, total: 2),
|
||||
);
|
||||
|
||||
when(mockFeedRepository.getDiets(
|
||||
query: anyNamed('query'),
|
||||
types: anyNamed('types'),
|
||||
duration: anyNamed('duration'),
|
||||
sorting: anyNamed('sorting'),
|
||||
)).thenAnswer((_) async => firstPagePagination);
|
||||
|
||||
await dietsCubit!.loadDiets();
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
when(mockFeedRepository.getDiets(
|
||||
page: 2,
|
||||
query: anyNamed('query'),
|
||||
types: anyNamed('types'),
|
||||
duration: anyNamed('duration'),
|
||||
sorting: anyNamed('sorting'),
|
||||
)).thenAnswer((_) async {
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
return firstPagePagination;
|
||||
});
|
||||
|
||||
final firstLoad = dietsCubit!.loadNextPage();
|
||||
await dietsCubit!.loadNextPage();
|
||||
await firstLoad;
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
verify(mockFeedRepository.getDiets(page: 2, query: anyNamed('query'), types: anyNamed('types'), duration: anyNamed('duration'), sorting: anyNamed('sorting'))).called(1);
|
||||
});
|
||||
|
||||
test('likeDiet - добавляет лайк', () async {
|
||||
dietsCubit = DietsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
dietsRepository: mockDietRepository,
|
||||
);
|
||||
|
||||
const testDiet = Diet(
|
||||
id: 1,
|
||||
slug: 'test-diet',
|
||||
name: 'Test Diet',
|
||||
image: 'https://example.com/image.jpg',
|
||||
duration: 7,
|
||||
state: DietState.active,
|
||||
type: DietType(veg: true, light: false, carb: false, meat: false),
|
||||
details: 'Test details',
|
||||
dailySchedule: {},
|
||||
author: Author(authorSlug: 'author', authorName: 'Author Name', authorProfileIcon: 'https://example.com/icon.jpg', authorIsMe: false, isEntitySubscribedByMe: null, authorPlaceInRating: null),
|
||||
totalLikes: 10,
|
||||
totalViews: 100,
|
||||
totalComments: 5,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: false,
|
||||
dailyNutrition: [],
|
||||
);
|
||||
|
||||
const dietsPagination = DietsPagination(
|
||||
data: [testDiet],
|
||||
links: Links(first: 'https://example.com?page=1', last: 'https://example.com?page=1', prev: null, next: null),
|
||||
meta: Meta(currentPage: 1, from: 1, lastPage: 1, links: [], perPage: 10, to: 1, total: 1),
|
||||
);
|
||||
|
||||
when(mockFeedRepository.getDiets(
|
||||
query: anyNamed('query'),
|
||||
types: anyNamed('types'),
|
||||
duration: anyNamed('duration'),
|
||||
sorting: anyNamed('sorting'),
|
||||
)).thenAnswer((_) async => dietsPagination);
|
||||
|
||||
when(mockDietRepository.likeDiet(1)).thenAnswer((_) async => const DietLikesModel(totalLikes: 11, isLiked: true));
|
||||
|
||||
await dietsCubit!.loadDiets();
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
await dietsCubit!.likeDiet(1, 0);
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
expect(dietsCubit!.state.dietsList[0].wasLikedByMe, true);
|
||||
expect(dietsCubit!.state.dietsList[0].totalLikes, 11);
|
||||
});
|
||||
|
||||
test('likeDiet - убирает лайк', () async {
|
||||
dietsCubit = DietsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
dietsRepository: mockDietRepository,
|
||||
);
|
||||
|
||||
const testDiet = Diet(
|
||||
id: 1,
|
||||
slug: 'test-diet',
|
||||
name: 'Test Diet',
|
||||
image: 'https://example.com/image.jpg',
|
||||
duration: 7,
|
||||
state: DietState.active,
|
||||
type: DietType(veg: true, light: false, carb: false, meat: false),
|
||||
details: 'Test details',
|
||||
dailySchedule: {},
|
||||
author: Author(authorSlug: 'author', authorName: 'Author Name', authorProfileIcon: 'https://example.com/icon.jpg', authorIsMe: false, isEntitySubscribedByMe: null, authorPlaceInRating: null),
|
||||
totalLikes: 10,
|
||||
totalViews: 100,
|
||||
totalComments: 5,
|
||||
wasLikedByMe: true,
|
||||
isFavorite: false,
|
||||
dailyNutrition: [],
|
||||
);
|
||||
|
||||
const dietsPagination = DietsPagination(
|
||||
data: [testDiet],
|
||||
links: Links(first: 'https://example.com?page=1', last: 'https://example.com?page=1', prev: null, next: null),
|
||||
meta: Meta(currentPage: 1, from: 1, lastPage: 1, links: [], perPage: 10, to: 1, total: 1),
|
||||
);
|
||||
|
||||
when(mockFeedRepository.getDiets(
|
||||
query: anyNamed('query'),
|
||||
types: anyNamed('types'),
|
||||
duration: anyNamed('duration'),
|
||||
sorting: anyNamed('sorting'),
|
||||
)).thenAnswer((_) async => dietsPagination);
|
||||
|
||||
when(mockDietRepository.likeDiet(1)).thenAnswer((_) async => const DietLikesModel(totalLikes: 9, isLiked: false));
|
||||
|
||||
await dietsCubit!.loadDiets();
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
await dietsCubit!.likeDiet(1, 0);
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
expect(dietsCubit!.state.dietsList[0].wasLikedByMe, false);
|
||||
expect(dietsCubit!.state.dietsList[0].totalLikes, 9);
|
||||
});
|
||||
|
||||
test('addDietToFavorite - добавляет диету в избранное', () async {
|
||||
dietsCubit = DietsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
dietsRepository: mockDietRepository,
|
||||
);
|
||||
|
||||
const testDiet = Diet(
|
||||
id: 1,
|
||||
slug: 'test-diet',
|
||||
name: 'Test Diet',
|
||||
image: 'https://example.com/image.jpg',
|
||||
duration: 7,
|
||||
state: DietState.active,
|
||||
type: DietType(veg: true, light: false, carb: false, meat: false),
|
||||
details: 'Test details',
|
||||
dailySchedule: {},
|
||||
author: Author(authorSlug: 'author', authorName: 'Author Name', authorProfileIcon: 'https://example.com/icon.jpg', authorIsMe: false, isEntitySubscribedByMe: null, authorPlaceInRating: null),
|
||||
totalLikes: 10,
|
||||
totalViews: 100,
|
||||
totalComments: 5,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: false,
|
||||
dailyNutrition: [],
|
||||
);
|
||||
|
||||
const dietsPagination = DietsPagination(
|
||||
data: [testDiet],
|
||||
links: Links(first: 'https://example.com?page=1', last: 'https://example.com?page=1', prev: null, next: null),
|
||||
meta: Meta(currentPage: 1, from: 1, lastPage: 1, links: [], perPage: 10, to: 1, total: 1),
|
||||
);
|
||||
|
||||
when(mockFeedRepository.getDiets(
|
||||
query: anyNamed('query'),
|
||||
types: anyNamed('types'),
|
||||
duration: anyNamed('duration'),
|
||||
sorting: anyNamed('sorting'),
|
||||
)).thenAnswer((_) async => dietsPagination);
|
||||
|
||||
when(mockDietRepository.addToFavorite(1)).thenAnswer((_) async => testDiet.copyWith(isFavorite: true));
|
||||
|
||||
await dietsCubit!.loadDiets();
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
await dietsCubit!.addDietToFavorite(1, 0);
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
|
||||
expect(dietsCubit!.state.dietsList[0].isFavorite, true);
|
||||
verify(mockDietRepository.addToFavorite(1)).called(1);
|
||||
});
|
||||
|
||||
test('removeDietFromFavorite - убирает диету из избранного', () async {
|
||||
dietsCubit = DietsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
dietsRepository: mockDietRepository,
|
||||
);
|
||||
|
||||
const testDiet = Diet(
|
||||
id: 1,
|
||||
slug: 'test-diet',
|
||||
name: 'Test Diet',
|
||||
image: 'https://example.com/image.jpg',
|
||||
duration: 7,
|
||||
state: DietState.active,
|
||||
type: DietType(veg: true, light: false, carb: false, meat: false),
|
||||
details: 'Test details',
|
||||
dailySchedule: {},
|
||||
author: Author(authorSlug: 'author', authorName: 'Author Name', authorProfileIcon: 'https://example.com/icon.jpg', authorIsMe: false, isEntitySubscribedByMe: null, authorPlaceInRating: null),
|
||||
totalLikes: 10,
|
||||
totalViews: 100,
|
||||
totalComments: 5,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: true,
|
||||
dailyNutrition: [],
|
||||
);
|
||||
|
||||
const dietsPagination = DietsPagination(
|
||||
data: [testDiet],
|
||||
links: Links(first: 'https://example.com?page=1', last: 'https://example.com?page=1', prev: null, next: null),
|
||||
meta: Meta(currentPage: 1, from: 1, lastPage: 1, links: [], perPage: 10, to: 1, total: 1),
|
||||
);
|
||||
|
||||
when(mockFeedRepository.getDiets(
|
||||
query: anyNamed('query'),
|
||||
types: anyNamed('types'),
|
||||
duration: anyNamed('duration'),
|
||||
sorting: anyNamed('sorting'),
|
||||
)).thenAnswer((_) async => dietsPagination);
|
||||
|
||||
when(mockDietRepository.removeFromFavorite(1)).thenAnswer((_) async => testDiet.copyWith(isFavorite: false));
|
||||
|
||||
await dietsCubit!.loadDiets();
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
await dietsCubit!.removeDietFromFavorite(1, 0);
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
expect(dietsCubit!.state.dietsList[0].isFavorite, false);
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
verify(mockDietRepository.removeFromFavorite(1)).called(1);
|
||||
});
|
||||
|
||||
test('deleteDiet - удаляет диету', () async {
|
||||
dietsCubit = DietsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
dietsRepository: mockDietRepository,
|
||||
);
|
||||
|
||||
const testDiet = Diet(
|
||||
id: 1,
|
||||
slug: 'test-diet',
|
||||
name: 'Test Diet',
|
||||
image: 'https://example.com/image.jpg',
|
||||
duration: 7,
|
||||
state: DietState.active,
|
||||
type: DietType(veg: true, light: false, carb: false, meat: false),
|
||||
details: 'Test details',
|
||||
dailySchedule: {},
|
||||
author: Author(authorSlug: 'author', authorName: 'Author Name', authorProfileIcon: 'https://example.com/icon.jpg', authorIsMe: false, isEntitySubscribedByMe: null, authorPlaceInRating: null),
|
||||
totalLikes: 10,
|
||||
totalViews: 100,
|
||||
totalComments: 5,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: false,
|
||||
dailyNutrition: [],
|
||||
);
|
||||
|
||||
const dietsPagination = DietsPagination(
|
||||
data: [testDiet],
|
||||
links: Links(first: 'https://example.com?page=1', last: 'https://example.com?page=1', prev: null, next: null),
|
||||
meta: Meta(currentPage: 1, from: 1, lastPage: 1, links: [], perPage: 10, to: 1, total: 1),
|
||||
);
|
||||
|
||||
when(mockFeedRepository.getDiets(
|
||||
query: anyNamed('query'),
|
||||
types: anyNamed('types'),
|
||||
duration: anyNamed('duration'),
|
||||
sorting: anyNamed('sorting'),
|
||||
)).thenAnswer((_) async => dietsPagination);
|
||||
|
||||
when(mockDietRepository.deleteDiet(1)).thenAnswer((_) async => {});
|
||||
|
||||
await dietsCubit!.loadDiets();
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
final result = await dietsCubit!.deleteDiet(1);
|
||||
|
||||
expect(result, true);
|
||||
verify(mockDietRepository.deleteDiet(1)).called(1);
|
||||
});
|
||||
|
||||
test('deleteDiet - возвращает false при ошибке', () async {
|
||||
dietsCubit = DietsCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
dietsRepository: mockDietRepository,
|
||||
);
|
||||
|
||||
when(mockDietRepository.deleteDiet(1)).thenThrow(Exception('Ошибка удаления'));
|
||||
|
||||
final result = await dietsCubit!.deleteDiet(1);
|
||||
|
||||
expect(result, false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -56,6 +56,57 @@ void main() {
|
||||
expect(state.dietsList.length, 1);
|
||||
expect(state.isLoading, isFalse);
|
||||
});
|
||||
|
||||
test('copyWith creates new instance with updated values', () {
|
||||
const original = DietsState(
|
||||
filterState: DietsFilterState(
|
||||
durationIndex: 0,
|
||||
sortingIndex: 0,
|
||||
typeIndex: 0,
|
||||
),
|
||||
dietsList: [],
|
||||
isLoading: true,
|
||||
errorMessage: null,
|
||||
);
|
||||
|
||||
final updated = original.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: 'Test error',
|
||||
);
|
||||
|
||||
expect(updated.isLoading, isFalse);
|
||||
expect(updated.errorMessage, 'Test error');
|
||||
expect(updated.dietsList, original.dietsList);
|
||||
expect(updated.filterState, original.filterState);
|
||||
});
|
||||
});
|
||||
|
||||
group('DietsFilterState', () {
|
||||
test('creates DietsFilterState with values', () {
|
||||
const state = DietsFilterState(
|
||||
sortingIndex: 1,
|
||||
durationIndex: 2,
|
||||
typeIndex: 3,
|
||||
);
|
||||
|
||||
expect(state.sortingIndex, 1);
|
||||
expect(state.durationIndex, 2);
|
||||
expect(state.typeIndex, 3);
|
||||
});
|
||||
|
||||
test('copyWith creates new instance with updated values', () {
|
||||
const original = DietsFilterState(
|
||||
sortingIndex: 0,
|
||||
durationIndex: 0,
|
||||
typeIndex: 0,
|
||||
);
|
||||
|
||||
final updated = original.copyWith(sortingIndex: 1);
|
||||
|
||||
expect(updated.sortingIndex, 1);
|
||||
expect(updated.durationIndex, original.durationIndex);
|
||||
expect(updated.typeIndex, original.typeIndex);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:easy_debounce/easy_debounce.dart';
|
||||
import 'package:eatvio_app/core/models/pagination_model.dart';
|
||||
import 'package:eatvio_app/features/diets/repositories/diet_repository.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
@@ -34,6 +35,9 @@ void main() {
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
EasyDebounce.cancel('loadPlans');
|
||||
EasyDebounce.cancel('like_plan');
|
||||
EasyDebounce.cancel('add_or_remove_plan_from_favorite');
|
||||
if (plansCubit != null && !plansCubit!.isClosed) {
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
await plansCubit!.close();
|
||||
@@ -153,6 +157,427 @@ void main() {
|
||||
expect(plansCubit!.state.plans.first.id, 1);
|
||||
expect(plansCubit!.state.errorMessage, isNull);
|
||||
});
|
||||
|
||||
test('loadPlans - обработка ошибки', () async {
|
||||
plansCubit = PlansCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
planRepository: mockPlanRepository,
|
||||
);
|
||||
|
||||
when(mockFeedRepository.getPlans(
|
||||
query: anyNamed('query'),
|
||||
types: anyNamed('types'),
|
||||
duration: anyNamed('duration'),
|
||||
minPrice: anyNamed('minPrice'),
|
||||
maxPrice: anyNamed('maxPrice'),
|
||||
)).thenThrow(Exception('Ошибка загрузки'));
|
||||
|
||||
await plansCubit!.loadPlans();
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
expect(plansCubit!.state.errorMessage, isNotNull);
|
||||
});
|
||||
|
||||
test('loadNextPage - загружает следующую страницу', () async {
|
||||
plansCubit = PlansCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
planRepository: mockPlanRepository,
|
||||
);
|
||||
|
||||
const testPlan1 = PlanModel(
|
||||
id: 1,
|
||||
slug: 'test-plan-1',
|
||||
name: 'Test Plan 1',
|
||||
image: 'https://example.com/image1.jpg',
|
||||
duration: 7,
|
||||
state: 'active',
|
||||
type: PlanType(fit: true, slim: false, behavior: false, wellness: false),
|
||||
details: 'Test details 1',
|
||||
packetsCount: 3,
|
||||
minPriceOfOptions: 1000.0,
|
||||
maxPriceOfOptions: 2000.0,
|
||||
author: Author(authorSlug: 'author', authorName: 'Author Name', authorProfileIcon: 'https://example.com/icon.jpg', authorIsMe: false, isEntitySubscribedByMe: null, authorPlaceInRating: null),
|
||||
totalLikes: 10,
|
||||
totalViews: 100,
|
||||
totalComments: 5,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: false,
|
||||
);
|
||||
|
||||
const testPlan2 = PlanModel(
|
||||
id: 2,
|
||||
slug: 'test-plan-2',
|
||||
name: 'Test Plan 2',
|
||||
image: 'https://example.com/image2.jpg',
|
||||
duration: 14,
|
||||
state: 'active',
|
||||
type: PlanType(fit: false, slim: true, behavior: false, wellness: false),
|
||||
details: 'Test details 2',
|
||||
packetsCount: 5,
|
||||
minPriceOfOptions: 2000.0,
|
||||
maxPriceOfOptions: 3000.0,
|
||||
author: Author(authorSlug: 'author', authorName: 'Author Name', authorProfileIcon: 'https://example.com/icon.jpg', authorIsMe: false, isEntitySubscribedByMe: null, authorPlaceInRating: null),
|
||||
totalLikes: 20,
|
||||
totalViews: 200,
|
||||
totalComments: 10,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: false,
|
||||
);
|
||||
|
||||
const firstPagePagination = PlanPaginationModel(
|
||||
data: [testPlan1],
|
||||
links: Links(first: 'https://example.com?page=1', last: 'https://example.com?page=2', prev: null, next: 'https://example.com?page=2'),
|
||||
meta: Meta(currentPage: 1, from: 1, lastPage: 2, links: [], perPage: 10, to: 1, total: 2, totalMinPrice: 1000, totalMaxPrice: 3000),
|
||||
);
|
||||
|
||||
const secondPagePagination = PlanPaginationModel(
|
||||
data: [testPlan2],
|
||||
links: Links(first: 'https://example.com?page=1', last: 'https://example.com?page=2', prev: 'https://example.com?page=1', next: null),
|
||||
meta: Meta(currentPage: 2, from: 2, lastPage: 2, links: [], perPage: 10, to: 2, total: 2, totalMinPrice: 1000, totalMaxPrice: 3000),
|
||||
);
|
||||
|
||||
when(mockFeedRepository.getPlans(
|
||||
query: anyNamed('query'),
|
||||
types: anyNamed('types'),
|
||||
duration: anyNamed('duration'),
|
||||
minPrice: anyNamed('minPrice'),
|
||||
maxPrice: anyNamed('maxPrice'),
|
||||
)).thenAnswer((_) async => firstPagePagination);
|
||||
|
||||
await plansCubit!.loadPlans();
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
when(mockFeedRepository.getPlans(
|
||||
page: 2,
|
||||
query: anyNamed('query'),
|
||||
)).thenAnswer((_) async => secondPagePagination);
|
||||
|
||||
await plansCubit!.loadNextPage();
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
|
||||
expect(plansCubit!.state.plans.length, 2);
|
||||
expect(plansCubit!.state.plans[0].id, 1);
|
||||
expect(plansCubit!.state.plans[1].id, 2);
|
||||
});
|
||||
|
||||
test('loadNextPage - не загружает если уже загружается', () async {
|
||||
plansCubit = PlansCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
planRepository: mockPlanRepository,
|
||||
);
|
||||
|
||||
const testPlan = PlanModel(
|
||||
id: 1,
|
||||
slug: 'test-plan',
|
||||
name: 'Test Plan',
|
||||
image: 'https://example.com/image.jpg',
|
||||
duration: 7,
|
||||
state: 'active',
|
||||
type: PlanType(fit: true, slim: false, behavior: false, wellness: false),
|
||||
details: 'Test details',
|
||||
packetsCount: 3,
|
||||
minPriceOfOptions: 1000.0,
|
||||
maxPriceOfOptions: 2000.0,
|
||||
author: Author(authorSlug: 'author', authorName: 'Author Name', authorProfileIcon: 'https://example.com/icon.jpg', authorIsMe: false, isEntitySubscribedByMe: null, authorPlaceInRating: null),
|
||||
totalLikes: 10,
|
||||
totalViews: 100,
|
||||
totalComments: 5,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: false,
|
||||
);
|
||||
|
||||
const firstPagePagination = PlanPaginationModel(
|
||||
data: [testPlan],
|
||||
links: Links(first: 'https://example.com?page=1', last: 'https://example.com?page=2', prev: null, next: 'https://example.com?page=2'),
|
||||
meta: Meta(currentPage: 1, from: 1, lastPage: 2, links: [], perPage: 10, to: 1, total: 2, totalMinPrice: 1000, totalMaxPrice: 2000),
|
||||
);
|
||||
|
||||
when(mockFeedRepository.getPlans(
|
||||
query: anyNamed('query'),
|
||||
types: anyNamed('types'),
|
||||
duration: anyNamed('duration'),
|
||||
minPrice: anyNamed('minPrice'),
|
||||
maxPrice: anyNamed('maxPrice'),
|
||||
)).thenAnswer((_) async => firstPagePagination);
|
||||
|
||||
when(mockFeedRepository.getPlans(
|
||||
page: 2,
|
||||
query: anyNamed('query'),
|
||||
)).thenAnswer((_) async {
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
return firstPagePagination;
|
||||
});
|
||||
|
||||
await plansCubit!.loadPlans();
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
final firstLoad = plansCubit!.loadNextPage();
|
||||
await plansCubit!.loadNextPage();
|
||||
await firstLoad;
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
verify(mockFeedRepository.getPlans(page: 2, query: anyNamed('query'))).called(1);
|
||||
});
|
||||
|
||||
test('addPlanToFavorite - добавляет план в избранное', () async {
|
||||
plansCubit = PlansCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
planRepository: mockPlanRepository,
|
||||
);
|
||||
|
||||
const testPlan = PlanModel(
|
||||
id: 1,
|
||||
slug: 'test-plan',
|
||||
name: 'Test Plan',
|
||||
image: 'https://example.com/image.jpg',
|
||||
duration: 7,
|
||||
state: 'active',
|
||||
type: PlanType(fit: true, slim: false, behavior: false, wellness: false),
|
||||
details: 'Test details',
|
||||
packetsCount: 3,
|
||||
minPriceOfOptions: 1000.0,
|
||||
maxPriceOfOptions: 2000.0,
|
||||
author: Author(authorSlug: 'author', authorName: 'Author Name', authorProfileIcon: 'https://example.com/icon.jpg', authorIsMe: false, isEntitySubscribedByMe: null, authorPlaceInRating: null),
|
||||
totalLikes: 10,
|
||||
totalViews: 100,
|
||||
totalComments: 5,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: false,
|
||||
);
|
||||
|
||||
const plansPagination = PlanPaginationModel(
|
||||
data: [testPlan],
|
||||
links: Links(first: 'https://example.com?page=1', last: 'https://example.com?page=1', prev: null, next: null),
|
||||
meta: Meta(currentPage: 1, from: 1, lastPage: 1, links: [], perPage: 10, to: 1, total: 1, totalMinPrice: 1000, totalMaxPrice: 2000),
|
||||
);
|
||||
|
||||
when(mockFeedRepository.getPlans(
|
||||
query: anyNamed('query'),
|
||||
types: anyNamed('types'),
|
||||
duration: anyNamed('duration'),
|
||||
minPrice: anyNamed('minPrice'),
|
||||
maxPrice: anyNamed('maxPrice'),
|
||||
)).thenAnswer((_) async => plansPagination);
|
||||
|
||||
when(mockPlanRepository.addToFavorite('test-plan')).thenAnswer((_) async => {});
|
||||
|
||||
await plansCubit!.loadPlans();
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
await plansCubit!.addPlanToFavorite('test-plan', 0);
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
expect(plansCubit!.state.plans[0].isFavorite, true);
|
||||
});
|
||||
|
||||
test('removePlanFromFavorite - убирает план из избранного', () async {
|
||||
plansCubit = PlansCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
planRepository: mockPlanRepository,
|
||||
);
|
||||
|
||||
const testPlan = PlanModel(
|
||||
id: 1,
|
||||
slug: 'test-plan',
|
||||
name: 'Test Plan',
|
||||
image: 'https://example.com/image.jpg',
|
||||
duration: 7,
|
||||
state: 'active',
|
||||
type: PlanType(fit: true, slim: false, behavior: false, wellness: false),
|
||||
details: 'Test details',
|
||||
packetsCount: 3,
|
||||
minPriceOfOptions: 1000.0,
|
||||
maxPriceOfOptions: 2000.0,
|
||||
author: Author(authorSlug: 'author', authorName: 'Author Name', authorProfileIcon: 'https://example.com/icon.jpg', authorIsMe: false, isEntitySubscribedByMe: null, authorPlaceInRating: null),
|
||||
totalLikes: 10,
|
||||
totalViews: 100,
|
||||
totalComments: 5,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: true,
|
||||
);
|
||||
|
||||
const plansPagination = PlanPaginationModel(
|
||||
data: [testPlan],
|
||||
links: Links(first: 'https://example.com?page=1', last: 'https://example.com?page=1', prev: null, next: null),
|
||||
meta: Meta(currentPage: 1, from: 1, lastPage: 1, links: [], perPage: 10, to: 1, total: 1, totalMinPrice: 1000, totalMaxPrice: 2000),
|
||||
);
|
||||
|
||||
when(mockFeedRepository.getPlans(
|
||||
query: anyNamed('query'),
|
||||
types: anyNamed('types'),
|
||||
duration: anyNamed('duration'),
|
||||
minPrice: anyNamed('minPrice'),
|
||||
maxPrice: anyNamed('maxPrice'),
|
||||
)).thenAnswer((_) async => plansPagination);
|
||||
|
||||
when(mockPlanRepository.removeFromFavorite('test-plan')).thenAnswer((_) async => {});
|
||||
|
||||
await plansCubit!.loadPlans();
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
await plansCubit!.removePlanFromFavorite('test-plan', 0);
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
expect(plansCubit!.state.plans[0].isFavorite, false);
|
||||
});
|
||||
|
||||
test('loadNextPage - обработка ошибки', () async {
|
||||
plansCubit = PlansCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
planRepository: mockPlanRepository,
|
||||
);
|
||||
|
||||
const testPlan = PlanModel(
|
||||
id: 1,
|
||||
slug: 'test-plan',
|
||||
name: 'Test Plan',
|
||||
image: 'https://example.com/image.jpg',
|
||||
duration: 7,
|
||||
state: 'active',
|
||||
type: PlanType(fit: true, slim: false, behavior: false, wellness: false),
|
||||
details: 'Test details',
|
||||
packetsCount: 3,
|
||||
minPriceOfOptions: 1000.0,
|
||||
maxPriceOfOptions: 2000.0,
|
||||
author: Author(authorSlug: 'author', authorName: 'Author Name', authorProfileIcon: 'https://example.com/icon.jpg', authorIsMe: false, isEntitySubscribedByMe: null, authorPlaceInRating: null),
|
||||
totalLikes: 10,
|
||||
totalViews: 100,
|
||||
totalComments: 5,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: false,
|
||||
);
|
||||
|
||||
const firstPagePagination = PlanPaginationModel(
|
||||
data: [testPlan],
|
||||
links: Links(first: 'https://example.com?page=1', last: 'https://example.com?page=2', prev: null, next: 'https://example.com?page=2'),
|
||||
meta: Meta(currentPage: 1, from: 1, lastPage: 2, links: [], perPage: 10, to: 1, total: 2, totalMinPrice: 1000, totalMaxPrice: 2000),
|
||||
);
|
||||
|
||||
when(mockFeedRepository.getPlans(
|
||||
query: anyNamed('query'),
|
||||
types: anyNamed('types'),
|
||||
duration: anyNamed('duration'),
|
||||
minPrice: anyNamed('minPrice'),
|
||||
maxPrice: anyNamed('maxPrice'),
|
||||
)).thenAnswer((_) async => firstPagePagination);
|
||||
|
||||
when(mockFeedRepository.getPlans(
|
||||
page: 2,
|
||||
query: anyNamed('query'),
|
||||
)).thenThrow(Exception('Ошибка загрузки'));
|
||||
|
||||
await plansCubit!.loadPlans();
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
await plansCubit!.loadNextPage();
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
expect(plansCubit!.state.errorMessage, isNotNull);
|
||||
});
|
||||
|
||||
test('likePlan - добавляет лайк', () async {
|
||||
plansCubit = PlansCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
planRepository: mockPlanRepository,
|
||||
);
|
||||
|
||||
const testPlan = PlanModel(
|
||||
id: 1,
|
||||
slug: 'test-plan',
|
||||
name: 'Test Plan',
|
||||
image: 'https://example.com/image.jpg',
|
||||
duration: 7,
|
||||
state: 'active',
|
||||
type: PlanType(fit: true, slim: false, behavior: false, wellness: false),
|
||||
details: 'Test details',
|
||||
packetsCount: 3,
|
||||
minPriceOfOptions: 1000.0,
|
||||
maxPriceOfOptions: 2000.0,
|
||||
author: Author(authorSlug: 'author', authorName: 'Author Name', authorProfileIcon: 'https://example.com/icon.jpg', authorIsMe: false, isEntitySubscribedByMe: null, authorPlaceInRating: null),
|
||||
totalLikes: 10,
|
||||
totalViews: 100,
|
||||
totalComments: 5,
|
||||
wasLikedByMe: false,
|
||||
isFavorite: false,
|
||||
);
|
||||
|
||||
const plansPagination = PlanPaginationModel(
|
||||
data: [testPlan],
|
||||
links: Links(first: 'https://example.com?page=1', last: 'https://example.com?page=1', prev: null, next: null),
|
||||
meta: Meta(currentPage: 1, from: 1, lastPage: 1, links: [], perPage: 10, to: 1, total: 1, totalMinPrice: 1000, totalMaxPrice: 2000),
|
||||
);
|
||||
|
||||
when(mockFeedRepository.getPlans(
|
||||
query: anyNamed('query'),
|
||||
types: anyNamed('types'),
|
||||
duration: anyNamed('duration'),
|
||||
minPrice: anyNamed('minPrice'),
|
||||
maxPrice: anyNamed('maxPrice'),
|
||||
)).thenAnswer((_) async => plansPagination);
|
||||
|
||||
when(mockPlanRepository.likePlan('test-plan')).thenAnswer((_) async => {});
|
||||
|
||||
await plansCubit!.loadPlans();
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
await plansCubit!.likePlan('test-plan', 0);
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
expect(plansCubit!.state.plans[0].wasLikedByMe, true);
|
||||
expect(plansCubit!.state.plans[0].totalLikes, 11);
|
||||
});
|
||||
|
||||
test('likePlan - убирает лайк', () async {
|
||||
plansCubit = PlansCubit(
|
||||
feedRepository: mockFeedRepository,
|
||||
planRepository: mockPlanRepository,
|
||||
);
|
||||
|
||||
const testPlan = PlanModel(
|
||||
id: 1,
|
||||
slug: 'test-plan',
|
||||
name: 'Test Plan',
|
||||
image: 'https://example.com/image.jpg',
|
||||
duration: 7,
|
||||
state: 'active',
|
||||
type: PlanType(fit: true, slim: false, behavior: false, wellness: false),
|
||||
details: 'Test details',
|
||||
packetsCount: 3,
|
||||
minPriceOfOptions: 1000.0,
|
||||
maxPriceOfOptions: 2000.0,
|
||||
author: Author(authorSlug: 'author', authorName: 'Author Name', authorProfileIcon: 'https://example.com/icon.jpg', authorIsMe: false, isEntitySubscribedByMe: null, authorPlaceInRating: null),
|
||||
totalLikes: 10,
|
||||
totalViews: 100,
|
||||
totalComments: 5,
|
||||
wasLikedByMe: true,
|
||||
isFavorite: false,
|
||||
);
|
||||
|
||||
const plansPagination = PlanPaginationModel(
|
||||
data: [testPlan],
|
||||
links: Links(first: 'https://example.com?page=1', last: 'https://example.com?page=1', prev: null, next: null),
|
||||
meta: Meta(currentPage: 1, from: 1, lastPage: 1, links: [], perPage: 10, to: 1, total: 1, totalMinPrice: 1000, totalMaxPrice: 2000),
|
||||
);
|
||||
|
||||
when(mockFeedRepository.getPlans(
|
||||
query: anyNamed('query'),
|
||||
types: anyNamed('types'),
|
||||
duration: anyNamed('duration'),
|
||||
minPrice: anyNamed('minPrice'),
|
||||
maxPrice: anyNamed('maxPrice'),
|
||||
)).thenAnswer((_) async => plansPagination);
|
||||
|
||||
when(mockPlanRepository.likePlan('test-plan')).thenAnswer((_) async => {});
|
||||
|
||||
await plansCubit!.loadPlans();
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
await plansCubit!.likePlan('test-plan', 0);
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
|
||||
expect(plansCubit!.state.plans[0].wasLikedByMe, false);
|
||||
expect(plansCubit!.state.plans[0].totalLikes, 9);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,59 @@ void main() {
|
||||
expect(state.plans.length, 1);
|
||||
expect(state.isLoading, isFalse);
|
||||
});
|
||||
|
||||
test('copyWith creates new instance with updated values', () {
|
||||
const original = PlansState(
|
||||
isLoading: true,
|
||||
plans: [],
|
||||
errorMessage: null,
|
||||
filterState: PlansFilterState(
|
||||
priceFilter: (null, null),
|
||||
durationIndex: 0,
|
||||
typeIndex: 0,
|
||||
),
|
||||
minPlanPrice: 0,
|
||||
maxPlanPrice: 0,
|
||||
);
|
||||
|
||||
final updated = original.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: 'Test error',
|
||||
);
|
||||
|
||||
expect(updated.isLoading, isFalse);
|
||||
expect(updated.errorMessage, 'Test error');
|
||||
expect(updated.plans, original.plans);
|
||||
expect(updated.filterState, original.filterState);
|
||||
});
|
||||
});
|
||||
|
||||
group('PlansFilterState', () {
|
||||
test('creates PlansFilterState with values', () {
|
||||
const state = PlansFilterState(
|
||||
priceFilter: (1000, 2000),
|
||||
durationIndex: 1,
|
||||
typeIndex: 2,
|
||||
);
|
||||
|
||||
expect(state.priceFilter.$1, 1000);
|
||||
expect(state.priceFilter.$2, 2000);
|
||||
expect(state.durationIndex, 1);
|
||||
expect(state.typeIndex, 2);
|
||||
});
|
||||
|
||||
test('copyWith creates new instance with updated values', () {
|
||||
const original = PlansFilterState(
|
||||
priceFilter: (null, null),
|
||||
durationIndex: 0,
|
||||
typeIndex: 0,
|
||||
);
|
||||
|
||||
final updated = original.copyWith(durationIndex: 1);
|
||||
|
||||
expect(updated.durationIndex, 1);
|
||||
expect(updated.typeIndex, original.typeIndex);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:easy_debounce/easy_debounce.dart';
|
||||
import 'package:eatvio_app/features/create_recipe/models/recipe_tag_model.dart';
|
||||
import 'package:eatvio_app/features/diets/repositories/diet_repository.dart';
|
||||
import 'package:eatvio_app/features/feed/models/diets_pagination_model.dart';
|
||||
@@ -35,6 +36,8 @@ void main() {
|
||||
});
|
||||
|
||||
tearDown(() async {
|
||||
EasyDebounce.cancel('add_or_remove_plan_from_favorite');
|
||||
EasyDebounce.cancel('like_plan');
|
||||
if (recipesCubit != null && !recipesCubit!.isClosed) {
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
await recipesCubit!.close();
|
||||
@@ -438,5 +441,111 @@ void main() {
|
||||
|
||||
expect(result, false);
|
||||
});
|
||||
|
||||
test('loadRecipesList - обработка ошибки', () async {
|
||||
recipesCubit = RecipesCubit(feedRepository: mockFeedRepository, recipeRepository: mockRecipeRepository, aboutRecipeRepository: mockAboutRecipeRepository);
|
||||
|
||||
when(mockFeedRepository.getRecipes(tags: anyNamed('tags'), query: anyNamed('query'))).thenThrow(Exception('Ошибка загрузки'));
|
||||
|
||||
await recipesCubit!.loadRecipesList();
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
expect(recipesCubit!.state.errorMessage, isNotNull);
|
||||
expect(recipesCubit!.state.isLoading, false);
|
||||
});
|
||||
|
||||
test('loadNextPage - обработка ошибки', () async {
|
||||
recipesCubit = RecipesCubit(feedRepository: mockFeedRepository, recipeRepository: mockRecipeRepository, aboutRecipeRepository: mockAboutRecipeRepository);
|
||||
|
||||
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),
|
||||
);
|
||||
|
||||
final testTags = [RecipeTag(id: 1, name: 'Tag 1', recipesCount: 10, createdAt: DateTime(2024, 1, 1), updatedAt: DateTime(2024, 1, 2))];
|
||||
|
||||
when(mockFeedRepository.getRecipes(tags: anyNamed('tags'), query: anyNamed('query'))).thenAnswer((_) async => [testRecipe]);
|
||||
when(mockRecipeRepository.getRecipesTags()).thenAnswer((_) async => testTags);
|
||||
|
||||
await recipesCubit!.loadRecipesList();
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
recipesCubit!.lastPage = 2;
|
||||
when(mockFeedRepository.getRecipes(page: 2, tags: anyNamed('tags'), query: anyNamed('query'))).thenThrow(Exception('Ошибка загрузки'));
|
||||
|
||||
await recipesCubit!.loadNextPage();
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
expect(recipesCubit!.state.errorMessage, isNotNull);
|
||||
expect(recipesCubit!.state.isLoading, false);
|
||||
});
|
||||
|
||||
test('likeRecipe - убирает лайк', () async {
|
||||
recipesCubit = RecipesCubit(feedRepository: mockFeedRepository, recipeRepository: mockRecipeRepository, aboutRecipeRepository: mockAboutRecipeRepository);
|
||||
|
||||
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: true,
|
||||
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),
|
||||
);
|
||||
|
||||
final testTags = [RecipeTag(id: 1, name: 'Tag 1', recipesCount: 10, createdAt: DateTime(2024, 1, 1), updatedAt: DateTime(2024, 1, 2))];
|
||||
|
||||
when(mockFeedRepository.getRecipes(tags: anyNamed('tags'), query: anyNamed('query'))).thenAnswer((_) async => [testRecipe]);
|
||||
when(mockRecipeRepository.getRecipesTags()).thenAnswer((_) async => testTags);
|
||||
when(mockAboutRecipeRepository.likeRecipe('test-recipe')).thenAnswer((_) async => Future<void>.value());
|
||||
|
||||
await recipesCubit!.loadRecipesList();
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
|
||||
await recipesCubit!.likeRecipe('test-recipe', 0);
|
||||
|
||||
expect(recipesCubit!.state.recipesList[0].wasLikedByMe, false);
|
||||
expect(recipesCubit!.state.recipesList[0].likesCount, 9);
|
||||
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
verify(mockAboutRecipeRepository.likeRecipe('test-recipe')).called(1);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -72,6 +72,27 @@ void main() {
|
||||
expect(state.recipesTags.length, 1);
|
||||
expect(state.selectedTags.length, 1);
|
||||
});
|
||||
|
||||
test('copyWith creates new instance with updated values', () {
|
||||
const original = RecipesState(
|
||||
recipesList: [],
|
||||
recipesTags: [],
|
||||
selectedTags: {},
|
||||
selectedTagsCounter: 0,
|
||||
isLoading: true,
|
||||
errorMessage: null,
|
||||
);
|
||||
|
||||
final updated = original.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: 'Test error',
|
||||
);
|
||||
|
||||
expect(updated.isLoading, isFalse);
|
||||
expect(updated.errorMessage, 'Test error');
|
||||
expect(updated.recipesList, original.recipesList);
|
||||
expect(updated.recipesTags, original.recipesTags);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user