Latest
This commit is contained in:
@@ -103,7 +103,7 @@ public sealed class ProductCardShould : BunitContext
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Title = "Aluminum Chandelier",
|
||||
Url = "/catalog/product/aluminum-chandelier",
|
||||
Url = "/browse/product?slug=aluminum-chandelier",
|
||||
Slug = "aluminum-chandelier",
|
||||
CategoryName = "Chandeliers",
|
||||
CategoryUrl = "/catalog/chandeliers",
|
||||
|
||||
128
Prefab.Tests/Web.Client/Pages/ProductPageTests.cs
Normal file
128
Prefab.Tests/Web.Client/Pages/ProductPageTests.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using System.Globalization;
|
||||
using Bunit;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Prefab.Web.Client.Models.Catalog;
|
||||
using Prefab.Web.Client.Models.Shared;
|
||||
using Prefab.Web.Client.Pages.Browse;
|
||||
using Prefab.Web.Client.Services;
|
||||
using Shouldly;
|
||||
|
||||
namespace Prefab.Tests.Web.Client.Pages;
|
||||
|
||||
[Trait(TraitName.Category, TraitCategory.Unit)]
|
||||
public sealed class ProductPageTests : BunitContext
|
||||
{
|
||||
[Fact]
|
||||
public void ProductPage_Renders_Product_Details_From_Service()
|
||||
{
|
||||
var model = CreateSampleProduct();
|
||||
Services.AddScoped<IProductDisplayService>(_ =>
|
||||
new FakeProductDisplayService(Result<ProductDisplayModel>.Success(model)));
|
||||
|
||||
var navigation = Services.GetRequiredService<NavigationManager>();
|
||||
navigation.NavigateTo(navigation.GetUriWithQueryParameter("slug", model.Slug));
|
||||
|
||||
var component = Render<Product>();
|
||||
|
||||
component.Markup.ShouldContain(model.Name);
|
||||
model.Description.ShouldNotBeNull();
|
||||
component.Markup.ShouldContain(model.Description!);
|
||||
component.FindAll("input[type=radio]").Count.ShouldBe(2);
|
||||
component.Markup.ShouldContain("Quantity");
|
||||
component.FindAll(".product__add-to-cart").Count.ShouldBe(1);
|
||||
component.Markup.ShouldContain("Documents");
|
||||
component.Markup.ShouldContain("Spec Sheet");
|
||||
component.Markup.ShouldContain("SW-001");
|
||||
component.Markup.ShouldContain("Lighting");
|
||||
var expectedPrice = model.BasePrice!.Value.ToString("C", CultureInfo.CurrentCulture);
|
||||
component.Markup.ShouldContain(expectedPrice);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ProductPage_Shows_Problem_When_NotFound()
|
||||
{
|
||||
Services.AddScoped<IProductDisplayService>(_ =>
|
||||
new FakeProductDisplayService(Result<ProductDisplayModel>.Failure(new ResultProblem
|
||||
{
|
||||
Title = "Product not found.",
|
||||
Detail = "Product 'unknown' was not found.",
|
||||
StatusCode = (int)HttpStatusCode.NotFound
|
||||
})));
|
||||
|
||||
var navigation = Services.GetRequiredService<NavigationManager>();
|
||||
navigation.NavigateTo(navigation.GetUriWithQueryParameter("slug", "unknown"));
|
||||
|
||||
var component = Render<Product>();
|
||||
|
||||
component.Markup.ShouldContain("Product not found.");
|
||||
component.FindAll(".alert-warning").Count.ShouldBe(1);
|
||||
}
|
||||
|
||||
private static ProductDisplayModel CreateSampleProduct() => new()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Slug = "sample-widget",
|
||||
Name = "Sample Widget",
|
||||
Description = "<p>Sample description.</p>",
|
||||
BasePrice = 42.50m,
|
||||
Sku = "SW-001",
|
||||
Categories =
|
||||
[
|
||||
new ProductDisplayModel.CategoryRef(Guid.NewGuid(), "Lighting", "lighting")
|
||||
],
|
||||
Options =
|
||||
[
|
||||
new ProductDisplayModel.OptionDefinition(
|
||||
Id: Guid.NewGuid(),
|
||||
Code: "color",
|
||||
Name: "Color",
|
||||
DataType: 0,
|
||||
IsVariantAxis: true,
|
||||
Unit: null,
|
||||
Min: null,
|
||||
Max: null,
|
||||
Step: null,
|
||||
PricePerUnit: null,
|
||||
Tiers: Array.Empty<ProductDisplayModel.Tier>(),
|
||||
Values:
|
||||
[
|
||||
new ProductDisplayModel.OptionValue(Guid.NewGuid(), "red", "Red", 0m, 0),
|
||||
new ProductDisplayModel.OptionValue(Guid.NewGuid(), "blue", "Blue", 0m, 0)
|
||||
]),
|
||||
new ProductDisplayModel.OptionDefinition(
|
||||
Id: Guid.NewGuid(),
|
||||
Code: "length",
|
||||
Name: "Length",
|
||||
DataType: 1,
|
||||
IsVariantAxis: false,
|
||||
Unit: "ft",
|
||||
Min: 1,
|
||||
Max: 10,
|
||||
Step: 1,
|
||||
PricePerUnit: null,
|
||||
Tiers:
|
||||
[
|
||||
new ProductDisplayModel.Tier(1, 5, 1, null)
|
||||
],
|
||||
Values: Array.Empty<ProductDisplayModel.OptionValue>())
|
||||
],
|
||||
Specs =
|
||||
[
|
||||
new ProductDisplayModel.Spec("Weight", "25 lb", null, null)
|
||||
],
|
||||
GenericAttributes = new Dictionary<string, string>
|
||||
{
|
||||
["catalog.product.docs"] = """[{ "title": "Spec Sheet", "url": "https://example.com/spec.pdf" }]"""
|
||||
}
|
||||
};
|
||||
|
||||
private sealed class FakeProductDisplayService(Result<ProductDisplayModel> result) : IProductDisplayService
|
||||
{
|
||||
private readonly Result<ProductDisplayModel> _result = result;
|
||||
|
||||
public Task<Result<ProductDisplayModel>> Get(string slug, CancellationToken cancellationToken = default) =>
|
||||
Task.FromResult(_result);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user