first commit
This commit is contained in:
@@ -0,0 +1,243 @@
|
||||
using System.Globalization;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Bunit;
|
||||
using Bunit.JSInterop;
|
||||
using SufiChain.SufiBlazor.Components.Forms;
|
||||
using SufiChain.SufiBlazor.Localization;
|
||||
using Xunit;
|
||||
|
||||
namespace SufiChain.SufiBlazor.Tests.Components.Forms;
|
||||
|
||||
/// <summary>
|
||||
/// Stub localizer that returns the key as the value (for testing).
|
||||
/// </summary>
|
||||
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 SbAutocompleteTests : BunitContext
|
||||
{
|
||||
public SbAutocompleteTests()
|
||||
{
|
||||
Services.AddSingleton<IStringLocalizer<SufiBlazorResource>>(new StubStringLocalizer());
|
||||
JSInterop.Mode = JSRuntimeMode.Loose;
|
||||
}
|
||||
|
||||
private static List<AutocompleteTestItem> CreateItems(int count)
|
||||
{
|
||||
return Enumerable.Range(1, count)
|
||||
.Select(i => new AutocompleteTestItem { Id = i, Name = $"Item {i}" })
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private IRenderedComponent<SbAutocomplete<AutocompleteTestItem>> RenderAutocomplete(
|
||||
Action<ComponentParameterCollectionBuilder<SbAutocomplete<AutocompleteTestItem>>>? configure = null)
|
||||
{
|
||||
var items = CreateItems(5);
|
||||
return Render<SbAutocomplete<AutocompleteTestItem>>(p =>
|
||||
{
|
||||
p.Add(x => x.Items, items)
|
||||
.Add(x => x.TextField, (Func<AutocompleteTestItem, string>)(item => item.Name))
|
||||
.Add(x => x.ValueField, (Func<AutocompleteTestItem, object>)(item => item.Id))
|
||||
.Add(x => x.DebounceMs, 0); // No debounce for faster tests
|
||||
configure?.Invoke(p);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RendersAutocompleteStructure()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cut = RenderAutocomplete();
|
||||
|
||||
// Assert
|
||||
var wrapper = cut.Find(".sb-autocomplete");
|
||||
Assert.NotNull(wrapper);
|
||||
Assert.NotNull(cut.Find(".sb-autocomplete__input-wrapper"));
|
||||
Assert.NotNull(cut.Find(".sb-autocomplete__input"));
|
||||
Assert.NotNull(cut.Find(".sb-autocomplete__icon"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RendersLabelWhenProvided()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cut = RenderAutocomplete(p => p.Add(x => x.Label, "Search"));
|
||||
|
||||
// Assert
|
||||
var label = cut.Find(".sb-autocomplete__label");
|
||||
Assert.NotNull(label);
|
||||
Assert.Contains("Search", label.TextContent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DoesNotRenderLabelWhenEmpty()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cut = RenderAutocomplete();
|
||||
|
||||
// Assert
|
||||
Assert.Empty(cut.FindAll(".sb-autocomplete__label"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RendersRequiredAsteriskWhenRequired()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cut = RenderAutocomplete(p => p
|
||||
.Add(x => x.Label, "Name")
|
||||
.Add(x => x.Required, true));
|
||||
|
||||
// Assert
|
||||
var required = cut.Find(".sb-autocomplete__required");
|
||||
Assert.NotNull(required);
|
||||
Assert.Contains("*", required.TextContent);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RendersPlaceholderWhenProvided()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cut = RenderAutocomplete(p => p.Add(x => x.Placeholder, "Type to search..."));
|
||||
|
||||
// Assert
|
||||
var input = cut.Find(".sb-autocomplete__input");
|
||||
Assert.Equal("Type to search...", input.GetAttribute("placeholder"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UsesLocalizedPlaceholderWhenPlaceholderNull()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cut = RenderAutocomplete();
|
||||
|
||||
// Assert - StubStringLocalizer returns key as value, so "Search_Placeholder"
|
||||
var input = cut.Find(".sb-autocomplete__input");
|
||||
Assert.Equal("Search_Placeholder", input.GetAttribute("placeholder"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void InputIsDisabledWhenDisabledTrue()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cut = RenderAutocomplete(p => p.Add(x => x.Disabled, true));
|
||||
|
||||
// Assert
|
||||
var input = cut.Find(".sb-autocomplete__input");
|
||||
Assert.True(input.GetAttribute("disabled") != null || input.OuterHtml.Contains("disabled"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DisplaysValueWhenValueSet()
|
||||
{
|
||||
// Arrange
|
||||
var items = CreateItems(3);
|
||||
var selected = items[1];
|
||||
|
||||
// Act
|
||||
var cut = Render<SbAutocomplete<AutocompleteTestItem>>(p => p
|
||||
.Add(x => x.Items, items)
|
||||
.Add(x => x.Value, selected)
|
||||
.Add(x => x.TextField, (Func<AutocompleteTestItem, string>)(item => item.Name))
|
||||
.Add(x => x.ValueField, (Func<AutocompleteTestItem, object>)(item => item.Id))
|
||||
.Add(x => x.DebounceMs, 0));
|
||||
|
||||
// Assert
|
||||
var input = cut.Find(".sb-autocomplete__input");
|
||||
Assert.Equal("Item 2", input.GetAttribute("value"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AppliesCustomClass()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cut = RenderAutocomplete(p => p.Add(x => x.Class, "my-autocomplete"));
|
||||
|
||||
// Assert
|
||||
var wrapper = cut.Find(".sb-autocomplete");
|
||||
Assert.Contains("my-autocomplete", wrapper.ClassList);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AppliesInlineStyle()
|
||||
{
|
||||
// Arrange & Act
|
||||
var cut = RenderAutocomplete(p => p.Add(x => x.Style, "max-width: 300px;"));
|
||||
|
||||
// Assert
|
||||
var wrapper = cut.Find(".sb-autocomplete");
|
||||
Assert.Contains("max-width: 300px", wrapper.GetAttribute("style"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InvokesValueChangedWhenItemSelected()
|
||||
{
|
||||
// Arrange
|
||||
AutocompleteTestItem? selected = null;
|
||||
var items = CreateItems(3);
|
||||
|
||||
var cut = Render<SbAutocomplete<AutocompleteTestItem>>(p => p
|
||||
.Add(x => x.Items, items)
|
||||
.Add(x => x.TextField, (Func<AutocompleteTestItem, string>)(item => item.Name))
|
||||
.Add(x => x.ValueField, (Func<AutocompleteTestItem, object>)(item => item.Id))
|
||||
.Add(x => x.DebounceMs, 0)
|
||||
.Add(x => x.ValueChanged, EventCallback.Factory.Create<AutocompleteTestItem?>(this, item => selected = item)));
|
||||
|
||||
// Act - type to open dropdown (SbAutocomplete uses @oninput, not @onchange), then select
|
||||
var input = cut.Find(".sb-autocomplete__input");
|
||||
await cut.InvokeAsync(() => input!.Input("Item"));
|
||||
cut.WaitForState(() => cut.FindAll(".sb-autocomplete__option").Count > 0);
|
||||
|
||||
var option = cut.FindAll(".sb-autocomplete__option").FirstOrDefault(o => o.TextContent.Contains("Item 1"));
|
||||
Assert.NotNull(option);
|
||||
await cut.InvokeAsync(() => option!.Click());
|
||||
|
||||
cut.WaitForState(() => selected != null);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(selected);
|
||||
Assert.Equal(1, selected!.Id);
|
||||
Assert.Equal("Item 1", selected.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ClearsValueWhenClearButtonClicked()
|
||||
{
|
||||
// Arrange
|
||||
var items = CreateItems(2);
|
||||
var selected = items[0];
|
||||
|
||||
var cut = Render<SbAutocomplete<AutocompleteTestItem>>(p => p
|
||||
.Add(x => x.Items, items)
|
||||
.Add(x => x.Value, selected)
|
||||
.Add(x => x.TextField, (Func<AutocompleteTestItem, string>)(item => item.Name))
|
||||
.Add(x => x.ValueField, (Func<AutocompleteTestItem, object>)(item => item.Id))
|
||||
.Add(x => x.Clearable, true)
|
||||
.Add(x => x.DebounceMs, 0));
|
||||
|
||||
cut.WaitForState(() => cut.Find(".sb-autocomplete__input")?.GetAttribute("value") == "Item 1");
|
||||
|
||||
// Act
|
||||
var clearBtn = cut.Find(".sb-autocomplete__clear");
|
||||
Assert.NotNull(clearBtn);
|
||||
await cut.InvokeAsync(() => clearBtn!.Click());
|
||||
|
||||
cut.WaitForState(() => cut.Find(".sb-autocomplete__input")?.GetAttribute("value") == "");
|
||||
|
||||
// Assert
|
||||
var input = cut.Find(".sb-autocomplete__input");
|
||||
Assert.Equal("", input.GetAttribute("value"));
|
||||
}
|
||||
|
||||
private class AutocompleteTestItem
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Name { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user