Files
radzen-blazor/Radzen.Blazor.Tests/AutoCompleteTests.cs
Guilherme Moitinho ced6176dc3 feat(AutoComplete): add EmptyTemplate, LoadingTemplate and IsLoading parameters (#2534)
* feat(AutoComplete): add EmptyTemplate, LoadingTemplate and IsLoading parameters

Adds three new parameters to RadzenAutoComplete to customize the popup
when there is no data to display or while data is being loaded, mirroring
the API already exposed by RadzenDataGrid.

- EmptyTemplate renders inside the popup when there are no suggestions.
- LoadingTemplate renders while IsLoading is true; takes precedence over items
  and EmptyTemplate.
- IsLoading is a user-controlled flag toggled around the LoadData callback.

When none of the new parameters are set, the rendered markup is unchanged.

Closes #2038

* docs(AutoComplete): add demo for EmptyTemplate and LoadingTemplate

* docs(AutoComplete): align demo input width with sibling examples (13rem)
2026-04-27 16:35:55 +03:00

285 lines
13 KiB
C#

using System.Collections;
using Bunit;
using Xunit;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Radzen.Blazor.Tests
{
public class AutoCompleteTests
{
[Fact]
public void AutoComplete_Renders_WithClassName()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenAutoComplete>();
Assert.Contains(@"rz-autocomplete", component.Markup);
}
[Fact]
public void AutoComplete_Renders_InputElement()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenAutoComplete>();
Assert.Contains("type=\"text\"", component.Markup);
Assert.Contains("rz-inputtext", component.Markup);
}
[Fact]
public void AutoComplete_Renders_Disabled()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenAutoComplete>(parameters =>
{
parameters.Add(p => p.Disabled, true);
});
Assert.Contains("disabled", component.Markup);
Assert.Contains("rz-state-disabled", component.Markup);
}
[Fact]
public void AutoComplete_Renders_Placeholder()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var component = ctx.RenderComponent<RadzenAutoComplete>(parameters =>
{
parameters.Add(p => p.Placeholder, "Type to search...");
});
Assert.Contains("placeholder=\"Type to search...\"", component.Markup);
}
[Fact]
public void AutoComplete_Renders_WithData()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var data = new List<string> { "Apple", "Banana", "Cherry" };
var component = ctx.RenderComponent<RadzenAutoComplete>(parameters =>
{
parameters.Add(p => p.Data, data);
});
Assert.Contains("rz-autocomplete-panel", component.Markup);
}
[Fact]
public void AutoComplete_Enum_Converts_To_Attr_Value()
{
// Options
Assert.Equal("off", AutoCompleteType.Off.GetAutoCompleteValue());
Assert.Equal("on", AutoCompleteType.On.GetAutoCompleteValue());
Assert.Equal("name", AutoCompleteType.Name.GetAutoCompleteValue());
Assert.Equal("honorific-prefix", AutoCompleteType.HonorificPrefix.GetAutoCompleteValue());
Assert.Equal("given-name", AutoCompleteType.GivenName.GetAutoCompleteValue());
Assert.Equal("additional-name", AutoCompleteType.AdditionalName.GetAutoCompleteValue());
Assert.Equal("family-name", AutoCompleteType.FamilyName.GetAutoCompleteValue());
Assert.Equal("honorific-suffix", AutoCompleteType.HonorificSuffix.GetAutoCompleteValue());
Assert.Equal("nickname", AutoCompleteType.Nickname.GetAutoCompleteValue());
Assert.Equal("email", AutoCompleteType.Email.GetAutoCompleteValue());
Assert.Equal("username", AutoCompleteType.Username.GetAutoCompleteValue());
Assert.Equal("new-password", AutoCompleteType.NewPassword.GetAutoCompleteValue());
Assert.Equal("current-password", AutoCompleteType.CurrentPassword.GetAutoCompleteValue());
Assert.Equal("one-time-code", AutoCompleteType.OneTimeCode.GetAutoCompleteValue());
Assert.Equal("organization-title", AutoCompleteType.OrganizationTitle.GetAutoCompleteValue());
Assert.Equal("organization", AutoCompleteType.Organization.GetAutoCompleteValue());
Assert.Equal("street-address", AutoCompleteType.StreetAddress.GetAutoCompleteValue());
Assert.Equal("address-line1", AutoCompleteType.AddressLine1.GetAutoCompleteValue());
Assert.Equal("address-line2", AutoCompleteType.AddressLine2.GetAutoCompleteValue());
Assert.Equal("address-line3", AutoCompleteType.AddressLine3.GetAutoCompleteValue());
Assert.Equal("address-level1", AutoCompleteType.AddressLevel1.GetAutoCompleteValue());
Assert.Equal("address-level2", AutoCompleteType.AddressLevel2.GetAutoCompleteValue());
Assert.Equal("address-level3", AutoCompleteType.AddressLevel3.GetAutoCompleteValue());
Assert.Equal("address-level4", AutoCompleteType.AddressLevel4.GetAutoCompleteValue());
Assert.Equal("country", AutoCompleteType.Country.GetAutoCompleteValue());
Assert.Equal("country-name", AutoCompleteType.CountryName.GetAutoCompleteValue());
Assert.Equal("postal-code", AutoCompleteType.PostalCode.GetAutoCompleteValue());
Assert.Equal("cc-name", AutoCompleteType.CcName.GetAutoCompleteValue());
Assert.Equal("cc-given-name", AutoCompleteType.CcGivenName.GetAutoCompleteValue());
Assert.Equal("cc-additional-name", AutoCompleteType.CcAdditionalName.GetAutoCompleteValue());
Assert.Equal("cc-family-name", AutoCompleteType.CcFamilyName.GetAutoCompleteValue());
Assert.Equal("cc-number", AutoCompleteType.CcNumber.GetAutoCompleteValue());
Assert.Equal("cc-exp", AutoCompleteType.CcExp.GetAutoCompleteValue());
Assert.Equal("cc-exp-month", AutoCompleteType.CcExpMonth.GetAutoCompleteValue());
Assert.Equal("cc-exp-year", AutoCompleteType.CcExpYear.GetAutoCompleteValue());
Assert.Equal("cc-csc", AutoCompleteType.CcCsc.GetAutoCompleteValue());
Assert.Equal("cc-type", AutoCompleteType.CcType.GetAutoCompleteValue());
Assert.Equal("transaction-currency", AutoCompleteType.TransactionCurrency.GetAutoCompleteValue());
Assert.Equal("transaction-amount", AutoCompleteType.TransactionAmount.GetAutoCompleteValue());
Assert.Equal("language", AutoCompleteType.Language.GetAutoCompleteValue());
Assert.Equal("bday", AutoCompleteType.Bday.GetAutoCompleteValue());
Assert.Equal("bday-day", AutoCompleteType.BdayDay.GetAutoCompleteValue());
Assert.Equal("bday-month", AutoCompleteType.BdayMonth.GetAutoCompleteValue());
Assert.Equal("bday-year", AutoCompleteType.BdayYear.GetAutoCompleteValue());
Assert.Equal("sex", AutoCompleteType.Sex.GetAutoCompleteValue());
Assert.Equal("tel", AutoCompleteType.Tel.GetAutoCompleteValue());
Assert.Equal("tel-country-code", AutoCompleteType.TelCountryCode.GetAutoCompleteValue());
Assert.Equal("tel-national", AutoCompleteType.TelNational.GetAutoCompleteValue());
Assert.Equal("tel-area-code", AutoCompleteType.TelAreaCode.GetAutoCompleteValue());
Assert.Equal("tel-local", AutoCompleteType.TelLocal.GetAutoCompleteValue());
Assert.Equal("tel-extension", AutoCompleteType.TelExtension.GetAutoCompleteValue());
Assert.Equal("impp", AutoCompleteType.Impp.GetAutoCompleteValue());
Assert.Equal("url", AutoCompleteType.Url.GetAutoCompleteValue());
Assert.Equal("photo", AutoCompleteType.Photo.GetAutoCompleteValue());
// Synonyms
Assert.Equal("address-level1", AutoCompleteType.State.GetAutoCompleteValue());
Assert.Equal("address-level1", AutoCompleteType.Province.GetAutoCompleteValue());
Assert.Equal("postal-code", AutoCompleteType.ZipCode.GetAutoCompleteValue());
Assert.Equal("given-name", AutoCompleteType.FirstName.GetAutoCompleteValue());
Assert.Equal("additional-name", AutoCompleteType.MiddleName.GetAutoCompleteValue());
Assert.Equal("family-name", AutoCompleteType.LastName.GetAutoCompleteValue());
}
[Fact]
public void AutoComplete_Renders_EmptyTemplate_WhenNoData()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var data = new List<string>();
var component = ctx.RenderComponent<RadzenAutoComplete>(parameters =>
{
parameters
.Add(p => p.Data, data)
.Add(p => p.OpenOnFocus, true)
.Add(p => p.EmptyTemplate, b => b.AddMarkupContent(0, "<span class=\"empty-marker\">No results</span>"));
});
Assert.Contains("empty-marker", component.Markup);
Assert.Contains("No results", component.Markup);
}
[Fact]
public void AutoComplete_DoesNotRender_EmptyTemplate_WhenItemsPresent()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var data = new List<string> { "Apple" };
var component = ctx.RenderComponent<RadzenAutoComplete>(parameters =>
{
parameters
.Add(p => p.Data, data)
.Add(p => p.OpenOnFocus, true)
.Add(p => p.EmptyTemplate, b => b.AddMarkupContent(0, "<span class=\"empty-marker\">No results</span>"));
});
Assert.DoesNotContain("empty-marker", component.Markup);
Assert.Contains("Apple", component.Markup);
}
[Fact]
public void AutoComplete_Renders_LoadingTemplate_WhenIsLoading()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var data = new List<string> { "Apple", "Banana" };
var component = ctx.RenderComponent<RadzenAutoComplete>(parameters =>
{
parameters
.Add(p => p.Data, data)
.Add(p => p.OpenOnFocus, true)
.Add(p => p.IsLoading, true)
.Add(p => p.LoadingTemplate, b => b.AddMarkupContent(0, "<span class=\"loading-marker\">Loading...</span>"));
});
Assert.Contains("loading-marker", component.Markup);
Assert.DoesNotContain("Apple", component.Markup);
Assert.DoesNotContain("Banana", component.Markup);
}
[Fact]
public void AutoComplete_DoesNotRender_EmptyMarker_WhenEmptyTemplateNotSet()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var data = new List<string>();
var component = ctx.RenderComponent<RadzenAutoComplete>(parameters =>
{
parameters
.Add(p => p.Data, data)
.Add(p => p.OpenOnFocus, true);
});
Assert.DoesNotContain("rz-state-disabled", component.Markup);
Assert.DoesNotContain("role=\"presentation\"", component.Markup);
}
[Fact]
public void AutoComplete_DoesNotRender_LoadingMarker_WhenLoadingTemplateNotSet()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var data = new List<string> { "Apple" };
var component = ctx.RenderComponent<RadzenAutoComplete>(parameters =>
{
parameters
.Add(p => p.Data, data)
.Add(p => p.OpenOnFocus, true)
.Add(p => p.IsLoading, true);
});
Assert.DoesNotContain("role=\"presentation\"", component.Markup);
Assert.Contains("Apple", component.Markup);
}
[Fact]
public void AutoComplete_LoadingTemplate_HasPrecedence_OverEmptyTemplate()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var data = new List<string>();
var component = ctx.RenderComponent<RadzenAutoComplete>(parameters =>
{
parameters
.Add(p => p.Data, data)
.Add(p => p.OpenOnFocus, true)
.Add(p => p.IsLoading, true)
.Add(p => p.LoadingTemplate, b => b.AddMarkupContent(0, "<span class=\"loading-marker\">Loading...</span>"))
.Add(p => p.EmptyTemplate, b => b.AddMarkupContent(0, "<span class=\"empty-marker\">No results</span>"));
});
Assert.Contains("loading-marker", component.Markup);
Assert.DoesNotContain("empty-marker", component.Markup);
}
[Fact]
public void AutoComplete_Filters_StringList()
{
using var ctx = new TestContext();
ctx.JSInterop.Mode = JSRuntimeMode.Loose;
var data = new List<string> { "Apple", "Banana", "Cherry" };
var component = ctx.RenderComponent<AutoCompleteWithAccessibleView>(parameters =>
{
parameters
.Add(p => p.Data, data)
.Add(p => p.SearchText, "Ban")
.Add(p => p.OpenOnFocus, true);
});
Assert.Contains("Banana", component.Instance.CurrentView.OfType<string>());
Assert.DoesNotContain("Apple", component.Instance.CurrentView.OfType<string>());
Assert.DoesNotContain("Cherry", component.Instance.CurrentView.OfType<string>());
}
private sealed class AutoCompleteWithAccessibleView : RadzenAutoComplete
{
public IEnumerable CurrentView => View;
}
}
}