Files
2026-05-18 15:53:59 +03:30

194 lines
5.2 KiB
C#

using System.Globalization;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Bunit;
using SufiChain.SufiBlazor.Components.Feedback;
using SufiChain.SufiBlazor.Localization;
using Xunit;
namespace SufiChain.SufiBlazor.Tests.Components.Feedback;
/// <summary>
/// Stub localizer that returns the key as the value (for testing).
/// </summary>
file class StubStringLocalizer : IStringLocalizer<SufiBlazorResource>
{
public LocalizedString this[string name] => new(name, name);
public LocalizedString this[string name, params object[] arguments] => new(name, string.Format(CultureInfo.InvariantCulture, name, arguments));
public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures) => Array.Empty<LocalizedString>();
}
public class SbToastTests : BunitContext
{
public SbToastTests()
{
Services.AddSingleton<IStringLocalizer<SufiBlazorResource>>(new StubStringLocalizer());
}
private IRenderedComponent<SbToast> RenderToast(
Action<ComponentParameterCollectionBuilder<SbToast>>? configure = null)
{
return Render<SbToast>(p =>
{
p.Add(x => x.Message, "Toast message");
configure?.Invoke(p);
});
}
[Fact]
public void RendersToastStructure()
{
// Arrange & Act
var cut = RenderToast();
// Assert
var toast = cut.Find(".sb-toast");
Assert.NotNull(toast);
Assert.Equal("alert", toast.GetAttribute("role"));
Assert.Equal("polite", toast.GetAttribute("aria-live"));
Assert.NotNull(cut.Find(".sb-toast__icon"));
Assert.NotNull(cut.Find(".sb-toast__content"));
Assert.NotNull(cut.Find(".sb-toast__message"));
}
[Fact]
public void RendersMessage()
{
// Arrange & Act
var cut = RenderToast();
// Assert
Assert.Contains("Toast message", cut.Markup);
}
[Fact]
public void RendersChildContentOverMessage()
{
// Arrange & Act
var cut = Render<SbToast>(p => p
.Add(x => x.Message, "Fallback")
.AddChildContent("<span class=\"custom-msg\">Custom content</span>"));
// Assert - ChildContent takes precedence
Assert.Contains("Custom content", cut.Markup);
}
[Fact]
public void RendersTitleWhenProvided()
{
// Arrange & Act
var cut = RenderToast(p => p.Add(x => x.Title, "Success"));
// Assert
var title = cut.Find(".sb-toast__title");
Assert.NotNull(title);
Assert.Contains("Success", title.TextContent);
}
[Fact]
public void DoesNotRenderTitleWhenEmpty()
{
// Arrange & Act
var cut = RenderToast();
// Assert
Assert.Empty(cut.FindAll(".sb-toast__title"));
}
[Fact]
public void AppliesInfoSeverityByDefault()
{
// Arrange & Act
var cut = RenderToast();
// Assert
var toast = cut.Find(".sb-toast");
Assert.Contains("sb-toast--info", toast.ClassList);
}
[Fact]
public void AppliesSuccessSeverity()
{
// Arrange & Act
var cut = RenderToast(p => p.Add(x => x.Severity, SbToastSeverity.Success));
// Assert
var toast = cut.Find(".sb-toast");
Assert.Contains("sb-toast--success", toast.ClassList);
}
[Fact]
public void AppliesWarningSeverity()
{
// Arrange & Act
var cut = RenderToast(p => p.Add(x => x.Severity, SbToastSeverity.Warning));
// Assert
var toast = cut.Find(".sb-toast");
Assert.Contains("sb-toast--warning", toast.ClassList);
}
[Fact]
public void AppliesErrorSeverity()
{
// Arrange & Act
var cut = RenderToast(p => p.Add(x => x.Severity, SbToastSeverity.Error));
// Assert
var toast = cut.Find(".sb-toast");
Assert.Contains("sb-toast--error", toast.ClassList);
}
[Fact]
public void RendersCloseButtonByDefault()
{
// Arrange & Act
var cut = RenderToast();
// Assert
var closeBtn = cut.Find(".sb-toast__close");
Assert.NotNull(closeBtn);
Assert.Equal("Close", closeBtn.GetAttribute("aria-label"));
}
[Fact]
public void DoesNotRenderCloseButtonWhenShowCloseButtonFalse()
{
// Arrange & Act
var cut = RenderToast(p => p.Add(x => x.ShowCloseButton, false));
// Assert
Assert.Empty(cut.FindAll(".sb-toast__close"));
}
[Fact]
public async Task InvokesOnCloseWhenCloseButtonClicked()
{
// Arrange
var closed = false;
var cut = RenderToast(p => p.Add(x => x.OnClose, EventCallback.Factory.Create(this, () => closed = true)));
var closeBtn = cut.Find(".sb-toast__close");
// Act
await cut.InvokeAsync(() => closeBtn!.Click());
cut.WaitForState(() => closed);
// Assert
Assert.True(closed);
}
[Fact]
public void AppliesCustomClass()
{
// Arrange & Act
var cut = RenderToast(p => p.Add(x => x.Class, "my-toast"));
// Assert
var toast = cut.Find(".sb-toast");
Assert.Contains("my-toast", toast.ClassList);
}
}