diff --git a/test/features/feed/services/feed_service_test.dart b/test/features/feed/services/feed_service_test.dart new file mode 100644 index 00000000..e8832ec5 --- /dev/null +++ b/test/features/feed/services/feed_service_test.dart @@ -0,0 +1,378 @@ +import 'package:eatvio_app/core/models/pagination_model.dart'; +import 'package:eatvio_app/features/feed/models/comment_model.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/models/feed_blog_post_settings_model.dart'; +import 'package:eatvio_app/features/feed/models/feed_consultant_model.dart'; +import 'package:eatvio_app/features/feed/models/plan_pagination_model.dart'; +import 'package:eatvio_app/features/feed/models/recipes_model.dart'; +import 'package:eatvio_app/features/feed/models/recipes_pagination_model.dart'; +import 'package:eatvio_app/features/feed/models/view_model.dart'; +import 'package:eatvio_app/features/feed/services/feed_service.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mockito/annotations.dart'; +import 'package:mockito/mockito.dart'; + +import 'feed_service_test.mocks.dart'; + +@GenerateNiceMocks([MockSpec()]) +void main() { + group('FeedService', () { + late MockFeedService mockFeedService; + + setUp(() { + mockFeedService = MockFeedService(); + }); + + test('getBlogPostList returns settings', () async { + const page = 1; + final expected = FeedBlogPostSettingsModel( + feedBlogPostList: [ + FeedBlogPostModel( + id: 1, + title: 'Post Title', + description: 'Test post description', + image: 'https://someurl.com/img.jpg', + state: 'published', + author: const Author(authorSlug: '', authorName: '', authorProfileIcon: '', authorIsMe: false), + videoUrl: 'https://someurl.com/video.mp4', + createdAt: DateTime.now(), + updatedAt: DateTime.now(), + totalLikes: 5, + totalViews: 10, + totalComments: 2, + wasLikedByMe: false, + ), + ], + meta: const Meta(currentPage: 1, lastPage: 1, total: 1, perPage: 10, from: null, links: [Link(url: null, label: null, active: null)], to: null), + ); + + when(mockFeedService.getBlogPostList(page: page, query: null)).thenAnswer((_) async => expected); + + final result = await mockFeedService.getBlogPostList(page: page, query: null); + + expect(result, isA()); + verify(mockFeedService.getBlogPostList(page: page, query: null)).called(1); + }); + + test('getBlogPost returns post', () async { + const id = 10; + final expected = FeedBlogPostModel( + id: id, + title: 'Test', + description: 'Test post description', + image: 'https://someurl.com/img.jpg', + state: 'published', + author: const Author(authorSlug: '', authorName: '', authorProfileIcon: '', authorIsMe: false), + videoUrl: 'https://someurl.com/video.mp4', + createdAt: DateTime.now(), + updatedAt: DateTime.now(), + totalLikes: 3, + totalViews: 14, + totalComments: 1, + wasLikedByMe: false, + ); + + when(mockFeedService.getBlogPost(postId: id)).thenAnswer((_) async => expected); + + final result = await mockFeedService.getBlogPost(postId: id); + + expect(result.id, id); + verify(mockFeedService.getBlogPost(postId: id)).called(1); + }); + + test('getRecipes returns recipes pagination', () async { + final expected = RecipesPagination( + recipesList: [ + Recipe( + id: 1, + image: 'https://someurl.com/img.jpg', + state: 'published', + cookingTime: 30, + activeCookingTime: 20, + ingredients: [const Ingredient(name: 'ingredient1', unit: 'unit1', portion: 'portion1', productId: 1)], + description: 'Test post description', + steps: [const Step(description: 'step1', image: 'https://someurl.com/img.jpg')], + videoUrl: 'https://someurl.com/video.mp4', + createdAt: DateTime.now(), + updatedAt: DateTime.now(), + title: 'Test', + type: 'recipe', + slug: 'test-recipe', + commentsCount: 1, + wasLikedByMe: false, + isFavorite: false, + calories: 100, + servings: 1, + likesCount: 3, + viewsCount: 14, + tags: [const Tag(name: '1')], + author: const Author(authorSlug: '', authorName: '', authorProfileIcon: '', authorIsMe: false), + ), + ], + ); + + when(mockFeedService.getRecipes(page: 1, tags: [1], query: null)).thenAnswer((_) async => expected); + + await mockFeedService.getRecipes(page: 1, tags: [1], query: null); + + verify(mockFeedService.getRecipes(page: 1, tags: [1], query: null)).called(1); + }); + + test('getDiets returns pagination', () async { + const expected = DietsPagination( + data: [ + Diet( + id: 1, + slug: 'test-diet', + name: 'Test Diet', + image: 'https://someurl.com/img.jpg', + duration: 30, + state: DietState.active, + type: DietType(light: false, veg: false, carb: false, meat: false), + details: 'Test diet description', + dailySchedule: {}, + author: Author(authorSlug: '', authorName: '', authorProfileIcon: '', authorIsMe: false), + totalLikes: 1, + totalViews: 1, + totalComments: 1, + wasLikedByMe: false, + isFavorite: false, + dailyNutrition: [], + ), + ], + links: Links(first: '', last: '', prev: null, next: null), + meta: Meta(currentPage: 1, lastPage: 1, total: 0, perPage: 10, from: null, links: [Link(url: null, label: null, active: null)], to: null), + ); + + when(mockFeedService.getDiets(page: 1, query: null)).thenAnswer((_) async => expected); + + await mockFeedService.getDiets(page: 1, query: null); + + verify(mockFeedService.getDiets(page: 1, query: null)).called(1); + }); + + test('getPlans returns pagination', () async { + const expected = PlanPaginationModel( + data: [ + PlanModel( + id: 1, + slug: 'test-plan', + name: 'Test Plan', + image: 'https://someurl.com/img.jpg', + duration: 30, + state: 'active', + type: PlanType(fit: false, slim: false, behavior: false, wellness: false), + details: '', + packetsCount: 1, + author: Author(authorSlug: '', authorName: '', authorProfileIcon: '', authorIsMe: false), + totalLikes: 1, + totalViews: 1, + totalComments: 1, + isFavorite: false, + minPriceOfOptions: 100, + maxPriceOfOptions: 500, + wasLikedByMe: false, + ), + ], + links: Links(first: '', last: '', prev: null, next: null), + meta: Meta(currentPage: 1, lastPage: 1, total: 0, perPage: 10, from: null, links: [Link(url: null, label: null, active: null)], to: null), + ); + + when(mockFeedService.getPlans(page: 1, query: null)).thenAnswer((_) async => expected); + + await mockFeedService.getPlans(page: 1, query: null); + + verify(mockFeedService.getPlans(page: 1, query: null)).called(1); + }); + + test('getBlogPostComments returns comments', () async { + const id = "1"; + final expected = CommentModel( + data: [ + Comment( + id: 1, + authorName: 'user1', + authorSlug: '', + authorProfileIcon: '', + body: 'Nice', + childrenComments: [ + Comment(id: 2, authorName: 'user2', authorSlug: '', authorProfileIcon: '', body: 'Great', childrenComments: [], createdAt: DateTime.now()), + ], + createdAt: DateTime.now(), + ), + ], + links: const Links(first: '', last: '', prev: null, next: null), + meta: const Meta(currentPage: 1, lastPage: 1, total: 1, perPage: 10, from: null, links: [Link(url: null, label: null, active: null)], to: null), + ); + + when(mockFeedService.getBlogPostComments(id: id)).thenAnswer((_) async => expected); + + await mockFeedService.getBlogPostComments(id: id); + + verify(mockFeedService.getBlogPostComments(id: id)).called(1); + }); + + test('sendBlogPostComment sends comment', () async { + when(mockFeedService.sendBlogPostComment(id: "1", body: "Great", parentCommentId: null)).thenAnswer((_) async => Future.value()); + + await mockFeedService.sendBlogPostComment(id: "1", body: "Great", parentCommentId: null); + + verify(mockFeedService.sendBlogPostComment(id: "1", body: "Great", parentCommentId: null)).called(1); + }); + + test('getDietsComments returns comments', () async { + const id = "5"; + final expected = CommentModel( + data: [Comment(id: 2, authorName: 'user2', authorSlug: '', authorProfileIcon: '', body: 'Cool diet!', childrenComments: [], createdAt: DateTime.now())], + links: const Links(first: '', last: '', prev: null, next: null), + meta: const Meta(currentPage: 1, lastPage: 1, total: 1, perPage: 10, from: null, links: [Link(url: null, label: null, active: null)], to: null), + ); + + when(mockFeedService.getDietsComments(id: id)).thenAnswer((_) async => expected); + + await mockFeedService.getDietsComments(id: id); + + verify(mockFeedService.getDietsComments(id: id)).called(1); + }); + + test('sendDietsComment sends comment', () async { + when(mockFeedService.sendDietsComment(id: "5", body: "Nice diet", parentCommentId: null)).thenAnswer((_) async => Future.value()); + + await mockFeedService.sendDietsComment(id: "5", body: "Nice diet", parentCommentId: null); + + verify(mockFeedService.sendDietsComment(id: "5", body: "Nice diet", parentCommentId: null)).called(1); + }); + + test('getPlansComments returns comments', () async { + const slug = "plan-1"; + final expected = CommentModel( + data: [ + Comment(id: 3, authorName: 'user3', authorSlug: '', authorProfileIcon: '', body: 'Super plan!', childrenComments: [], createdAt: DateTime.now()), + ], + links: const Links(first: '', last: '', prev: null, next: null), + meta: const Meta(currentPage: 1, lastPage: 1, total: 1, perPage: 10, from: null, links: [Link(url: null, label: null, active: null)], to: null), + ); + + when(mockFeedService.getPlansComments(slug: slug)).thenAnswer((_) async => expected); + + await mockFeedService.getPlansComments(slug: slug); + + verify(mockFeedService.getPlansComments(slug: slug)).called(1); + }); + + test('sendPlansComment sends comment', () async { + when(mockFeedService.sendPlansComment(slug: "plan-1", body: "Ok", parentCommentId: null)).thenAnswer((_) async => Future.value()); + + await mockFeedService.sendPlansComment(slug: "plan-1", body: "Ok", parentCommentId: null); + + verify(mockFeedService.sendPlansComment(slug: "plan-1", body: "Ok", parentCommentId: null)).called(1); + }); + + test('getRecipesComments returns comments', () async { + const id = "33"; + final expected = CommentModel( + data: [ + Comment(id: 4, authorName: 'user4', authorSlug: '', authorProfileIcon: '', body: 'Looks tasty!', childrenComments: [], createdAt: DateTime.now()), + ], + links: const Links(first: '', last: '', prev: null, next: null), + meta: const Meta(currentPage: 1, lastPage: 1, total: 1, perPage: 10, from: null, links: [Link(url: null, label: null, active: null)], to: null), + ); + + when(mockFeedService.getRecipesComments(id: id)).thenAnswer((_) async => expected); + + await mockFeedService.getRecipesComments(id: id); + + verify(mockFeedService.getRecipesComments(id: id)).called(1); + }); + + test('sendRecipesComment sends comment', () async { + when(mockFeedService.sendRecipesComment(id: "33", body: "Tasty", parentCommentId: null)).thenAnswer((_) async => Future.value()); + + await mockFeedService.sendRecipesComment(id: "33", body: "Tasty", parentCommentId: null); + + verify(mockFeedService.sendRecipesComment(id: "33", body: "Tasty", parentCommentId: null)).called(1); + }); + + test('likeBlogPost works', () async { + when(mockFeedService.likeBlogPost(id: 1)).thenAnswer((_) async => Future.value()); + + await mockFeedService.likeBlogPost(id: 1); + + verify(mockFeedService.likeBlogPost(id: 1)).called(1); + }); + + test('unlikedBlogPost works', () async { + when(mockFeedService.unlikedBlogPost(id: 1)).thenAnswer((_) async => Future.value()); + + await mockFeedService.unlikedBlogPost(id: 1); + + verify(mockFeedService.unlikedBlogPost(id: 1)).called(1); + }); + + test('getConsultants returns consultant pagination', () async { + const expected = FeedConsultantPaginationModel( + data: [ + FeedConsultantModel( + slug: 'consultant-1', + name: 'Anna Ivanova', + description: 'Test consultant description', + totalScores: 5, + photo: 'https://someurl.com/consultant1.jpg', + badges: [], + ), + ], + links: Links(first: '', last: '', prev: null, next: null), + meta: Meta(currentPage: 1, lastPage: 1, total: 1, perPage: 10, from: null, links: [Link(url: null, label: null, active: null)], to: null), + ); + + when(mockFeedService.getConsultants(name: 'Anna')).thenAnswer((_) async => expected); + + await mockFeedService.getConsultants(name: 'Anna'); + + verify(mockFeedService.getConsultants(name: 'Anna')).called(1); + }); + + test('viewPost works', () async { + when(mockFeedService.viewPost(id: 1)).thenAnswer((_) async => Future.value()); + + await mockFeedService.viewPost(id: 1); + + verify(mockFeedService.viewPost(id: 1)).called(1); + }); + + test('viewRecipe works', () async { + when(mockFeedService.viewRecipe(slug: 'abc')).thenAnswer((_) async => Future.value()); + + await mockFeedService.viewRecipe(slug: 'abc'); + + verify(mockFeedService.viewRecipe(slug: 'abc')).called(1); + }); + + test('viewDiet works', () async { + when(mockFeedService.viewDiet(id: 2)).thenAnswer((_) async => Future.value()); + + await mockFeedService.viewDiet(id: 2); + + verify(mockFeedService.viewDiet(id: 2)).called(1); + }); + + test('viewPlan works', () async { + when(mockFeedService.viewPlan(slug: 'plan-7')).thenAnswer((_) async => Future.value()); + + await mockFeedService.viewPlan(slug: 'plan-7'); + + verify(mockFeedService.viewPlan(slug: 'plan-7')).called(1); + }); + + test('viewContent sends view model', () async { + final view = ViewModel(type: 'recipe', slugs: ['recipe-1']); + + when(mockFeedService.viewContent(viewModel: view)).thenAnswer((_) async => Future.value()); + + await mockFeedService.viewContent(viewModel: view); + + verify(mockFeedService.viewContent(viewModel: view)).called(1); + }); + }); +}