154 lines
6.1 KiB
C#
154 lines
6.1 KiB
C#
using FluentValidation;
|
|
using Moq;
|
|
using Prefab.Shared.Catalog;
|
|
using Prefab.Shared.Catalog.Products;
|
|
using Prefab.Tests;
|
|
using Prefab.Web.Client.Models.Catalog;
|
|
using Prefab.Web.Client.Models.Home;
|
|
using Prefab.Web.Client.Models.Shared;
|
|
using Prefab.Web.Gateway;
|
|
using Shouldly;
|
|
using UrlPolicy = Prefab.Web.UrlPolicy.UrlPolicy;
|
|
|
|
namespace Prefab.Tests.Unit.Web.Gateway;
|
|
|
|
[Trait(TraitName.Category, TraitCategory.Unit)]
|
|
public sealed class HomeServiceShould
|
|
{
|
|
[Fact]
|
|
public async Task AggregateFeaturedProductsAndCategories()
|
|
{
|
|
var (service, productClient) = CreateService();
|
|
|
|
var featured = CreateNode("Featured Leaf", "featured-leaf", displayOrder: 2, isFeatured: true);
|
|
var secondary = CreateNode("Secondary Leaf", "secondary-leaf", displayOrder: 1, isFeatured: false);
|
|
|
|
productClient
|
|
.Setup(client => client.GetCategoryTree(3, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(new GetCategoryTree.Response(new[] { featured, secondary }));
|
|
|
|
productClient
|
|
.Setup(client => client.GetCategoryModels("featured-leaf", It.IsAny<int?>(), It.IsAny<int?>(), It.IsAny<string?>(), It.IsAny<string?>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(CreateListingResponse("featured-leaf", total: 3, cards: new[]
|
|
{
|
|
CreateProductCardDto("Featured 1", "featured-1", 19m),
|
|
CreateProductCardDto("Duplicate", "duplicate", 21m)
|
|
}));
|
|
|
|
productClient
|
|
.Setup(client => client.GetCategoryModels("secondary-leaf", It.IsAny<int?>(), It.IsAny<int?>(), It.IsAny<string?>(), It.IsAny<string?>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(CreateListingResponse("secondary-leaf", total: 2, cards: new[]
|
|
{
|
|
CreateProductCardDto("Secondary 1", "secondary-1", 15m),
|
|
CreateProductCardDto("Duplicate", "duplicate", 21m)
|
|
}));
|
|
|
|
var result = await service.Get(CancellationToken.None);
|
|
|
|
result.IsSuccess.ShouldBeTrue();
|
|
var payload = result.Value.ShouldNotBeNull();
|
|
|
|
payload.LatestCategories.Count.ShouldBe(2);
|
|
payload.LatestCategories.Select(category => category.Title).ShouldBe(["Featured Leaf", "Secondary Leaf"]);
|
|
|
|
payload.FeaturedProducts.Count.ShouldBe(3);
|
|
payload.FeaturedProducts.Select(product => product.Url).ShouldBe([
|
|
UrlPolicy.BrowseProduct("featured-1"),
|
|
UrlPolicy.BrowseProduct("duplicate"),
|
|
UrlPolicy.BrowseProduct("secondary-1")
|
|
]);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SkipCategoriesWithoutProducts()
|
|
{
|
|
var (service, productClient) = CreateService();
|
|
|
|
var empty = CreateNode("Empty Leaf", "empty-leaf", displayOrder: 0, isFeatured: true);
|
|
var populated = CreateNode("Populated Leaf", "populated-leaf", displayOrder: 1, isFeatured: false);
|
|
|
|
productClient
|
|
.Setup(client => client.GetCategoryTree(3, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(new GetCategoryTree.Response(new[] { empty, populated }));
|
|
|
|
productClient
|
|
.Setup(client => client.GetCategoryModels("empty-leaf", It.IsAny<int?>(), It.IsAny<int?>(), It.IsAny<string?>(), It.IsAny<string?>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(CreateListingResponse("empty-leaf", total: 0, cards: Array.Empty<GetCategoryModels.ProductCardDto>()));
|
|
|
|
productClient
|
|
.Setup(client => client.GetCategoryModels("populated-leaf", It.IsAny<int?>(), It.IsAny<int?>(), It.IsAny<string?>(), It.IsAny<string?>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(CreateListingResponse("populated-leaf", total: 1, cards: new[]
|
|
{
|
|
CreateProductCardDto("Populated", "populated-1", 32m)
|
|
}));
|
|
|
|
var result = await service.Get(CancellationToken.None);
|
|
|
|
result.IsSuccess.ShouldBeTrue();
|
|
var payload = result.Value.ShouldNotBeNull();
|
|
|
|
payload.LatestCategories.Count.ShouldBe(1);
|
|
payload.LatestCategories.Single().Title.ShouldBe("Populated Leaf");
|
|
payload.FeaturedProducts.Single().Url.ShouldBe(UrlPolicy.BrowseProduct("populated-1"));
|
|
}
|
|
|
|
private static (Home.Service Service, Mock<IProductClient> ProductClient) CreateService()
|
|
{
|
|
var moduleClient = new Mock<IModuleClient>();
|
|
var productClient = new Mock<IProductClient>();
|
|
moduleClient.SetupGet(client => client.Product).Returns(productClient.Object);
|
|
|
|
var listingService = new Products.ListingService(moduleClient.Object);
|
|
var service = new Home.Service(moduleClient.Object, listingService);
|
|
|
|
return (service, productClient);
|
|
}
|
|
|
|
private static GetCategoryModels.CategoryNodeDto CreateNode(string name, string slug, int displayOrder, bool isFeatured) =>
|
|
new(
|
|
Guid.NewGuid(),
|
|
name,
|
|
slug,
|
|
Description: null,
|
|
HeroImageUrl: null,
|
|
Icon: null,
|
|
DisplayOrder: displayOrder,
|
|
IsFeatured: isFeatured,
|
|
IsLeaf: true,
|
|
Children: Array.Empty<GetCategoryModels.CategoryNodeDto>());
|
|
|
|
private static GetCategoryModels.Response CreateListingResponse(
|
|
string slug,
|
|
int total,
|
|
IReadOnlyList<GetCategoryModels.ProductCardDto> cards)
|
|
{
|
|
var category = new GetCategoryModels.CategoryDetailDto(
|
|
Guid.NewGuid(),
|
|
slug,
|
|
slug,
|
|
Description: null,
|
|
HeroImageUrl: null,
|
|
Icon: null,
|
|
IsLeaf: true,
|
|
Children: Array.Empty<GetCategoryModels.CategoryNodeDto>());
|
|
|
|
var response = new GetCategoryModels.CategoryProductsResponse(
|
|
category,
|
|
cards,
|
|
total,
|
|
Page: 1,
|
|
PageSize: Math.Max(1, cards.Count));
|
|
|
|
return new GetCategoryModels.Response(response);
|
|
}
|
|
|
|
private static GetCategoryModels.ProductCardDto CreateProductCardDto(string name, string slug, decimal price) =>
|
|
new(
|
|
Guid.NewGuid(),
|
|
name,
|
|
slug,
|
|
FromPrice: price,
|
|
PrimaryImageUrl: null,
|
|
LastModifiedOn: DateTimeOffset.UtcNow);
|
|
}
|