using Prefab.Catalog.Domain.Entities; using Prefab.Catalog.Domain.Services; using Prefab.Tests; using Prefab.Web.Pricing; using Shouldly; namespace Prefab.Tests.Unit.Web.Pricing; [Trait(TraitName.Category, TraitCategory.Unit)] public sealed class FromPriceCalculatorShould { private readonly FromPriceCalculator _calculator = new(); private readonly IUniqueChecker _uniqueChecker = new AlwaysUniqueChecker(); [Fact] public async Task UseModelPriceWhenAvailable() { var cancellationToken = TestContext.Current.CancellationToken; var product = await Product.CreateModel( name: "Model A", slug: "model-a", description: null, uniqueChecker: _uniqueChecker, cancellationToken: cancellationToken); product.SetBasePrice(199.99m); var variant = await Product.CreateVariant( product.Id, sku: "SKU-1", name: "Variant 1", price: 149.99m, uniqueChecker: _uniqueChecker, cancellationToken: cancellationToken); product.AttachVariant(variant); var result = _calculator.Compute(product); result.IsPriced.ShouldBeTrue(); result.Amount.ShouldBe(199.99m); result.Currency.ShouldBe("USD"); } [Fact] public async Task UseLowestVariantPriceWhenModelPriceMissing() { var cancellationToken = TestContext.Current.CancellationToken; var product = await Product.CreateModel( name: "Model B", slug: "model-b", description: null, uniqueChecker: _uniqueChecker, cancellationToken: cancellationToken); var highVariant = await Product.CreateVariant( product.Id, sku: "HIGH", name: "High Variant", price: 249.50m, uniqueChecker: _uniqueChecker, cancellationToken: cancellationToken); var lowVariant = await Product.CreateVariant( product.Id, sku: "LOW", name: "Low Variant", price: 125.25m, uniqueChecker: _uniqueChecker, cancellationToken: cancellationToken); product.AttachVariant(highVariant); product.AttachVariant(lowVariant); var result = _calculator.Compute(product); result.IsPriced.ShouldBeTrue(); result.Amount.ShouldBe(125.25m); result.Currency.ShouldBe("USD"); } [Fact] public async Task ReturnUnpricedWhenNoPricesAvailable() { var cancellationToken = TestContext.Current.CancellationToken; var product = await Product.CreateModel( name: "Model C", slug: "model-c", description: null, uniqueChecker: _uniqueChecker, cancellationToken: cancellationToken); var result = _calculator.Compute(product); result.IsPriced.ShouldBeFalse(); result.Amount.ShouldBeNull(); result.Currency.ShouldBeNull(); } private sealed class AlwaysUniqueChecker : IUniqueChecker { public Task CategoryNameIsUnique(string name, CancellationToken cancellationToken = default) => Task.FromResult(true); public Task ProductModelNameIsUnique(string name, CancellationToken cancellationToken = default) => Task.FromResult(true); public Task ProductSlugIsUnique(string? slug, CancellationToken cancellationToken = default) => Task.FromResult(true); public Task ProductSkuIsUnique(string sku, CancellationToken cancellationToken = default) => Task.FromResult(true); public Task OptionCodeIsUniqueForProduct(Guid productId, string code, CancellationToken cancellationToken = default) => Task.FromResult(true); } }