first commit

This commit is contained in:
2026-05-18 15:53:59 +03:30
commit 2c100028a1
534 changed files with 94240 additions and 0 deletions
@@ -0,0 +1,320 @@
using System.Globalization;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Bunit;
using SufiChain.SufiBlazor.Components.Overlays;
using SufiChain.SufiBlazor.Localization;
using Xunit;
namespace SufiChain.SufiBlazor.Tests.Components.Overlays;
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 SbConfirmDialogTests : BunitContext
{
public SbConfirmDialogTests()
{
Services.AddSingleton<IStringLocalizer<SufiBlazorResource>>(new StubStringLocalizer());
}
private IRenderedComponent<SbConfirmDialog> RenderConfirmDialog(
Action<ComponentParameterCollectionBuilder<SbConfirmDialog>>? configure = null)
{
return Render<SbConfirmDialog>(p => configure?.Invoke(p));
}
[Fact]
public void DoesNotRenderWhenClosed()
{
// Arrange & Act
var cut = RenderConfirmDialog(p => p
.Add(x => x.Title, "Confirm")
.Add(x => x.Message, "Are you sure?"));
// Assert
Assert.Empty(cut.FindAll(".sb-confirm-dialog-overlay"));
}
[Fact]
public async Task RendersWhenShowCalled()
{
// Arrange & Act
var cut = RenderConfirmDialog(p => p
.Add(x => x.Title, "Confirm")
.Add(x => x.Message, "Proceed?"));
await cut.InvokeAsync(() => cut.Instance.Show());
cut.Render();
// Assert
var overlay = cut.Find(".sb-confirm-dialog-overlay");
Assert.NotNull(overlay);
var dialog = cut.Find(".sb-confirm-dialog");
Assert.NotNull(dialog);
}
[Fact]
public async Task RendersTitleAndMessage()
{
// Arrange & Act
var cut = RenderConfirmDialog(p => p
.Add(x => x.Title, "Delete Item")
.Add(x => x.Message, "This cannot be undone."));
await cut.InvokeAsync(() => cut.Instance.Show());
cut.Render();
// Assert
Assert.Contains("Delete Item", cut.Markup);
Assert.Contains("This cannot be undone.", cut.Markup);
var title = cut.Find(".sb-confirm-dialog__title");
Assert.NotNull(title);
var message = cut.Find(".sb-confirm-dialog__message");
Assert.NotNull(message);
}
[Fact]
public async Task RendersChildContent()
{
// Arrange & Act
var cut = RenderConfirmDialog(p => p
.Add(x => x.Title, "Confirm")
.AddChildContent(b => b.AddMarkupContent(0, "<p>Custom content</p>")));
await cut.InvokeAsync(() => cut.Instance.Show());
cut.Render();
// Assert
Assert.Contains("Custom content", cut.Markup);
var body = cut.Find(".sb-confirm-dialog__body");
Assert.NotNull(body);
}
[Fact]
public async Task DoesNotRenderMessageWhenNull()
{
// Arrange & Act
var cut = RenderConfirmDialog(p => p
.Add(x => x.Title, "Title only"));
await cut.InvokeAsync(() => cut.Instance.Show());
cut.Render();
// Assert
Assert.Empty(cut.FindAll(".sb-confirm-dialog__message"));
}
[Fact]
public async Task AppliesVariantClass()
{
// Arrange & Act
var cut = RenderConfirmDialog(p => p
.Add(x => x.Title, "Confirm")
.Add(x => x.Variant, SbConfirmDialogVariant.Danger));
await cut.InvokeAsync(() => cut.Instance.Show());
cut.Render();
// Assert
var dialog = cut.Find(".sb-confirm-dialog");
Assert.Contains("sb-confirm-dialog--danger", dialog.ClassList);
}
[Theory]
[InlineData(SbConfirmDialogVariant.Default, "default")]
[InlineData(SbConfirmDialogVariant.Danger, "danger")]
[InlineData(SbConfirmDialogVariant.Warning, "warning")]
[InlineData(SbConfirmDialogVariant.Info, "info")]
public async Task AppliesCorrectVariantClass(SbConfirmDialogVariant variant, string expectedClass)
{
// Arrange & Act
var cut = RenderConfirmDialog(p => p
.Add(x => x.Title, "Confirm")
.Add(x => x.Variant, variant));
await cut.InvokeAsync(() => cut.Instance.Show());
cut.Render();
// Assert
var dialog = cut.Find(".sb-confirm-dialog");
Assert.Contains($"sb-confirm-dialog--{expectedClass}", dialog.ClassList);
}
[Fact]
public async Task ShowsCancelButtonByDefault()
{
// Arrange & Act
var cut = RenderConfirmDialog(p => p.Add(x => x.Title, "Confirm"));
await cut.InvokeAsync(() => cut.Instance.Show());
cut.Render();
// Assert - two buttons: Cancel and Confirm
var buttons = cut.FindAll("button");
Assert.True(buttons.Count >= 2);
}
[Fact]
public async Task HidesCancelButtonWhenShowCancelButtonFalse()
{
// Arrange & Act
var cut = RenderConfirmDialog(p => p
.Add(x => x.Title, "Confirm")
.Add(x => x.ShowCancelButton, false));
await cut.InvokeAsync(() => cut.Instance.Show());
cut.Render();
// Assert - only Confirm button (SbButton with Ghost variant is Cancel)
var ghostButtons = cut.FindAll("button.sb-button--ghost");
Assert.Empty(ghostButtons);
}
[Fact]
public async Task AppliesCustomButtonText()
{
// Arrange & Act
var cut = RenderConfirmDialog(p => p
.Add(x => x.Title, "Confirm")
.Add(x => x.ConfirmText, "Yes, delete")
.Add(x => x.CancelText, "Keep"));
await cut.InvokeAsync(() => cut.Instance.Show());
cut.Render();
// Assert
Assert.Contains("Yes, delete", cut.Markup);
Assert.Contains("Keep", cut.Markup);
}
[Fact]
public async Task AppliesClassParameter()
{
// Arrange & Act
var cut = RenderConfirmDialog(p => p
.Add(x => x.Title, "Confirm")
.Add(x => x.Class, "my-dialog"));
await cut.InvokeAsync(() => cut.Instance.Show());
cut.Render();
// Assert
var dialog = cut.Find(".sb-confirm-dialog");
Assert.Contains("my-dialog", dialog.ClassList);
}
[Fact]
public async Task HasAlertDialogRole()
{
// Arrange & Act
var cut = RenderConfirmDialog(p => p.Add(x => x.Title, "Confirm"));
await cut.InvokeAsync(() => cut.Instance.Show());
cut.Render();
// Assert
var dialog = cut.Find(".sb-confirm-dialog");
Assert.Equal("alertdialog", dialog.GetAttribute("role"));
Assert.Equal("true", dialog.GetAttribute("aria-modal"));
}
[Fact]
public async Task ConfirmButtonInvokesOnConfirm()
{
// Arrange
var confirmed = false;
var cut = RenderConfirmDialog(p => p
.Add(x => x.Title, "Confirm")
.Add(x => x.OnConfirm, EventCallback.Factory.Create(this, () => confirmed = true)));
await cut.InvokeAsync(() => cut.Instance.Show());
cut.Render();
// Act - click Confirm (Solid button, not Ghost)
var confirmBtn = cut.FindAll("button.sb-button--solid").Last();
await cut.InvokeAsync(() => confirmBtn.Click());
// Assert
Assert.True(confirmed);
}
[Fact]
public async Task CancelButtonInvokesOnCancel()
{
// Arrange
var cancelled = false;
var cut = RenderConfirmDialog(p => p
.Add(x => x.Title, "Confirm")
.Add(x => x.OnCancel, EventCallback.Factory.Create(this, () => cancelled = true)));
await cut.InvokeAsync(() => cut.Instance.Show());
cut.Render();
// Act - click Cancel (Ghost button)
var cancelBtn = cut.Find("button.sb-button--ghost");
await cut.InvokeAsync(() => cancelBtn!.Click());
// Assert
Assert.True(cancelled);
}
[Fact]
public async Task ShowAsyncReturnsTrueWhenConfirmed()
{
// Arrange
var cut = RenderConfirmDialog(p => p
.Add(x => x.Title, "Confirm")
.Add(x => x.ShowCancelButton, false));
Task<bool> showTask = null!;
await cut.InvokeAsync(() => { showTask = cut.Instance.ShowAsync(); });
cut.Render();
// Act
var confirmBtn = cut.Find("button.sb-button--solid");
await cut.InvokeAsync(() => confirmBtn!.Click());
// Assert
var result = await showTask;
Assert.True(result);
}
[Fact]
public async Task ShowAsyncReturnsFalseWhenCancelled()
{
// Arrange
var cut = RenderConfirmDialog(p => p.Add(x => x.Title, "Confirm"));
Task<bool> showTask = null!;
await cut.InvokeAsync(() => { showTask = cut.Instance.ShowAsync(); });
cut.Render();
// Act - click Cancel
var cancelBtn = cut.Find("button.sb-button--ghost");
await cut.InvokeAsync(() => cancelBtn!.Click());
// Assert
var result = await showTask;
Assert.False(result);
}
[Fact]
public async Task CloseHidesDialog()
{
// Arrange & Act
var cut = RenderConfirmDialog(p => p.Add(x => x.Title, "Confirm"));
await cut.InvokeAsync(() => cut.Instance.Show());
cut.Render();
Assert.NotNull(cut.Find(".sb-confirm-dialog-overlay"));
await cut.InvokeAsync(() => cut.Instance.Close());
cut.Render();
// Assert
Assert.Empty(cut.FindAll(".sb-confirm-dialog-overlay"));
}
[Fact]
public async Task RendersIconSection()
{
// Arrange & Act
var cut = RenderConfirmDialog(p => p.Add(x => x.Title, "Confirm"));
await cut.InvokeAsync(() => cut.Instance.Show());
cut.Render();
// Assert
var icon = cut.Find(".sb-confirm-dialog__icon");
Assert.NotNull(icon);
}
}