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 RenderCheckbox( Action>? configure = null) { return Render(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(p => p .Add(x => x.Label, "Ignore me") .AddChildContent(b => b.AddMarkupContent(0, "Custom content"))); // 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(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(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(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 { { "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")); } }