feat(tests): tests coverage 67.2

This commit is contained in:
misha
2026-01-19 12:32:11 +03:00
parent 13ccf56df0
commit 44ede73ceb
20 changed files with 5084 additions and 409 deletions

View File

@@ -19,6 +19,8 @@ import 'plans_cubit_test.mocks.dart';
MockSpec<PlanRepository>(),
])
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('PlansCubit', () {
PlansCubit? plansCubit;
late MockFeedRepository mockFeedRepository;
@@ -578,6 +580,220 @@ void main() {
expect(plansCubit!.state.plans[0].wasLikedByMe, false);
expect(plansCubit!.state.plans[0].totalLikes, 9);
});
test('changePriceFilter - с disableDebounce = true', () 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);
plansCubit!.changePriceFilter(100, 500, disableDebounce: true);
await Future.delayed(const Duration(milliseconds: 200));
expect(plansCubit!.state.filterState.priceFilter, (100, 500));
verify(mockFeedRepository.getPlans(
query: anyNamed('query'),
types: anyNamed('types'),
duration: anyNamed('duration'),
minPrice: anyNamed('minPrice'),
maxPrice: anyNamed('maxPrice'),
)).called(1);
});
// Тесты для stream обновлений сложны для unit-тестирования, так как требуют пересоздания cubit
// Эти методы тестируются через интеграционные тесты или через прямой вызов методов
// Тесты для обработки ошибок в addPlanToFavorite и removePlanFromFavorite
// требуют Flutter binding для showErrorToast, поэтому пропускаем их в unit-тестах
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')).thenThrow(Exception('Ошибка'));
await plansCubit!.loadPlans();
await Future.delayed(const Duration(milliseconds: 200));
await plansCubit!.likePlan('test-plan', 0);
await Future.delayed(const Duration(milliseconds: 400));
// После ошибки состояние должно вернуться к исходному
expect(plansCubit!.state.plans[0].wasLikedByMe, false);
expect(plansCubit!.state.plans[0].totalLikes, 10);
});
test('loadNextPage - не загружает если lastPage == currentPage', () 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);
await plansCubit!.loadPlans();
await Future.delayed(const Duration(milliseconds: 200));
await plansCubit!.loadNextPage();
await Future.delayed(const Duration(milliseconds: 200));
// Не должно вызывать getPlans для страницы 2
verifyNever(mockFeedRepository.getPlans(page: 2, query: anyNamed('query')));
});
test('loadPlans - загружает планы с query', () 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);
await plansCubit!.loadPlans(query: 'test');
await Future.delayed(const Duration(milliseconds: 200));
verify(mockFeedRepository.getPlans(
query: 'test',
types: anyNamed('types'),
duration: anyNamed('duration'),
minPrice: anyNamed('minPrice'),
maxPrice: anyNamed('maxPrice'),
)).called(1);
});
});
}