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
+372
View File
@@ -0,0 +1,372 @@
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 SbRadioTests : BunitContext
{
private IRenderedComponent<SbRadioGroup<string>> RenderRadioGroup(
Action<ComponentParameterCollectionBuilder<SbRadioGroup<string>>>? configure = null)
{
return Render<SbRadioGroup<string>>(p =>
{
p.AddChildContent(builder =>
{
builder.OpenComponent<SbRadio<string>>(0);
builder.AddAttribute(1, "Value", "a");
builder.AddAttribute(2, "Label", "Option A");
builder.CloseComponent();
builder.OpenComponent<SbRadio<string>>(3);
builder.AddAttribute(4, "Value", "b");
builder.AddAttribute(5, "Label", "Option B");
builder.CloseComponent();
builder.OpenComponent<SbRadio<string>>(6);
builder.AddAttribute(7, "Value", "c");
builder.AddAttribute(8, "Label", "Option C");
builder.CloseComponent();
});
configure?.Invoke(p);
});
}
[Fact]
public void RendersRadioStructure()
{
// Arrange & Act
var cut = RenderRadioGroup();
// Assert
var radios = cut.FindAll("label.sb-radio");
Assert.Equal(3, radios.Count);
Assert.NotNull(cut.Find("input.sb-radio__input[type='radio']"));
Assert.NotNull(cut.Find(".sb-radio__circle"));
Assert.NotNull(cut.Find(".sb-radio__dot"));
Assert.NotNull(cut.Find(".sb-radio__text"));
}
[Fact]
public void RendersLabelWhenProvided()
{
// Arrange & Act
var cut = RenderRadioGroup();
// Assert
var labels = cut.FindAll(".sb-radio__label");
Assert.Contains(labels, l => l.TextContent.Contains("Option A"));
Assert.Contains(labels, l => l.TextContent.Contains("Option B"));
}
[Fact]
public void RendersCheckedClassWhenValueMatches()
{
// Arrange & Act
var cut = RenderRadioGroup(p => p.Add(x => x.Value, "b"));
// Assert
var radios = cut.FindAll("label.sb-radio");
var checkedRadio = radios.FirstOrDefault(r => r.ClassList.Contains("sb-radio--checked"));
Assert.NotNull(checkedRadio);
Assert.Contains("Option B", checkedRadio.TextContent);
}
[Fact]
public void InputHasCheckedAttributeWhenSelected()
{
// Arrange & Act
var cut = RenderRadioGroup(p => p.Add(x => x.Value, "a"));
// Assert
var inputs = cut.FindAll("input.sb-radio__input");
var checkedInput = inputs.FirstOrDefault(i => i.GetAttribute("value") == "a");
Assert.NotNull(checkedInput);
Assert.NotNull(checkedInput.GetAttribute("checked"));
}
[Fact]
public void InputsShareSameNameFromGroup()
{
// Arrange & Act
var cut = RenderRadioGroup(p => p.Add(x => x.Name, "test-group"));
// Assert
var inputs = cut.FindAll("input[type='radio']");
var name = inputs[0].GetAttribute("name");
Assert.NotNull(name);
Assert.All(inputs, i => Assert.Equal(name, i.GetAttribute("name")));
}
[Fact]
public void RendersHelperTextWhenProvided()
{
// Arrange & Act
var cut = Render<SbRadioGroup<string>>(p => p
.Add(x => x.Value, "pro")
.AddChildContent(builder =>
{
builder.OpenComponent<SbRadio<string>>(0);
builder.AddAttribute(1, "Value", "free");
builder.AddAttribute(2, "Label", "Free");
builder.AddAttribute(3, "HelperText", "Basic features");
builder.CloseComponent();
builder.OpenComponent<SbRadio<string>>(4);
builder.AddAttribute(5, "Value", "pro");
builder.AddAttribute(6, "Label", "Pro");
builder.AddAttribute(7, "HelperText", "Advanced features");
builder.CloseComponent();
}));
// Assert
var helpers = cut.FindAll(".sb-radio__helper");
Assert.Equal(2, helpers.Count);
Assert.Contains(helpers, h => h.TextContent.Contains("Basic features"));
Assert.Contains(helpers, h => h.TextContent.Contains("Advanced features"));
}
[Fact]
public void RendersChildContentInsteadOfLabel()
{
// Arrange & Act
var cut = Render<SbRadioGroup<string>>(p => p
.AddChildContent(builder =>
{
builder.OpenComponent<SbRadio<string>>(0);
builder.AddAttribute(1, "Value", "custom");
builder.AddAttribute(2, "ChildContent", (RenderFragment)(b => b.AddMarkupContent(0, "<strong>Custom option</strong>")));
builder.CloseComponent();
}));
// Assert
var labelSpan = cut.Find(".sb-radio__label");
Assert.NotNull(labelSpan);
Assert.Contains("Custom option", labelSpan.InnerHtml);
}
[Fact]
public void AppliesDisabledClassWhenRadioDisabled()
{
// Arrange & Act
var cut = Render<SbRadioGroup<string>>(p => p
.AddChildContent(builder =>
{
builder.OpenComponent<SbRadio<string>>(0);
builder.AddAttribute(1, "Value", "enabled");
builder.AddAttribute(2, "Label", "Enabled");
builder.CloseComponent();
builder.OpenComponent<SbRadio<string>>(3);
builder.AddAttribute(4, "Value", "disabled");
builder.AddAttribute(5, "Label", "Disabled");
builder.AddAttribute(6, "Disabled", true);
builder.CloseComponent();
}));
// Assert
var radios = cut.FindAll("label.sb-radio");
var disabledRadio = radios.FirstOrDefault(r => r.ClassList.Contains("sb-radio--disabled"));
Assert.NotNull(disabledRadio);
Assert.Contains("Disabled", disabledRadio.TextContent);
}
[Fact]
public void AppliesDisabledClassWhenGroupDisabled()
{
// Arrange & Act
var cut = RenderRadioGroup(p => p.Add(x => x.Disabled, true));
// Assert
var radios = cut.FindAll("label.sb-radio");
Assert.All(radios, r => Assert.Contains("sb-radio--disabled", r.ClassList));
}
[Fact]
public void AppliesClassParameter()
{
// Arrange & Act
var cut = Render<SbRadioGroup<string>>(p => p
.AddChildContent(builder =>
{
builder.OpenComponent<SbRadio<string>>(0);
builder.AddAttribute(1, "Value", "x");
builder.AddAttribute(2, "Label", "X");
builder.AddAttribute(3, "Class", "my-radio");
builder.CloseComponent();
}));
// Assert
var radio = cut.Find("label.sb-radio");
Assert.Contains("my-radio", radio.ClassList);
}
[Fact]
public void AppliesIdToInput()
{
// Arrange & Act
var cut = Render<SbRadioGroup<string>>(p => p
.AddChildContent(builder =>
{
builder.OpenComponent<SbRadio<string>>(0);
builder.AddAttribute(1, "Value", "x");
builder.AddAttribute(2, "Label", "X");
builder.AddAttribute(3, "Id", "radio-x");
builder.CloseComponent();
}));
// Assert
var input = cut.Find("input.sb-radio__input");
Assert.Equal("radio-x", input.GetAttribute("id"));
}
[Fact]
public async Task InvokesValueChangedWhenRadioSelected()
{
// Arrange
string? received = null;
var cut = RenderRadioGroup(p => p
.Add(x => x.Value, "a")
.Add(x => x.ValueChanged, EventCallback.Factory.Create<string>(this, v => received = v)));
// Act - select Option B via input change (radio uses @onchange)
var inputB = cut.FindAll("input.sb-radio__input").First(i => i.GetAttribute("value") == "b");
await cut.InvokeAsync(() => inputB!.Change("b"));
// Assert
Assert.Equal("b", received);
}
[Fact]
public void RendersRadioGroupStructure()
{
// Arrange & Act
var cut = RenderRadioGroup(p => p.Add(x => x.Label, "Choose one"));
// Assert
var group = cut.Find(".sb-radio-group");
Assert.NotNull(group);
Assert.Equal("radiogroup", group.GetAttribute("role"));
Assert.NotNull(cut.Find(".sb-radio-group__label"));
Assert.Contains("Choose one", cut.Markup);
}
[Fact]
public void AppliesAdditionalAttributesToInput()
{
// Arrange & Act
var cut = Render<SbRadioGroup<string>>(p => p
.AddChildContent(builder =>
{
builder.OpenComponent<SbRadio<string>>(0);
builder.AddAttribute(1, "Value", "x");
builder.AddAttribute(2, "Label", "X");
builder.AddAttribute(3, "AdditionalAttributes", new Dictionary<string, object>
{
{ "data-testid", "radio-x" },
{ "aria-label", "Select X" }
});
builder.CloseComponent();
}));
// Assert
var input = cut.Find("input.sb-radio__input");
Assert.Equal("radio-x", input.GetAttribute("data-testid"));
Assert.Equal("Select X", input.GetAttribute("aria-label"));
}
// SbRadioGroup-specific tests
[Fact]
public void AppliesVerticalOrientationByDefault()
{
// Arrange & Act
var cut = RenderRadioGroup();
// Assert
var group = cut.Find(".sb-radio-group");
Assert.Contains("sb-radio-group--vertical", group.ClassList);
}
[Fact]
public void AppliesHorizontalOrientationWhenSet()
{
// Arrange & Act
var cut = RenderRadioGroup(p => p.Add(x => x.Orientation, SbOrientation.Horizontal));
// Assert
var group = cut.Find(".sb-radio-group");
Assert.Contains("sb-radio-group--horizontal", group.ClassList);
}
[Fact]
public void UsesAriaLabelWhenProvided()
{
// Arrange & Act
var cut = RenderRadioGroup(p => p
.Add(x => x.AriaLabel, "Select an option")
.Add(x => x.Label, "Choose one"));
// Assert - AriaLabel takes precedence over Label
var group = cut.Find(".sb-radio-group");
Assert.Equal("Select an option", group.GetAttribute("aria-label"));
}
[Fact]
public void UsesLabelAsAriaLabelWhenAriaLabelNotSet()
{
// Arrange & Act
var cut = RenderRadioGroup(p => p.Add(x => x.Label, "Choose one"));
// Assert
var group = cut.Find(".sb-radio-group");
Assert.Equal("Choose one", group.GetAttribute("aria-label"));
}
[Fact]
public void AppliesGroupClassParameter()
{
// Arrange & Act
var cut = RenderRadioGroup(p => p.Add(x => x.Class, "horizontal-group"));
// Assert
var group = cut.Find(".sb-radio-group");
Assert.Contains("horizontal-group", group.ClassList);
}
[Fact]
public void AppliesGroupStyleParameter()
{
// Arrange & Act
var cut = RenderRadioGroup(p => p.Add(x => x.Style, "gap: 1rem;"));
// Assert
var group = cut.Find(".sb-radio-group");
Assert.Contains("gap: 1rem", group.GetAttribute("style"));
}
[Fact]
public void AppliesGroupAdditionalAttributes()
{
// Arrange & Act
var cut = RenderRadioGroup(p => p.Add(x => x.AdditionalAttributes, new Dictionary<string, object>
{
{ "data-testid", "radio-group" },
{ "aria-describedby", "group-desc" }
}));
// Assert
var group = cut.Find(".sb-radio-group");
Assert.Equal("radio-group", group.GetAttribute("data-testid"));
Assert.Equal("group-desc", group.GetAttribute("aria-describedby"));
}
[Fact]
public void AppliesGroupDisabledClassWhenDisabled()
{
// Arrange & Act
var cut = RenderRadioGroup(p => p.Add(x => x.Disabled, true));
// Assert
var group = cut.Find(".sb-radio-group");
Assert.Contains("sb-radio-group--disabled", group.ClassList);
}
}