148 lines
5.5 KiB
C#
148 lines
5.5 KiB
C#
using Prefab.Catalog.Domain.Entities;
|
|
using Prefab.Catalog.Domain.Services;
|
|
using Shouldly;
|
|
|
|
namespace Prefab.Tests.Unit.Modules.Catalog.Domain.Services;
|
|
|
|
[Trait(TraitName.Category, TraitCategory.Unit)]
|
|
public sealed class VariantResolverShould
|
|
{
|
|
private readonly StubUniqueChecker _checker = new();
|
|
|
|
[Fact]
|
|
public async Task ResolveVariantFromAxisSelections()
|
|
{
|
|
var context = await BuildModelWithVariantsAsync();
|
|
var resolver = new VariantResolver();
|
|
|
|
var selections = new[]
|
|
{
|
|
new OptionSelection(context.ColorOption.Id, context.RedValue.Id, null),
|
|
new OptionSelection(context.DepthOption.Id, context.Depth24Value.Id, null)
|
|
};
|
|
|
|
var result = resolver.Resolve(context.Model, selections);
|
|
|
|
result.IsSuccess.ShouldBeTrue();
|
|
result.Variant.ShouldBe(context.Red24Variant);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ReturnErrorWhenAxisSelectionMissing()
|
|
{
|
|
var context = await BuildModelWithVariantsAsync();
|
|
var resolver = new VariantResolver();
|
|
|
|
var selections = new[]
|
|
{
|
|
new OptionSelection(context.ColorOption.Id, context.RedValue.Id, null)
|
|
};
|
|
|
|
var result = resolver.Resolve(context.Model, selections);
|
|
|
|
result.IsSuccess.ShouldBeFalse();
|
|
result.Errors.ShouldContain(e => e.Contains("axis", StringComparison.OrdinalIgnoreCase));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ResolveBySkuWhenProvided()
|
|
{
|
|
var context = await BuildModelWithVariantsAsync();
|
|
var resolver = new VariantResolver();
|
|
|
|
var result = resolver.Resolve(context.Model, Array.Empty<OptionSelection>(), context.Blue34Variant.Sku);
|
|
|
|
result.IsSuccess.ShouldBeTrue();
|
|
result.Variant.ShouldBe(context.Blue34Variant);
|
|
}
|
|
|
|
private async Task<ModelContext> BuildModelWithVariantsAsync()
|
|
{
|
|
var model = await Product.CreateModel($"variant-model-{Guid.NewGuid():N}", $"variant-model-{Guid.NewGuid():N}", null, _checker);
|
|
|
|
var colorOption = await OptionDefinition.CreateChoice(model, "color", "Color", _checker, isVariantAxis: true);
|
|
var redValue = colorOption.AddValue("red", "Red", 0m, PriceDeltaKind.Absolute);
|
|
var blueValue = colorOption.AddValue("blue", "Blue", 0m, PriceDeltaKind.Absolute);
|
|
|
|
var depthOption = await OptionDefinition.CreateChoice(model, "depth", "Depth", _checker, isVariantAxis: true);
|
|
var depth24Value = depthOption.AddValue("depth_24", "24\"", 0m, PriceDeltaKind.Absolute);
|
|
var depth34Value = depthOption.AddValue("depth_34", "34\"", 0m, PriceDeltaKind.Absolute);
|
|
|
|
var red24Variant = await Product.CreateVariant(model.Id, $"SKU-{Guid.NewGuid():N}", "Red 24", 20m, _checker);
|
|
red24Variant.AxisValues.Add(new VariantAxisValue
|
|
{
|
|
ProductVariant = red24Variant,
|
|
ProductVariantId = red24Variant.Id,
|
|
OptionDefinition = colorOption,
|
|
OptionDefinitionId = colorOption.Id,
|
|
OptionValue = redValue,
|
|
OptionValueId = redValue.Id
|
|
});
|
|
red24Variant.AxisValues.Add(new VariantAxisValue
|
|
{
|
|
ProductVariant = red24Variant,
|
|
ProductVariantId = red24Variant.Id,
|
|
OptionDefinition = depthOption,
|
|
OptionDefinitionId = depthOption.Id,
|
|
OptionValue = depth24Value,
|
|
OptionValueId = depth24Value.Id
|
|
});
|
|
|
|
var blue34Variant = await Product.CreateVariant(model.Id, $"SKU-{Guid.NewGuid():N}", "Blue 34", 22m, _checker);
|
|
blue34Variant.AxisValues.Add(new VariantAxisValue
|
|
{
|
|
ProductVariant = blue34Variant,
|
|
ProductVariantId = blue34Variant.Id,
|
|
OptionDefinition = colorOption,
|
|
OptionDefinitionId = colorOption.Id,
|
|
OptionValue = blueValue,
|
|
OptionValueId = blueValue.Id
|
|
});
|
|
blue34Variant.AxisValues.Add(new VariantAxisValue
|
|
{
|
|
ProductVariant = blue34Variant,
|
|
ProductVariantId = blue34Variant.Id,
|
|
OptionDefinition = depthOption,
|
|
OptionDefinitionId = depthOption.Id,
|
|
OptionValue = depth34Value,
|
|
OptionValueId = depth34Value.Id
|
|
});
|
|
|
|
model.AttachVariant(red24Variant);
|
|
model.AttachVariant(blue34Variant);
|
|
|
|
return new ModelContext(
|
|
model,
|
|
colorOption,
|
|
depthOption,
|
|
redValue,
|
|
depth24Value,
|
|
blue34Variant,
|
|
red24Variant,
|
|
depth34Value);
|
|
}
|
|
|
|
private sealed record ModelContext(
|
|
Product Model,
|
|
OptionDefinition ColorOption,
|
|
OptionDefinition DepthOption,
|
|
OptionValue RedValue,
|
|
OptionValue Depth24Value,
|
|
Product Blue34Variant,
|
|
Product Red24Variant,
|
|
OptionValue Depth34Value);
|
|
|
|
private sealed class StubUniqueChecker : IUniqueChecker
|
|
{
|
|
public Task<bool> CategoryNameIsUnique(string name, CancellationToken cancellationToken = default) => Task.FromResult(true);
|
|
|
|
public Task<bool> ProductModelNameIsUnique(string name, CancellationToken cancellationToken = default) => Task.FromResult(true);
|
|
|
|
public Task<bool> ProductSlugIsUnique(string? slug, CancellationToken cancellationToken = default) => Task.FromResult(true);
|
|
|
|
public Task<bool> ProductSkuIsUnique(string sku, CancellationToken cancellationToken = default) => Task.FromResult(true);
|
|
|
|
public Task<bool> OptionCodeIsUniqueForProduct(Guid productId, string code, CancellationToken cancellationToken = default) => Task.FromResult(true);
|
|
}
|
|
}
|