338 lines
9.4 KiB
C#
338 lines
9.4 KiB
C#
using Microsoft.AspNetCore.Components;
|
|
using Bunit;
|
|
using SufiChain.SufiBlazor.Components.Forms;
|
|
using Xunit;
|
|
|
|
namespace SufiChain.SufiBlazor.Tests.Components.Forms;
|
|
|
|
public class SbNumberFieldTests : BunitContext
|
|
{
|
|
private IRenderedComponent<SbNumberField<int>> RenderNumberField(
|
|
Action<ComponentParameterCollectionBuilder<SbNumberField<int>>>? configure = null)
|
|
{
|
|
return Render<SbNumberField<int>>(p =>
|
|
{
|
|
configure?.Invoke(p);
|
|
});
|
|
}
|
|
|
|
[Fact]
|
|
public void RendersNumberFieldStructure()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNumberField();
|
|
|
|
// Assert
|
|
var wrapper = cut.Find(".sb-number-field");
|
|
Assert.NotNull(wrapper);
|
|
Assert.NotNull(cut.Find(".sb-number-field__input-group"));
|
|
var input = cut.Find("input.sb-number-field__input");
|
|
Assert.NotNull(input);
|
|
Assert.Equal("number", input.GetAttribute("type"));
|
|
}
|
|
|
|
[Fact]
|
|
public void RendersLabelWhenProvided()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNumberField(p => p
|
|
.Add(x => x.Label, "Quantity")
|
|
.Add(x => x.Id, "qty"));
|
|
|
|
// Assert
|
|
var label = cut.Find(".sb-number-field__label");
|
|
Assert.NotNull(label);
|
|
Assert.Contains("Quantity", label.TextContent);
|
|
}
|
|
|
|
[Fact]
|
|
public void DoesNotRenderLabelWhenEmpty()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNumberField();
|
|
|
|
// Assert
|
|
Assert.Empty(cut.FindAll(".sb-number-field__label"));
|
|
}
|
|
|
|
[Fact]
|
|
public void RendersRequiredAsteriskWhenRequired()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNumberField(p => p
|
|
.Add(x => x.Label, "Amount")
|
|
.Add(x => x.Required, true));
|
|
|
|
// Assert
|
|
var required = cut.Find(".sb-number-field__required");
|
|
Assert.NotNull(required);
|
|
Assert.Contains("*", required.TextContent);
|
|
}
|
|
|
|
[Fact]
|
|
public void AssociatesLabelWithInputId()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNumberField(p => p
|
|
.Add(x => x.Label, "Value")
|
|
.Add(x => x.Id, "value-input"));
|
|
|
|
// Assert
|
|
var label = cut.Find("label.sb-number-field__label");
|
|
Assert.Equal("value-input", label.GetAttribute("for"));
|
|
}
|
|
|
|
[Fact]
|
|
public void RendersHelperTextWhenProvided()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNumberField(p => p.Add(x => x.HelperText, "Enter a number between 1 and 100"));
|
|
|
|
// Assert
|
|
var helper = cut.Find(".sb-number-field__helper");
|
|
Assert.NotNull(helper);
|
|
Assert.Contains("Enter a number between 1 and 100", helper.TextContent);
|
|
}
|
|
|
|
[Fact]
|
|
public void DisplaysValueInInput()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNumberField(p => p.Add(x => x.Value, 42));
|
|
|
|
// Assert
|
|
var input = cut.Find("input");
|
|
Assert.Equal("42", input.GetAttribute("value"));
|
|
}
|
|
|
|
[Fact]
|
|
public void AppliesMinMaxStepAttributes()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNumberField(p => p
|
|
.Add(x => x.Value, 5)
|
|
.Add(x => x.Min, 0)
|
|
.Add(x => x.Max, 10)
|
|
.Add(x => x.Step, 2));
|
|
|
|
// Assert
|
|
var input = cut.Find("input");
|
|
Assert.Equal("0", input.GetAttribute("min"));
|
|
Assert.Equal("10", input.GetAttribute("max"));
|
|
Assert.Equal("2", input.GetAttribute("step"));
|
|
}
|
|
|
|
[Fact]
|
|
public void AppliesPlaceholder()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNumberField(p => p.Add(x => x.Placeholder, "0.00"));
|
|
|
|
// Assert
|
|
var input = cut.Find("input");
|
|
Assert.Equal("0.00", input.GetAttribute("placeholder"));
|
|
}
|
|
|
|
[Fact]
|
|
public void InputIsDisabledWhenDisabledTrue()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNumberField(p => p.Add(x => x.Disabled, true));
|
|
|
|
// Assert
|
|
var input = cut.Find("input");
|
|
Assert.NotNull(input.GetAttribute("disabled"));
|
|
}
|
|
|
|
[Fact]
|
|
public void InputIsReadOnlyWhenReadOnlyTrue()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNumberField(p => p.Add(x => x.ReadOnly, true));
|
|
|
|
// Assert
|
|
var input = cut.Find("input");
|
|
Assert.NotNull(input.GetAttribute("readonly"));
|
|
}
|
|
|
|
[Fact]
|
|
public void AppliesDisabledClassWhenDisabled()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNumberField(p => p.Add(x => x.Disabled, true));
|
|
|
|
// Assert
|
|
var wrapper = cut.Find(".sb-number-field");
|
|
Assert.Contains("sb-number-field--disabled", wrapper.ClassList);
|
|
}
|
|
|
|
[Fact]
|
|
public void AppliesClassParameter()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNumberField(p => p.Add(x => x.Class, "custom-field"));
|
|
|
|
// Assert
|
|
var wrapper = cut.Find(".sb-number-field");
|
|
Assert.Contains("custom-field", wrapper.ClassList);
|
|
}
|
|
|
|
[Fact]
|
|
public void AppliesStyleParameter()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNumberField(p => p.Add(x => x.Style, "max-width: 200px;"));
|
|
|
|
// Assert
|
|
var wrapper = cut.Find(".sb-number-field");
|
|
Assert.Contains("max-width: 200px", wrapper.GetAttribute("style"));
|
|
}
|
|
|
|
[Fact]
|
|
public void RendersSpinButtonsByDefault()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNumberField();
|
|
|
|
// Assert
|
|
var spinners = cut.FindAll(".sb-number-field__spinner");
|
|
Assert.Equal(2, spinners.Count);
|
|
}
|
|
|
|
[Fact]
|
|
public void DoesNotRenderSpinButtonsWhenShowSpinButtonsFalse()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNumberField(p => p.Add(x => x.ShowSpinButtons, false));
|
|
|
|
// Assert
|
|
Assert.Empty(cut.FindAll(".sb-number-field__spinners"));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task InvokesValueChangedWhenInputChanged()
|
|
{
|
|
// Arrange
|
|
int? received = null;
|
|
var cut = RenderNumberField(p => p
|
|
.Add(x => x.Value, 10)
|
|
.Add(x => x.ValueChanged, EventCallback.Factory.Create<int>(this, v => received = v)));
|
|
|
|
// Act
|
|
var input = cut.Find("input");
|
|
await cut.InvokeAsync(() => input!.Change("25"));
|
|
|
|
// Assert
|
|
Assert.NotNull(received);
|
|
Assert.Equal(25, received);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task InvokesValueChangedWhenIncrementClicked()
|
|
{
|
|
// Arrange
|
|
int? received = null;
|
|
var cut = RenderNumberField(p => p
|
|
.Add(x => x.Value, 5)
|
|
.Add(x => x.ValueChanged, EventCallback.Factory.Create<int>(this, v => received = v)));
|
|
|
|
// Act
|
|
var incrementBtn = cut.FindAll(".sb-number-field__spinner")[0];
|
|
await cut.InvokeAsync(() => incrementBtn!.Click());
|
|
|
|
// Assert
|
|
Assert.NotNull(received);
|
|
Assert.Equal(6, received);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task InvokesValueChangedWhenDecrementClicked()
|
|
{
|
|
// Arrange
|
|
int? received = null;
|
|
var cut = RenderNumberField(p => p
|
|
.Add(x => x.Value, 5)
|
|
.Add(x => x.ValueChanged, EventCallback.Factory.Create<int>(this, v => received = v)));
|
|
|
|
// Act
|
|
var decrementBtn = cut.FindAll(".sb-number-field__spinner")[1];
|
|
await cut.InvokeAsync(() => decrementBtn!.Click());
|
|
|
|
// Assert
|
|
Assert.NotNull(received);
|
|
Assert.Equal(4, received);
|
|
}
|
|
|
|
[Fact]
|
|
public void IncrementButtonDisabledWhenAtMax()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNumberField(p => p
|
|
.Add(x => x.Value, 10)
|
|
.Add(x => x.Max, 10));
|
|
|
|
// Assert
|
|
var spinnerButtons = cut.FindAll(".sb-number-field__spinner");
|
|
var incrementBtn = spinnerButtons[0];
|
|
Assert.NotNull(incrementBtn.GetAttribute("disabled"));
|
|
}
|
|
|
|
[Fact]
|
|
public void DecrementButtonDisabledWhenAtMin()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNumberField(p => p
|
|
.Add(x => x.Value, 0)
|
|
.Add(x => x.Min, 0));
|
|
|
|
// Assert
|
|
var spinnerButtons = cut.FindAll(".sb-number-field__spinner");
|
|
var decrementBtn = spinnerButtons[1];
|
|
Assert.NotNull(decrementBtn.GetAttribute("disabled"));
|
|
}
|
|
|
|
[Fact]
|
|
public void UsesCustomIncreaseDecreaseAriaLabels()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNumberField(p => p
|
|
.Add(x => x.IncreaseAriaLabel, "Add one")
|
|
.Add(x => x.DecreaseAriaLabel, "Subtract one"));
|
|
|
|
// Assert
|
|
var spinners = cut.FindAll(".sb-number-field__spinner");
|
|
Assert.Equal("Add one", spinners[0].GetAttribute("aria-label"));
|
|
Assert.Equal("Subtract one", spinners[1].GetAttribute("aria-label"));
|
|
}
|
|
|
|
[Fact]
|
|
public void WorksWithDecimalType()
|
|
{
|
|
// Arrange & Act
|
|
var cut = Render<SbNumberField<decimal>>(p => p
|
|
.Add(x => x.Value, 3.5m)
|
|
.Add(x => x.Step, 0.5m));
|
|
|
|
// Assert
|
|
var input = cut.Find("input");
|
|
Assert.Equal("3.5", input.GetAttribute("value"));
|
|
Assert.Equal("0.5", input.GetAttribute("step"));
|
|
}
|
|
|
|
[Fact]
|
|
public void AppliesAdditionalAttributes()
|
|
{
|
|
// Arrange & Act
|
|
var cut = RenderNumberField(p => p.Add(x => x.AdditionalAttributes, new Dictionary<string, object>
|
|
{
|
|
{ "data-testid", "number-input" },
|
|
{ "aria-label", "Quantity" }
|
|
}));
|
|
|
|
// Assert
|
|
var input = cut.Find("input");
|
|
Assert.Equal("number-input", input.GetAttribute("data-testid"));
|
|
Assert.Equal("Quantity", input.GetAttribute("aria-label"));
|
|
}
|
|
}
|