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

255 lines
7.3 KiB
C#

using Microsoft.AspNetCore.Components;
using Bunit;
using SufiChain.SufiBlazor.Components;
using SufiChain.SufiBlazor.Components.Forms;
using Xunit;
namespace SufiChain.SufiBlazor.Tests.Components.Forms;
public class SbCheckboxTests : BunitContext
{
private IRenderedComponent<SbCheckbox> RenderCheckbox(
Action<ComponentParameterCollectionBuilder<SbCheckbox>>? configure = null)
{
return Render<SbCheckbox>(p =>
{
configure?.Invoke(p);
});
}
[Fact]
public void RendersCheckboxStructure()
{
// Arrange & Act
var cut = RenderCheckbox();
// Assert
var label = cut.Find("label.sb-checkbox");
Assert.NotNull(label);
Assert.NotNull(cut.Find("input.sb-checkbox__input"));
Assert.NotNull(cut.Find(".sb-checkbox__box"));
}
[Fact]
public void RendersLabelWhenProvided()
{
// Arrange & Act
var cut = RenderCheckbox(p => p.Add(x => x.Label, "Accept terms"));
// Assert
var labelSpan = cut.Find(".sb-checkbox__label");
Assert.NotNull(labelSpan);
Assert.Contains("Accept terms", labelSpan.TextContent);
}
[Fact]
public void DoesNotRenderLabelSpanWhenLabelAndChildContentEmpty()
{
// Arrange & Act
var cut = RenderCheckbox();
// Assert - no label span when both Label and ChildContent are null/empty
Assert.Empty(cut.FindAll(".sb-checkbox__label"));
}
[Fact]
public void RendersChildContentInsteadOfLabelWhenBothProvided()
{
// Arrange & Act
var cut = Render<SbCheckbox>(p => p
.Add(x => x.Label, "Ignore me")
.AddChildContent(b => b.AddMarkupContent(0, "<span>Custom content</span>")));
// Assert - ChildContent takes precedence
var labelSpan = cut.Find(".sb-checkbox__label");
Assert.NotNull(labelSpan);
Assert.Contains("Custom content", labelSpan.InnerHtml);
}
[Fact]
public void RendersCheckedClassAndCheckIconWhenValueTrue()
{
// Arrange & Act
var cut = RenderCheckbox(p => p.Add(x => x.Value, true));
// Assert
var label = cut.Find("label.sb-checkbox");
Assert.Contains("sb-checkbox--checked", label.ClassList);
Assert.NotNull(cut.Find(".sb-checkbox__check"));
}
[Fact]
public void RendersIndeterminateClassAndIconWhenIndeterminateTrue()
{
// Arrange & Act
var cut = RenderCheckbox(p => p
.Add(x => x.Value, false)
.Add(x => x.Indeterminate, true));
// Assert
var label = cut.Find("label.sb-checkbox");
Assert.Contains("sb-checkbox--indeterminate", label.ClassList);
Assert.NotNull(cut.Find(".sb-checkbox__indeterminate"));
}
[Fact]
public void RendersDisabledClassWhenDisabledTrue()
{
// Arrange & Act
var cut = RenderCheckbox(p => p.Add(x => x.Disabled, true));
// Assert
var label = cut.Find("label.sb-checkbox");
Assert.Contains("sb-checkbox--disabled", label.ClassList);
var input = cut.Find("input");
Assert.True(input.GetAttribute("disabled") != null || input.OuterHtml.Contains("disabled"));
}
[Fact]
public void AppliesColorClass()
{
// Arrange & Act
var cut = RenderCheckbox(p => p.Add(x => x.Color, SbColor.Success));
// Assert
var label = cut.Find("label.sb-checkbox");
Assert.Contains("sb-checkbox--success", label.ClassList);
}
[Fact]
public async Task InvokesValueChangedWhenChecked()
{
// Arrange
var received = false;
var cut = RenderCheckbox(p => p
.Add(x => x.Value, false)
.Add(x => x.ValueChanged, EventCallback.Factory.Create<bool>(this, v => received = v)));
// Act - SbCheckbox uses @onchange
var input = cut.Find("input.sb-checkbox__input");
await cut.InvokeAsync(() => input!.Change(true));
// Assert
Assert.True(received);
}
[Fact]
public async Task InvokesValueChangedWhenUnchecked()
{
// Arrange
var received = true;
var cut = RenderCheckbox(p => p
.Add(x => x.Value, true)
.Add(x => x.ValueChanged, EventCallback.Factory.Create<bool>(this, v => received = v)));
// Act
var input = cut.Find("input.sb-checkbox__input");
await cut.InvokeAsync(() => input!.Change(false));
// Assert
Assert.False(received);
}
[Fact]
public async Task DoesNotInvokeValueChangedWhenDisabled()
{
// Arrange
var received = (bool?)null;
var cut = RenderCheckbox(p => p
.Add(x => x.Value, false)
.Add(x => x.Disabled, true)
.Add(x => x.ValueChanged, EventCallback.Factory.Create<bool>(this, v => received = v)));
// Act
var input = cut.Find("input.sb-checkbox__input");
await cut.InvokeAsync(() => input!.Change(true));
// Assert - callback should not be invoked when disabled
Assert.Null(received);
}
[Fact]
public void HasCorrectAriaCheckedWhenChecked()
{
// Arrange & Act
var cut = RenderCheckbox(p => p.Add(x => x.Value, true));
// Assert
var input = cut.Find("input");
Assert.Equal("true", input.GetAttribute("aria-checked"));
}
[Fact]
public void HasCorrectAriaCheckedWhenUnchecked()
{
// Arrange & Act
var cut = RenderCheckbox(p => p.Add(x => x.Value, false));
// Assert
var input = cut.Find("input");
Assert.Equal("false", input.GetAttribute("aria-checked"));
}
[Fact]
public void HasAriaCheckedMixedWhenIndeterminate()
{
// Arrange & Act
var cut = RenderCheckbox(p => p
.Add(x => x.Value, false)
.Add(x => x.Indeterminate, true));
// Assert
var input = cut.Find("input");
Assert.Equal("mixed", input.GetAttribute("aria-checked"));
}
[Fact]
public void AppliesCustomClass()
{
// Arrange & Act
var cut = RenderCheckbox(p => p.Add(x => x.Class, "my-checkbox"));
// Assert
var label = cut.Find("label.sb-checkbox");
Assert.Contains("my-checkbox", label.ClassList);
}
[Fact]
public void AppliesInlineStyle()
{
// Arrange & Act
var cut = RenderCheckbox(p => p.Add(x => x.Style, "margin: 8px;"));
// Assert
var label = cut.Find("label.sb-checkbox");
Assert.Contains("margin: 8px", label.GetAttribute("style"));
}
[Fact]
public void AppliesIdToInput()
{
// Arrange & Act
var cut = RenderCheckbox(p => p.Add(x => x.Id, "agree-checkbox"));
// Assert
var input = cut.Find("input");
Assert.Equal("agree-checkbox", input.GetAttribute("id"));
}
[Fact]
public void AppliesAdditionalAttributes()
{
// Arrange & Act
var cut = RenderCheckbox(p => p.Add(x => x.AdditionalAttributes, new Dictionary<string, object>
{
{ "data-testid", "accept-checkbox" },
{ "aria-label", "Accept terms and conditions" }
}));
// Assert
var input = cut.Find("input");
Assert.Equal("accept-checkbox", input.GetAttribute("data-testid"));
Assert.Equal("Accept terms and conditions", input.GetAttribute("aria-label"));
}
}