Init
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
using Bunit;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Prefab.Web.Client.Components.Catalog;
|
||||
using Prefab.Web.Client.ViewModels.Catalog;
|
||||
using Shouldly;
|
||||
|
||||
namespace Prefab.Tests.Web.Client.Components.Catalog;
|
||||
|
||||
[Trait(TraitName.Category, TraitCategory.Unit)]
|
||||
public sealed class CategoryCardShould : BunitContext
|
||||
{
|
||||
[Fact]
|
||||
public void RenderImageAndTitle()
|
||||
{
|
||||
var model = new CategoryCardModel
|
||||
{
|
||||
Title = "Ceiling Supports",
|
||||
Url = "/catalog/products?category-slug=ceiling-supports",
|
||||
ImageUrl = "/images/categories/ceiling-supports.png",
|
||||
SecondaryText = "2 products"
|
||||
};
|
||||
|
||||
var cut = Render<CategoryCard>(parameters => parameters.Add(p => p.Category, model));
|
||||
|
||||
var root = cut.Find($".{TemplateCss.CardRoot}");
|
||||
root.ClassList.ShouldContain(TemplateCss.CategoryCardRoot);
|
||||
|
||||
var image = cut.Find($".{TemplateCss.CategoryCardImage} img");
|
||||
image.GetAttribute("src").ShouldBe(model.ImageUrl);
|
||||
image.GetAttribute("alt").ShouldBe(model.Title);
|
||||
|
||||
var title = cut.Find($".{TemplateCss.CategoryCardName}");
|
||||
title.TextContent.Trim().ShouldBe(model.Title);
|
||||
|
||||
var secondary = cut.Find($".{TemplateCss.CategoryCardProducts}");
|
||||
secondary.TextContent.Trim().ShouldBe("2 products");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RenderPlaceholderWhenNoImage()
|
||||
{
|
||||
const string placeholder = "No image available";
|
||||
var model = new CategoryCardModel
|
||||
{
|
||||
Title = "Prefabricated Assemblies",
|
||||
Url = "/catalog/products?category-slug=prefab-assemblies"
|
||||
};
|
||||
|
||||
var cut = Render<CategoryCard>(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.Category, model);
|
||||
parameters.Add(p => p.ImagePlaceholderText, placeholder);
|
||||
});
|
||||
|
||||
var placeholderNode = cut.Find($".{TemplateCss.CategoryCardImage} .{TemplateCss.CategoryCardImagePlaceholder}");
|
||||
placeholderNode.TextContent.Trim().ShouldBe(placeholder);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InvokeSelectionCallback()
|
||||
{
|
||||
var model = new CategoryCardModel
|
||||
{
|
||||
Title = "Rod & Strut Hardware",
|
||||
Url = "/catalog/products?category-slug=rod-strut-hardware"
|
||||
};
|
||||
|
||||
CategoryCardModel? selected = null;
|
||||
|
||||
var cut = Render<CategoryCard>(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.Category, model);
|
||||
parameters.Add(p => p.OnCategorySelected, EventCallback.Factory.Create<CategoryCardModel>(this, value => selected = value));
|
||||
});
|
||||
|
||||
cut.Find("a").Click();
|
||||
|
||||
selected.ShouldNotBeNull();
|
||||
ReferenceEquals(selected, model).ShouldBeTrue();
|
||||
}
|
||||
}
|
||||
128
Prefab.Tests/Web.Client/Components/Catalog/ProductCardShould.cs
Normal file
128
Prefab.Tests/Web.Client/Components/Catalog/ProductCardShould.cs
Normal file
@@ -0,0 +1,128 @@
|
||||
using System.Globalization;
|
||||
using Bunit;
|
||||
using Prefab.Web.Client.Components.Catalog;
|
||||
using Prefab.Web.Client.Models.Shared;
|
||||
using Prefab.Web.Client.ViewModels.Catalog;
|
||||
using Shouldly;
|
||||
|
||||
namespace Prefab.Tests.Web.Client.Components.Catalog;
|
||||
|
||||
[Trait(TraitName.Category, TraitCategory.Unit)]
|
||||
public sealed class ProductCardShould : BunitContext
|
||||
{
|
||||
[Fact]
|
||||
public void RenderSaleBadgeOldPriceAndRating()
|
||||
{
|
||||
var model = CreateModel(m =>
|
||||
{
|
||||
m.IsOnSale = true;
|
||||
m.OldPrice = 419m;
|
||||
m.Rating = 4;
|
||||
m.ReviewCount = 15;
|
||||
m.Badges.Add("New");
|
||||
});
|
||||
|
||||
var cut = Render<ProductCard>(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.Product, model);
|
||||
parameters.Add(p => p.ShowPrice, true);
|
||||
});
|
||||
|
||||
var root = cut.Find($".{TemplateCss.ProductCardRoot}");
|
||||
root.ClassList.ShouldContain(TemplateCss.ProductCardGridModifier);
|
||||
|
||||
cut.FindAll($".{TemplateCss.ProductCardBadgeSale}").Count.ShouldBe(1);
|
||||
cut.FindAll($".{TemplateCss.ProductCardBadge}").Count.ShouldBe(2);
|
||||
|
||||
var newPrice = cut.Find($".{TemplateCss.ProductCardPriceNew}");
|
||||
var expectedNewPrice = model.FromPrice?.Amount ?? throw new InvalidOperationException("Expected from price to be set.");
|
||||
newPrice.TextContent.Trim().ShouldBe(expectedNewPrice.ToString("C", CultureInfo.CurrentCulture));
|
||||
|
||||
var oldPrice = cut.Find($".{TemplateCss.ProductCardPriceOld}");
|
||||
var expectedOldPrice = model.OldPrice ?? throw new InvalidOperationException("Expected old price to be set for sale items.");
|
||||
oldPrice.TextContent.Trim().ShouldBe(expectedOldPrice.ToString("C", CultureInfo.CurrentCulture));
|
||||
|
||||
var rating = cut.Find($".{TemplateCss.ProductCardRating}");
|
||||
var ratingLabel = rating.QuerySelector($".{TemplateCss.Rating}")!;
|
||||
ratingLabel.GetAttribute("aria-label").ShouldBe("4 out of 5");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NotRenderSaleBadgeOrOldPriceWhenAbsent()
|
||||
{
|
||||
var model = CreateModel(m =>
|
||||
{
|
||||
m.IsOnSale = false;
|
||||
m.OldPrice = null;
|
||||
m.Rating = 0;
|
||||
m.ReviewCount = 0;
|
||||
});
|
||||
|
||||
var cut = Render<ProductCard>(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.Product, model);
|
||||
parameters.Add(p => p.ShowPrice, true);
|
||||
});
|
||||
|
||||
cut.FindAll($".{TemplateCss.ProductCardBadgeSale}").ShouldBeEmpty();
|
||||
cut.Markup.ShouldNotContain(TemplateCss.ProductCardPriceOld);
|
||||
cut.Markup.ShouldNotContain(TemplateCss.ProductCardRating);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NotRenderPricesByDefault()
|
||||
{
|
||||
var model = CreateModel();
|
||||
|
||||
var cut = Render<ProductCard>(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.Product, model);
|
||||
// ShowPrice is false by default
|
||||
});
|
||||
|
||||
cut.Markup.ShouldNotContain(TemplateCss.ProductCardPrice);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NotRenderActionButtons()
|
||||
{
|
||||
var model = CreateModel();
|
||||
|
||||
var cut = Render<ProductCard>(parameters =>
|
||||
{
|
||||
parameters.Add(p => p.Product, model);
|
||||
});
|
||||
|
||||
cut.Markup.ShouldNotContain("product-card__actions");
|
||||
cut.Markup.ShouldNotContain("product-card__buttons");
|
||||
}
|
||||
|
||||
private static ProductCardModel CreateModel(Action<ProductCardModel>? configure = null)
|
||||
{
|
||||
var model = new ProductCardModel
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Title = "Aluminum Chandelier",
|
||||
Url = "/catalog/product/aluminum-chandelier",
|
||||
Slug = "aluminum-chandelier",
|
||||
CategoryName = "Chandeliers",
|
||||
CategoryUrl = "/catalog/chandeliers",
|
||||
PrimaryImageUrl = "/images/products/product1.jpg",
|
||||
FromPrice = new MoneyModel
|
||||
{
|
||||
Amount = 321.54m,
|
||||
Currency = "USD"
|
||||
},
|
||||
IsPriced = true,
|
||||
Rating = 3,
|
||||
ReviewCount = 2,
|
||||
Sku = "SKU-1001",
|
||||
IsOnSale = true,
|
||||
OldPrice = 399.99m,
|
||||
LastModifiedOn = DateTimeOffset.UtcNow
|
||||
};
|
||||
|
||||
configure?.Invoke(model);
|
||||
return model;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user