From b9a58a963a63f870474e3d374ea3c0b7150b2531 Mon Sep 17 00:00:00 2001 From: cuqmbr Date: Sun, 15 Oct 2023 13:22:06 +0300 Subject: [PATCH] add ability to view products in wishlist --- .../Queries/WishlistsQuery.cs | 5 + .../IRepositories/IProductsRepository.cs | 5 + .../IServices/IWishlistService.cs | 2 + .../MappingProfiles/ProductProfile.cs | 15 ++ .../Models/CreateDtos/ProductCreateDto.cs | 18 +++ .../Models/Dtos/MessageDto.cs | 2 +- .../Models/Dtos/ProductDto.cs | 20 +++ .../Models/Dtos/WishlistDto.cs | 2 +- .../Entities/Message.cs | 2 +- .../Entities/Product.cs | 21 +++ .../Services/WishlistsService.cs | 26 +++- .../PersistanceExtentions/DbInitialaizer.cs | 54 ++++++- .../RepositoriesExtention.cs | 1 + .../Repositories/ProductRepository.cs | 10 ++ .../Tests/WishlistsTests.cs | 145 +++++++++++++++++- 15 files changed, 321 insertions(+), 7 deletions(-) create mode 100644 ShoppingAssistantApi.Application/IRepositories/IProductsRepository.cs create mode 100644 ShoppingAssistantApi.Application/MappingProfiles/ProductProfile.cs create mode 100644 ShoppingAssistantApi.Application/Models/CreateDtos/ProductCreateDto.cs create mode 100644 ShoppingAssistantApi.Application/Models/Dtos/ProductDto.cs create mode 100644 ShoppingAssistantApi.Domain/Entities/Product.cs create mode 100644 ShoppingAssistantApi.Persistance/Repositories/ProductRepository.cs diff --git a/ShoppingAssistantApi.Api/Queries/WishlistsQuery.cs b/ShoppingAssistantApi.Api/Queries/WishlistsQuery.cs index 49a229f..086be2e 100644 --- a/ShoppingAssistantApi.Api/Queries/WishlistsQuery.cs +++ b/ShoppingAssistantApi.Api/Queries/WishlistsQuery.cs @@ -22,4 +22,9 @@ public class WishlistsQuery public Task> GetMessagesPageFromPersonalWishlistAsync(string wishlistId, int pageNumber, int pageSize, CancellationToken cancellationToken, [Service] IWishlistsService wishlistsService) => wishlistsService.GetMessagesPageFromPersonalWishlistAsync(wishlistId, pageNumber, pageSize, cancellationToken); + + [Authorize] + public Task> GetProductsPageFromPersonalWishlistAsync(string wishlistId, int pageNumber, int pageSize, + CancellationToken cancellationToken, [Service] IWishlistsService wishlistsService) + => wishlistsService.GetProductsPageFromPersonalWishlistAsync(wishlistId, pageNumber, pageSize, cancellationToken); } diff --git a/ShoppingAssistantApi.Application/IRepositories/IProductsRepository.cs b/ShoppingAssistantApi.Application/IRepositories/IProductsRepository.cs new file mode 100644 index 0000000..d5c6c02 --- /dev/null +++ b/ShoppingAssistantApi.Application/IRepositories/IProductsRepository.cs @@ -0,0 +1,5 @@ +using ShoppingAssistantApi.Domain.Entities; + +namespace ShoppingAssistantApi.Application.IRepositories; + +public interface IProductsRepository : IBaseRepository { } diff --git a/ShoppingAssistantApi.Application/IServices/IWishlistService.cs b/ShoppingAssistantApi.Application/IServices/IWishlistService.cs index c2cd5f3..b34e985 100644 --- a/ShoppingAssistantApi.Application/IServices/IWishlistService.cs +++ b/ShoppingAssistantApi.Application/IServices/IWishlistService.cs @@ -16,5 +16,7 @@ public interface IWishlistsService Task> GetMessagesPageFromPersonalWishlistAsync(string wishlistId, int pageNumber, int pageSize, CancellationToken cancellationToken); + Task> GetProductsPageFromPersonalWishlistAsync(string wishlistId, int pageNumber, int pageSize, CancellationToken cancellationToken); + Task DeletePersonalWishlistAsync(string wishlistId, CancellationToken cancellationToken); } diff --git a/ShoppingAssistantApi.Application/MappingProfiles/ProductProfile.cs b/ShoppingAssistantApi.Application/MappingProfiles/ProductProfile.cs new file mode 100644 index 0000000..92ab66f --- /dev/null +++ b/ShoppingAssistantApi.Application/MappingProfiles/ProductProfile.cs @@ -0,0 +1,15 @@ +using AutoMapper; +using ShoppingAssistantApi.Application.Models.CreateDtos; +using ShoppingAssistantApi.Application.Models.Dtos; +using ShoppingAssistantApi.Domain.Entities; + +namespace ShoppingAssistantApi.Application.MappingProfiles; +public class ProductProfile : Profile +{ + public ProductProfile() + { + CreateMap().ReverseMap(); + + CreateMap().ReverseMap(); + } +} diff --git a/ShoppingAssistantApi.Application/Models/CreateDtos/ProductCreateDto.cs b/ShoppingAssistantApi.Application/Models/CreateDtos/ProductCreateDto.cs new file mode 100644 index 0000000..56687e1 --- /dev/null +++ b/ShoppingAssistantApi.Application/Models/CreateDtos/ProductCreateDto.cs @@ -0,0 +1,18 @@ +namespace ShoppingAssistantApi.Application.Models.CreateDtos; + +public class ProductCreateDto +{ + public required string Url { get; set; } + + public required string Name { get; set; } + + public required string Description { get; set; } + + public required double Rating { get; set; } + + public required string[] ImagesUrls { get; set; } + + public required bool WasOpened { get; set; } + + public required string WishlistId { get; set; } +} diff --git a/ShoppingAssistantApi.Application/Models/Dtos/MessageDto.cs b/ShoppingAssistantApi.Application/Models/Dtos/MessageDto.cs index a33c92e..9225d00 100644 --- a/ShoppingAssistantApi.Application/Models/Dtos/MessageDto.cs +++ b/ShoppingAssistantApi.Application/Models/Dtos/MessageDto.cs @@ -8,5 +8,5 @@ public class MessageDto public required string Role { get; set; } - public string? CreatedById { get; set; } = null; + public required string CreatedById { get; set; } } diff --git a/ShoppingAssistantApi.Application/Models/Dtos/ProductDto.cs b/ShoppingAssistantApi.Application/Models/Dtos/ProductDto.cs new file mode 100644 index 0000000..1697cd6 --- /dev/null +++ b/ShoppingAssistantApi.Application/Models/Dtos/ProductDto.cs @@ -0,0 +1,20 @@ +namespace ShoppingAssistantApi.Application.Models.Dtos; + +public class ProductDto +{ + public required string Id { get; set; } + + public required string Url { get; set; } + + public required string Name { get; set; } + + public required string Description { get; set; } + + public required double Rating { get; set; } + + public required string[] ImagesUrls { get; set; } + + public required bool WasOpened { get; set; } + + public required string WishlistId { get; set; } +} diff --git a/ShoppingAssistantApi.Application/Models/Dtos/WishlistDto.cs b/ShoppingAssistantApi.Application/Models/Dtos/WishlistDto.cs index 9398c26..cbb2cf6 100644 --- a/ShoppingAssistantApi.Application/Models/Dtos/WishlistDto.cs +++ b/ShoppingAssistantApi.Application/Models/Dtos/WishlistDto.cs @@ -8,5 +8,5 @@ public class WishlistDto public required string Type { get; set; } - public string CreatedById { get; set; } = null!; + public required string CreatedById { get; set; } } diff --git a/ShoppingAssistantApi.Domain/Entities/Message.cs b/ShoppingAssistantApi.Domain/Entities/Message.cs index 8a50457..77f4004 100644 --- a/ShoppingAssistantApi.Domain/Entities/Message.cs +++ b/ShoppingAssistantApi.Domain/Entities/Message.cs @@ -9,5 +9,5 @@ public class Message : EntityBase public required string Role { get; set; } - public ObjectId WishlistId { get; set; } + public required ObjectId WishlistId { get; set; } } diff --git a/ShoppingAssistantApi.Domain/Entities/Product.cs b/ShoppingAssistantApi.Domain/Entities/Product.cs new file mode 100644 index 0000000..40fbf90 --- /dev/null +++ b/ShoppingAssistantApi.Domain/Entities/Product.cs @@ -0,0 +1,21 @@ +using MongoDB.Bson; +using ShoppingAssistantApi.Domain.Common; + +namespace ShoppingAssistantApi.Domain.Entities; + +public class Product : EntityBase +{ + public required string Url { get; set; } + + public required string Name { get; set; } + + public required string Description { get; set; } + + public required double Rating { get; set; } + + public required string[] ImagesUrls { get; set; } + + public required bool WasOpened { get; set; } + + public required ObjectId WishlistId { get; set; } +} diff --git a/ShoppingAssistantApi.Infrastructure/Services/WishlistsService.cs b/ShoppingAssistantApi.Infrastructure/Services/WishlistsService.cs index 99cbad7..1a91f55 100644 --- a/ShoppingAssistantApi.Infrastructure/Services/WishlistsService.cs +++ b/ShoppingAssistantApi.Infrastructure/Services/WishlistsService.cs @@ -18,12 +18,15 @@ public class WishlistsService : IWishlistsService private readonly IMessagesRepository _messagesRepository; + private readonly IProductsRepository _productRepository; + private readonly IMapper _mapper; - public WishlistsService(IWishlistsRepository wishlistRepository, IMessagesRepository messageRepository, IMapper mapper) + public WishlistsService(IWishlistsRepository wishlistRepository, IMessagesRepository messageRepository, IProductsRepository productRepository, IMapper mapper) { _wishlistsRepository = wishlistRepository; _messagesRepository = messageRepository; + _productRepository = productRepository; _mapper = mapper; } @@ -113,6 +116,27 @@ public class WishlistsService : IWishlistsService return new PagedList(dtos, pageNumber, pageSize, count); } + public async Task> GetProductsPageFromPersonalWishlistAsync(string wishlistId, int pageNumber, int pageSize, CancellationToken cancellationToken) + { + if (!ObjectId.TryParse(wishlistId, out var wishlistObjectId)) + { + throw new InvalidDataException("Provided id is invalid."); + } + + await TryGetPersonalWishlist(wishlistObjectId, cancellationToken); + + var entities = await _productRepository.GetPageAsync(pageNumber, pageSize, x => x.WishlistId == wishlistObjectId, cancellationToken); + + foreach (var e in entities) + { + Console.WriteLine(e.Name); + } + + var dtos = _mapper.Map>(entities); + var count = await _productRepository.GetCountAsync(x => x.WishlistId == wishlistObjectId, cancellationToken); + return new PagedList(dtos, pageNumber, pageSize, count); + } + public async Task DeletePersonalWishlistAsync(string wishlistId, CancellationToken cancellationToken) { if (!ObjectId.TryParse(wishlistId, out var wishlistObjectId)) diff --git a/ShoppingAssistantApi.Persistance/PersistanceExtentions/DbInitialaizer.cs b/ShoppingAssistantApi.Persistance/PersistanceExtentions/DbInitialaizer.cs index 2d3af82..6233c86 100644 --- a/ShoppingAssistantApi.Persistance/PersistanceExtentions/DbInitialaizer.cs +++ b/ShoppingAssistantApi.Persistance/PersistanceExtentions/DbInitialaizer.cs @@ -29,6 +29,8 @@ public class DbInitialaizer private readonly IMongoCollection _messageCollection; + private readonly IMongoCollection _productCollection; + public IEnumerable Roles { get; set; } public DbInitialaizer(IServiceProvider serviceProvider) @@ -40,13 +42,14 @@ public class DbInitialaizer _userCollection = serviceProvider.GetService().Db.GetCollection("Users"); _wishlistCollection = serviceProvider.GetService().Db.GetCollection("Wishlists"); _messageCollection = serviceProvider.GetService().Db.GetCollection("Messages"); + _productCollection = serviceProvider.GetService().Db.GetCollection("Products"); } public async Task InitialaizeDb(CancellationToken cancellationToken) { await AddRoles(cancellationToken); await AddUsers(cancellationToken); - await AddWishlistsWithMessages(cancellationToken); + await AddWishlistsWithMessagesAndProducts(cancellationToken); } public async Task AddUsers(CancellationToken cancellationToken) @@ -170,7 +173,7 @@ public class DbInitialaizer var dto3 = await _rolesService.AddRoleAsync(role3, cancellationToken); } - public async Task AddWishlistsWithMessages(CancellationToken cancellationToken) + public async Task AddWishlistsWithMessagesAndProducts(CancellationToken cancellationToken) { var user1 = await (await _userCollection.FindAsync(x => x.Email.Equals("shopping.assistant.team@gmail.com"))).FirstAsync(); var user2 = await (await _userCollection.FindAsync(x => x.Email.Equals("mykhailo.bilodid@nure.ua"))).FirstAsync(); @@ -186,6 +189,7 @@ public class DbInitialaizer Name = "Gaming PC", Type = WishlistTypes.Product.ToString(), CreatedById = user1.Id, + CreatedDateUtc = DateTime.UtcNow }, new Wishlist { @@ -193,6 +197,7 @@ public class DbInitialaizer Name = "Generic Wishlist Name", Type = WishlistTypes.Product.ToString(), CreatedById = user2.Id, + CreatedDateUtc = DateTime.UtcNow } }; @@ -206,12 +211,14 @@ public class DbInitialaizer Role = MessageRoles.User.ToString(), WishlistId = wishlistId1, CreatedById = user1.Id, + CreatedDateUtc = DateTime.UtcNow }, new Message { Text = "Message 2", Role = MessageRoles.Application.ToString(), WishlistId = wishlistId1, + CreatedDateUtc = DateTime.UtcNow }, new Message { @@ -219,12 +226,14 @@ public class DbInitialaizer Role = MessageRoles.User.ToString(), WishlistId = wishlistId1, CreatedById = user1.Id, + CreatedDateUtc = DateTime.UtcNow }, new Message { Text = "Message 4", Role = MessageRoles.Application.ToString(), WishlistId = wishlistId1, + CreatedDateUtc = DateTime.UtcNow }, new Message { @@ -232,12 +241,14 @@ public class DbInitialaizer Role = MessageRoles.User.ToString(), WishlistId = wishlistId1, CreatedById = user1.Id, + CreatedDateUtc = DateTime.UtcNow }, new Message { Text = "Message 6", Role = MessageRoles.Application.ToString(), WishlistId = wishlistId1, + CreatedDateUtc = DateTime.UtcNow }, new Message { @@ -245,9 +256,48 @@ public class DbInitialaizer Role = MessageRoles.User.ToString(), WishlistId = wishlistId2, CreatedById = user2.Id, + CreatedDateUtc = DateTime.UtcNow } }; await _messageCollection.InsertManyAsync(messages); + + var products = new Product[] + { + new Product + { + Name = "AMD Ryzen 5 5600G 6-Core 12-Thread Unlocked Desktop Processor with Radeon Graphics", + Description = "Features best-in-class graphics performance in a desktop processor for smooth 1080p gaming, no graphics card required", + Rating = 4.8, + Url = "https://a.co/d/5ceuIrq", + ImagesUrls = new string[] + { + "https://m.media-amazon.com/images/I/51f2hkWjTlL._AC_SL1200_.jpg", + "https://m.media-amazon.com/images/I/51iji7Gel-L._AC_SL1200_.jpg" + }, + WasOpened = false, + WishlistId = wishlistId1, + CreatedById = user1.Id, + CreatedDateUtc = DateTime.UtcNow + }, + new Product + { + Name = "Samsung 970 EVO Plus SSD 2TB NVMe M.2 Internal Solid State Hard Drive, V-NAND Technology, Storage and Memory Expansion for Gaming, Graphics w/ Heat Control, Max Speed, MZ-V7S2T0B/AM ", + Description = "7 Year Limited Warranty: The 970 EVO Plus provides up to 1200 TBW (Terabytes Written) with 5-years of protection for exceptional endurance powered by the latest V-NAND technology and Samsung's reputation for quality ", + Rating = 4.8, + Url = "https://a.co/d/gxnuqs1", + ImagesUrls = new string[] + { + "https://m.media-amazon.com/images/I/51Brl+iYtvL._AC_SL1001_.jpg", + "https://m.media-amazon.com/images/I/51GOfLlVwoL._AC_SL1001_.jpg" + }, + WasOpened = false, + WishlistId = wishlistId1, + CreatedById = user1.Id, + CreatedDateUtc = DateTime.UtcNow + }, + }; + + await _productCollection.InsertManyAsync(products); } } diff --git a/ShoppingAssistantApi.Persistance/PersistanceExtentions/RepositoriesExtention.cs b/ShoppingAssistantApi.Persistance/PersistanceExtentions/RepositoriesExtention.cs index e48ae73..2fbfa72 100644 --- a/ShoppingAssistantApi.Persistance/PersistanceExtentions/RepositoriesExtention.cs +++ b/ShoppingAssistantApi.Persistance/PersistanceExtentions/RepositoriesExtention.cs @@ -15,6 +15,7 @@ public static class RepositoriesExtention services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); return services; } diff --git a/ShoppingAssistantApi.Persistance/Repositories/ProductRepository.cs b/ShoppingAssistantApi.Persistance/Repositories/ProductRepository.cs new file mode 100644 index 0000000..3e0863a --- /dev/null +++ b/ShoppingAssistantApi.Persistance/Repositories/ProductRepository.cs @@ -0,0 +1,10 @@ +using ShoppingAssistantApi.Application.IRepositories; +using ShoppingAssistantApi.Domain.Entities; +using ShoppingAssistantApi.Persistance.Database; + +namespace ShoppingAssistantApi.Persistance.Repositories; + +public class ProductsRepository : BaseRepository, IProductsRepository +{ + public ProductsRepository(MongoDbContext db) : base(db, "Products") { } +} diff --git a/ShoppingAssistantApi.Tests/Tests/WishlistsTests.cs b/ShoppingAssistantApi.Tests/Tests/WishlistsTests.cs index 90394c5..6f22fe7 100644 --- a/ShoppingAssistantApi.Tests/Tests/WishlistsTests.cs +++ b/ShoppingAssistantApi.Tests/Tests/WishlistsTests.cs @@ -186,7 +186,7 @@ public class WishlistsTests : IClassFixture> } [Fact] - public async Task GetMessagesPageFromPersonalWishlist_ValidPageNumberAndSizeValidWishlistIdOrAuthorizedAccess_ReturnsWishlistModel() + public async Task GetMessagesPageFromPersonalWishlist_ValidPageNumberAndSizeValidWishlistIdOrAuthorizedAccess_ReturnsPage() { var tokensModel = await AccessExtention.Login(WISHLIST_TESTING_USER_EMAIL, WISHLIST_TESTING_USER_PASSWORD, _httpClient); _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokensModel.AccessToken); @@ -221,6 +221,40 @@ public class WishlistsTests : IClassFixture> Assert.Equal(user.Id, (string) firstMessageInPage.createdById); } + [Fact] + public async Task GetProductsPageFromPersonalWishlist_ValidPageNumberAndSizeValidWishlistIdOrAuthorizedAccess_ReturnsPage() + { + var tokensModel = await AccessExtention.Login(WISHLIST_TESTING_USER_EMAIL, WISHLIST_TESTING_USER_PASSWORD, _httpClient); + _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokensModel.AccessToken); + var user = await UserExtention.GetCurrentUser(_httpClient); + + var mutation = new + { + query = "query productsPageFromPersonalWishlist($wishlistId: String!, $pageNumber: Int!, $pageSize: Int!) { productsPageFromPersonalWishlist (wishlistId: $wishlistId, pageNumber: $pageNumber, pageSize: $pageSize) { hasNextPage, hasPreviousPage, items { id, url, name, description, rating, imagesUrls, wasOpened, wishlistId }, pageNumber, pageSize, totalItems, totalPages } }", + variables = new + { + wishlistId = WISHLIST_TESTING_VALID_WISHLIST_ID, + pageNumber = 1, + pageSize = 2 + } + }; + + var jsonPayload = JsonConvert.SerializeObject(mutation); + var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json"); + + using var response = await _httpClient.PostAsync("graphql", content); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + + var responseString = await response.Content.ReadAsStringAsync(); + var document = JsonConvert.DeserializeObject(responseString); + + var productsPageFromPersonalWishlist = Enumerable.ToList(document.data.productsPageFromPersonalWishlist.items); + var secondProductInPage = productsPageFromPersonalWishlist[1]; + + Assert.Equal("Samsung 970 EVO Plus SSD 2TB NVMe M.2 Internal Solid State Hard Drive, V-NAND Technology, Storage and Memory Expansion for Gaming, Graphics w/ Heat Control, Max Speed, MZ-V7S2T0B/AM ", (string) secondProductInPage.name); + Assert.Equal(WISHLIST_TESTING_VALID_WISHLIST_ID, (string) secondProductInPage.wishlistId); + } + [Fact] public async Task DeletePersonalWishlist_ValidWishlistIdOrAuthorizedAccess_ReturnsWishlistModel() { @@ -553,6 +587,115 @@ public class WishlistsTests : IClassFixture> Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); } + [Fact] + public async Task GetProductsPageFromPersonalWishlist_InValidPageNumber_ReturnsInternalServerError() + { + var tokensModel = await AccessExtention.Login(WISHLIST_TESTING_USER_EMAIL, WISHLIST_TESTING_USER_PASSWORD, _httpClient); + _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokensModel.AccessToken); + var user = await UserExtention.GetCurrentUser(_httpClient); + + var mutation = new + { + query = "query productsPageFromPersonalWishlist($wishlistId: String!, $pageNumber: Int!, $pageSize: Int!) { productsPageFromPersonalWishlist (wishlistId: $wishlistId, pageNumber: $pageNumber, pageSize: $pageSize) { hasNextPage, hasPreviousPage, items { id, url, name, description, rating, imagesUrls, wasOpened, wishlistId }, pageNumber, pageSize, totalItems, totalPages } }", + variables = new + { + wishlistId = WISHLIST_TESTING_VALID_WISHLIST_ID, + pageNumber = 0, + pageSize = 2 + } + }; + + var jsonPayload = JsonConvert.SerializeObject(mutation); + var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json"); + + using var response = await _httpClient.PostAsync("graphql", content); + Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); + } + + [Fact] + public async Task GetProductsPageFromPersonalWishlist_InValidPageSize_ReturnsPage() + { + var tokensModel = await AccessExtention.Login(WISHLIST_TESTING_USER_EMAIL, WISHLIST_TESTING_USER_PASSWORD, _httpClient); + _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokensModel.AccessToken); + var user = await UserExtention.GetCurrentUser(_httpClient); + + var mutation = new + { + query = "query productsPageFromPersonalWishlist($wishlistId: String!, $pageNumber: Int!, $pageSize: Int!) { productsPageFromPersonalWishlist (wishlistId: $wishlistId, pageNumber: $pageNumber, pageSize: $pageSize) { hasNextPage, hasPreviousPage, items { id, url, name, description, rating, imagesUrls, wasOpened, wishlistId }, pageNumber, pageSize, totalItems, totalPages } }", + variables = new + { + wishlistId = WISHLIST_TESTING_VALID_WISHLIST_ID, + pageNumber = 1, + pageSize = 100 + } + }; + + var jsonPayload = JsonConvert.SerializeObject(mutation); + var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json"); + + using var response = await _httpClient.PostAsync("graphql", content); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + + var responseString = await response.Content.ReadAsStringAsync(); + var document = JsonConvert.DeserializeObject(responseString); + + var productsPageFromPersonalWishlist = Enumerable.ToList(document.data.productsPageFromPersonalWishlist.items); + var secondProductInPage = productsPageFromPersonalWishlist[1]; + + Assert.Equal("Samsung 970 EVO Plus SSD 2TB NVMe M.2 Internal Solid State Hard Drive, V-NAND Technology, Storage and Memory Expansion for Gaming, Graphics w/ Heat Control, Max Speed, MZ-V7S2T0B/AM ", (string) secondProductInPage.name); + Assert.Equal(WISHLIST_TESTING_VALID_WISHLIST_ID, (string) secondProductInPage.wishlistId); + } + + [Fact] + public async Task GetProductsPageFromPersonalWishlist_InValidWishlistId_ReturnsInternalServerError() + { + var tokensModel = await AccessExtention.Login(WISHLIST_TESTING_USER_EMAIL, WISHLIST_TESTING_USER_PASSWORD, _httpClient); + _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokensModel.AccessToken); + var user = await UserExtention.GetCurrentUser(_httpClient); + + var mutation = new + { + query = "query productsPageFromPersonalWishlist($wishlistId: String!, $pageNumber: Int!, $pageSize: Int!) { productsPageFromPersonalWishlist (wishlistId: $wishlistId, pageNumber: $pageNumber, pageSize: $pageSize) { hasNextPage, hasPreviousPage, items { id, url, name, description, rating, imagesUrls, wasOpened, wishlistId }, pageNumber, pageSize, totalItems, totalPages } }", + variables = new + { + wishlistId = WISHLIST_TESTING_INVALID_WISHLIST_ID, + pageNumber = 0, + pageSize = 2 + } + }; + + var jsonPayload = JsonConvert.SerializeObject(mutation); + var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json"); + + using var response = await _httpClient.PostAsync("graphql", content); + Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); + } + + [Fact] + public async Task GetProductsPageFromPersonalWishlist_UnAuthorizedAccess_ReturnsInternalServerError() + { + var tokensModel = await AccessExtention.Login(WISHLIST_TESTING_USER_EMAIL, WISHLIST_TESTING_USER_PASSWORD, _httpClient); + _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokensModel.AccessToken); + var user = await UserExtention.GetCurrentUser(_httpClient); + + var mutation = new + { + query = "query productsPageFromPersonalWishlist($wishlistId: String!, $pageNumber: Int!, $pageSize: Int!) { productsPageFromPersonalWishlist (wishlistId: $wishlistId, pageNumber: $pageNumber, pageSize: $pageSize) { hasNextPage, hasPreviousPage, items { id, url, name, description, rating, imagesUrls, wasOpened, wishlistId }, pageNumber, pageSize, totalItems, totalPages } }", + variables = new + { + wishlistId = WISHLIST_TESTING_OTHER_USER_WISHLIST_ID, + pageNumber = 0, + pageSize = 2 + } + }; + + var jsonPayload = JsonConvert.SerializeObject(mutation); + var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json"); + + using var response = await _httpClient.PostAsync("graphql", content); + Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); + } + [Fact] public async Task DeletePersonalWishlist_InValidWishlistId_ReturnsInternalServerError() {